Redirect to intercepted request resulting in "wrong" URL

Facing an interesting issue here. In a Neos site (v7.3) I am checking permission to see a node using an around aspect on Frontend/NodeController->showAction(). If the permission check fails, that aspect throws an AuthenticationRequiredException.

That is caught in Dispatcher->disptach() and there the $request is attached to the exception using $exception->attachInterceptedRequest($request). From there on, all that happens is “default behaviour” of Flow and Neos…

SecurityEntryPointMiddleware->process() calls $this->securityContext->setInterceptedRequest($authenticationException->getInterceptedRequest()) and the calls $entryPoint->startAuthentication($request, $response). The entrypoint is custom, but does not influence the stored intercepted request (it is doing what the WedRedirect does, just determining the route values differently.)

I end up at the login screen (a Neos document having a login form plugin) and after submitting that, I get rediretced to the document I tried to open originally. It shows as expected, but the URL is “wrong”.

Instead of

https://team.localbeach.net/de/news/news/foo.html

I end up at

https://team.localbeach.net/de/login.html?--acme_frontenduser-loginform
%5B%40package%5D=neos.neos&--acme_frontenduser-loginform
%5B%40controller%5D=frontend%5Cnode&--acme_frontenduser-loginform
%5B%40action%5D=show&--acme_frontenduser-loginform%5B%40format%5D=html&
--acme_frontenduser-loginform%5Bnode%5D=%2Fsites%2Fteam-portal%2Fnode-
9chjw98piv4jq%2Fnode-advfp3jseovt7%2Fnode-lj12hkrg12g1t%40live%3Blanguage%3Dde

The values are correct, just the argument namespace is wrong, and thus the “wrong” URL is generated by the routing.

Digging deeper I found that the namespace is added in UriBuilder->addNamespaceToArguments() which is called using $this->request in UriBuilder->uriFor().

Now, $this->request is the request from submitting the login form (set in AbstractController->initializeController()), thus it has an argument namespace, that “wins” over the intercepted request.

Ok, next try is to use $this->uriBuilder->setRequest($originalRequest) in my AuthenticationController->onAuthenticationSuccess() method before handing over to $this->redirectToRequest($originalRequest). Which leads to a new exception:

Exception in line 367 of /…/Neos_Flow_Mvc_Routing_UriBuilder.php: Return value of Neos\Flow\Mvc\ActionRequest_Original::getHttpRequest() must implement interface Psr\Http\Message\ServerRequestInterface, null returned - See also: 20230814134033198342.txt

Indeed, the stored intercepted request has no HTTP request attached (removed upon serialization using __sleep()), but the method must return one.


I then tried using build() instead of uriFor(), but the problem resurfaces in a different way, since that calls mergeArgumentsWithRequestArguments(), which in turn calls addNamespaceToArguments()


Now, did anyone ever have this issue? If yes, (how) was it solved?

I ended up with this code now… :sob:

if ($originalRequest !== null) {
    $httpRequest = new ServerRequest('GET', 'https://localhost');
    $httpRequest = $httpRequest->withAttribute(
        ServerRequestAttributes::ROUTING_PARAMETERS,
        RouteParameters::createEmpty()->withParameter('requestUriHost', $httpRequest->getUri()->getHost())
    );
    $uriBuilder = new UriBuilder();
    $uriBuilder->setRequest(ActionRequest::fromHttpRequest($httpRequest));

    $uri = $uriBuilder
        ->setCreateAbsoluteUri(true)
        ->uriFor(
            $originalRequest->getControllerActionName(),
            $originalRequest->getArguments(),
            $originalRequest->getControllerName(),
            $originalRequest->getControllerPackageKey()
        );
}

Why, oh, why… it should be as easy as:

$this->redirectToRequest($originalRequest);

Ok, I dug a bit further, together with @christianm. The result is

that can make this easier for the developer.

Going further we could instead store just the intercepted URI or the HTTP request, as mentioned in the issue.

1 Like