From b501bb58b8f2bc43a7b3fd1905e751de3cfee6e3 Mon Sep 17 00:00:00 2001 From: stefanorosanelli Date: Tue, 19 Mar 2024 19:50:48 +0100 Subject: [PATCH] feat: handle Apple auth --- src/Authenticator/OAuth2Authenticator.php | 28 +++++++++++++++++++++-- src/Identifier/OAuth2Identifier.php | 3 +++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Authenticator/OAuth2Authenticator.php b/src/Authenticator/OAuth2Authenticator.php index 62b9c84..918f6c6 100644 --- a/src/Authenticator/OAuth2Authenticator.php +++ b/src/Authenticator/OAuth2Authenticator.php @@ -22,6 +22,7 @@ use Cake\Log\LogTrait; use Cake\Routing\Router; use Cake\Utility\Hash; +use Firebase\JWT\JWT; use Psr\Http\Message\ServerRequestInterface; /** @@ -85,6 +86,12 @@ public function authenticate(ServerRequestInterface $request): ResultInterface { // extract provider from request $provider = basename($request->getUri()->getPath()); + $this->log('[OAuth2Authenticator] provider: ' . $provider, 'info'); + // leeway is needed for clock skew + $leeway = (int)$this->getConfig(sprintf('providers.%s.clientOptions.jwtLeeway', $provider), 0); + if ($leeway) { + JWT::$leeway = $leeway; + } $connect = $this->providerConnect($provider, $request); if (!empty($connect[static::AUTH_URL_KEY])) { @@ -97,7 +104,9 @@ public function authenticate(ServerRequestInterface $request): ResultInterface 'provider_username' => Hash::get($connect, sprintf('user.%s', $usernameField)), 'access_token' => Hash::get($connect, 'token.access_token'), 'provider_userdata' => (array)Hash::get($connect, 'user'), + 'id_token' => Hash::get($connect, 'token.id_token'), ]; + $this->log('[OAuth2Authenticator] identify user with: ' . json_encode($data), 'info'); $user = $this->_identifier->identify($data); if (empty($user)) { @@ -119,7 +128,12 @@ protected function providerConnect(string $provider, ServerRequestInterface $req { $this->initProvider($provider, $request); - $query = $request->getQueryParams(); + if ($request->getMethod() === 'GET') { + $query = $request->getQueryParams(); + } else { + $query = $request->getParsedBody(); + } + $this->log('[OAuth2Authenticator] Provider connect query: ' . json_encode($query), 'info'); $sessionKey = $this->getConfig('sessionKey'); /** @var \Cake\Http\Session $session */ $session = $request->getAttribute('session'); @@ -127,14 +141,22 @@ protected function providerConnect(string $provider, ServerRequestInterface $req if (!isset($query['code'])) { // If we don't have an authorization code then get one $options = (array)$this->getConfig(sprintf('providers.%s.options', $provider)); + $this->log('[OAuth2Authenticator] Provider options: ' . json_encode($options), 'info'); $authUrl = $this->provider->getAuthorizationUrl($options); + $this->log('[OAuth2Authenticator] State: ' . $this->provider->getState(), 'info'); + $this->log('[OAuth2Authenticator] Session id: ' . $session->id(), 'info'); $session->write($sessionKey, $this->provider->getState()); + $this->log('[OAuth2Authenticator] Authorization URL: ' . $authUrl, 'info'); return [static::AUTH_URL_KEY => $authUrl]; } // Check given state against previously stored one to mitigate CSRF attack - if (empty($query['state']) || ($query['state'] !== $session->read($sessionKey))) { + $this->log('[OAuth2Authenticator] Session id: ' . $session->id(), 'info'); + if ( + (empty($query['state']) || $query['state'] !== $session->read($sessionKey)) + && $request->getMethod() === 'GET' + ) { $session->delete($sessionKey); throw new BadRequestException('Invalid state'); } @@ -142,8 +164,10 @@ protected function providerConnect(string $provider, ServerRequestInterface $req // Try to get an access token (using the authorization code grant) /** @var \League\OAuth2\Client\Token\AccessToken $token */ $token = $this->provider->getAccessToken('authorization_code', ['code' => $query['code']]); + $this->log('[OAuth2Authenticator] Access token via auth code: ' . json_encode($token->jsonSerialize()), 'info'); // We got an access token, let's now get the user's details $user = $this->provider->getResourceOwner($token)->toArray(); + $this->log('[OAuth2Authenticator] User: ' . json_encode($user), 'info'); $token = $token->jsonSerialize(); return compact('token', 'user'); diff --git a/src/Identifier/OAuth2Identifier.php b/src/Identifier/OAuth2Identifier.php index 6164bb0..ce02754 100644 --- a/src/Identifier/OAuth2Identifier.php +++ b/src/Identifier/OAuth2Identifier.php @@ -77,6 +77,7 @@ public function identify(array $credentials) */ protected function externalAuth(array $credentials): array { + $this->log('[OAuth2Identifier] Signing in with credentials: ' . json_encode($credentials), 'info'); $apiClient = ApiClientProvider::getApiClient(); $result = $apiClient->post('/auth', json_encode($credentials), ['Content-Type' => 'application/json']); $tokens = $result['meta']; @@ -95,10 +96,12 @@ protected function externalAuth(array $credentials): array */ protected function signup(array $credentials): ?array { + $this->log('[OAuth2Identifier] Signin up with credentials: ' . json_encode($credentials), 'info'); $data = $this->signupData($credentials); try { $apiClient = ApiClientProvider::getApiClient(); $apiClient->setupTokens([]); + $this->log('[OAuth2Identifier] BEdita Signup data: ' . json_encode($data), 'info'); $apiClient->post('/signup', json_encode($data), ['Content-Type' => 'application/json']); // login after signup $user = $this->externalAuth($credentials);