Skip to content

Commit

Permalink
feat: handle Apple auth
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanorosanelli committed Mar 19, 2024
1 parent c812e52 commit b501bb5
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
28 changes: 26 additions & 2 deletions src/Authenticator/OAuth2Authenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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;

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (8.1)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (8.1)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (8.2)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (8.2)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (7.4)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (7.4)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (7.4)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (7.4)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (8.1)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (8.1)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (8.2)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.

Check failure on line 93 in src/Authenticator/OAuth2Authenticator.php

View workflow job for this annotation

GitHub Actions / stan / Static code analyzer (8.2)

Access to static property $leeway on an unknown class Firebase\JWT\JWT.
}

$connect = $this->providerConnect($provider, $request);
if (!empty($connect[static::AUTH_URL_KEY])) {
Expand All @@ -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)) {
Expand All @@ -119,31 +128,46 @@ 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');

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');
}

// 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');
Expand Down
3 changes: 3 additions & 0 deletions src/Identifier/OAuth2Identifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'];
Expand All @@ -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);
Expand Down

0 comments on commit b501bb5

Please sign in to comment.