How to redirect from an authenticator to an external authentication endpoint?

跟風遠走 提交于 2020-06-23 08:58:45

问题


I'm writing a web app which I want to have flexible authentication options due to different customers' needs. I'm using the official cakephp/authentication library, but it doesn't have an OpenID Connect Authenticator, so I'm rolling my own.

The problem I'm having is that I can't return a modified Cake\Http\Response object with a redirect header from my Authenticator. AuthenticatorInterface requires the authenticate() method to return a Result object. I'm hoping to not have to modify more than the Authenticator class, because it kind of defeats the purpose of using the library if I'm just going to rewrite it's flow.

class OidcAuthenticator extends AbstractAuthenticator
{
public function authenticate(ServerRequestInterface $request, ResponseInterface $response)
{
    // non-pertinent code removed for brevity
    return $this->_requestAuthorization($request, $response);
}


private function _requestAuthorization(ServerRequestInterface $request, ResponseInterface $response)
{
    $auth_endpoint = $this->getConfig('authorization_endpoint');
    $response_type = 'code';
    $state = $this->_setState($request, Security::randomString());

    $auth_params = [
        'response_type' => $response_type,
        'redirect_uri' => 'http://localhost:8080/',
        'client_id' => $this->getConfig('client_id'),
        'nonce' => $nonce,
        'state' => $state,
        'scope' => 'openid'
    ];

    $auth_endpoint .= (strpos($auth_endpoint, '?') === false ? '?' : '&') .
        http_build_query($auth_params, null, '&');

    /* What I want to return */
    $response = $response->withHeader('Location', $auth_endpoint);

    /* What I have to return */
    return new Result(null, Result::FAILURE_MISSING_CREDENTIALS);
}
}

I can make this work with

$request->getAttribute('session')->close();
header('Location: ' . $auth_endpoint, true, 302);
exit();

but that seems to violate CakePHP conventions. Ideally, I could embed the new response object into the Result and the Authentication middleware would catch it and emit it instead of the UnauthenticatedException. This is kind of a best-practices question, but hopefully it's specific enough for SO.

TL;DR: How to redirect when you can't return a response object to the middleware queue?


回答1:


AFAICT there isn't really a recommended practice for now, it might be worth opening an issue over at GitHub for clarification.

You could make use of AuthenticationRequiredException (or UnauthorizedException in earlier versions), it's kinda tangled with stateless authentication, but there's nothing that would stop you from using it. Unlike stateless authenticators you'd have to throw it in the authenticate() method call flow, something like this:

private function _requestAuthorization(
    ServerRequestInterface $request,
    ResponseInterface $response
) {
    // ...

    $headers = [
        'Location' => $auth_endpoint
    ];
    $body = null;
    $statusCode = 302;

    // in CakePHP 4.x / Authentication 2.x
    throw new \Authentication\Authenticator\AuthenticationRequiredException (
        $headers,
        $body,
        $statusCode
    );

    // in CakePHP 3.x / Authentication 1.x
    throw new \Authentication\Authenticator\UnauthorizedException(
        $headers,
        $body,
        $statusCode
    );
}

This will then be handled in AuthenticationMiddleware::__invoke() accordingly, where the response will be modified and returned.



来源:https://stackoverflow.com/questions/54067100/how-to-redirect-from-an-authenticator-to-an-external-authentication-endpoint

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!