patrickbussmann /
oauth2-apple
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace League\OAuth2\Client\Provider; |
||
| 4 | |||
| 5 | use Exception; |
||
| 6 | use InvalidArgumentException; |
||
| 7 | use Lcobucci\JWT\Configuration; |
||
| 8 | use Lcobucci\JWT\Signer\Key\LocalFileReference; |
||
| 9 | use Lcobucci\JWT\Signer; |
||
| 10 | use Lcobucci\JWT\Signer\Key; |
||
| 11 | use League\OAuth2\Client\Grant\AbstractGrant; |
||
| 12 | use League\OAuth2\Client\Provider\Exception\AppleAccessDeniedException; |
||
| 13 | use League\OAuth2\Client\Token\AccessToken; |
||
| 14 | use League\OAuth2\Client\Token\AccessTokenInterface; |
||
| 15 | use League\OAuth2\Client\Token\AppleAccessToken; |
||
| 16 | use League\OAuth2\Client\Tool\BearerAuthorizationTrait; |
||
| 17 | use Psr\Http\Message\ResponseInterface; |
||
| 18 | |||
| 19 | class Apple extends AbstractProvider |
||
| 20 | { |
||
| 21 | use BearerAuthorizationTrait; |
||
| 22 | |||
| 23 | /** |
||
| 24 | * Default scopes |
||
| 25 | * |
||
| 26 | * @var array |
||
| 27 | */ |
||
| 28 | public $defaultScopes = ['name', 'email']; |
||
| 29 | |||
| 30 | /** |
||
| 31 | * @var string the team id |
||
| 32 | */ |
||
| 33 | protected $teamId; |
||
| 34 | |||
| 35 | /** |
||
| 36 | * @var string the key file id |
||
| 37 | */ |
||
| 38 | protected $keyFileId; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * @var string the key file path |
||
| 42 | */ |
||
| 43 | protected $keyFilePath; |
||
| 44 | |||
| 45 | /** |
||
| 46 | * Constructs Apple's OAuth 2.0 service provider. |
||
| 47 | * |
||
| 48 | * @param array $options |
||
| 49 | * @param array $collaborators |
||
| 50 | */ |
||
| 51 | public function __construct(array $options = [], array $collaborators = []) |
||
| 52 | 13 | { |
|
| 53 | if (empty($options['teamId'])) { |
||
| 54 | 13 | throw new InvalidArgumentException('Required option not passed: "teamId"'); |
|
| 55 | 1 | } |
|
| 56 | |||
| 57 | if (empty($options['keyFileId'])) { |
||
| 58 | 13 | throw new InvalidArgumentException('Required option not passed: "keyFileId"'); |
|
| 59 | 1 | } |
|
| 60 | |||
| 61 | if (empty($options['keyFilePath'])) { |
||
| 62 | 13 | throw new InvalidArgumentException('Required option not passed: "keyFilePath"'); |
|
| 63 | 1 | } |
|
| 64 | |||
| 65 | parent::__construct($options, $collaborators); |
||
| 66 | 13 | } |
|
| 67 | 13 | ||
| 68 | /** |
||
| 69 | * Creates an access token from a response. |
||
| 70 | * |
||
| 71 | * The grant that was used to fetch the response can be used to provide |
||
| 72 | * additional context. |
||
| 73 | * |
||
| 74 | * @param array $response |
||
| 75 | * @param AbstractGrant $grant |
||
| 76 | * @return AccessTokenInterface |
||
| 77 | */ |
||
| 78 | protected function createAccessToken(array $response, AbstractGrant $grant) |
||
| 79 | { |
||
| 80 | return new AppleAccessToken($this->getHttpClient(), $response); |
||
| 81 | } |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Get the string used to separate scopes. |
||
| 85 | * |
||
| 86 | * @return string |
||
| 87 | */ |
||
| 88 | protected function getScopeSeparator() |
||
| 89 | 3 | { |
|
| 90 | return ' '; |
||
| 91 | 3 | } |
|
| 92 | |||
| 93 | /** |
||
| 94 | * Change response mode when scope requires it |
||
| 95 | * |
||
| 96 | * @param array $options |
||
| 97 | * |
||
| 98 | * @return array |
||
| 99 | */ |
||
| 100 | protected function getAuthorizationParameters(array $options) |
||
| 101 | 3 | { |
|
| 102 | $options = parent::getAuthorizationParameters($options); |
||
| 103 | 3 | if (strpos($options['scope'], 'name') !== false || strpos($options['scope'], 'email') !== false) { |
|
| 104 | 3 | $options['response_mode'] = 'form_post'; |
|
| 105 | 2 | } |
|
| 106 | return $options; |
||
| 107 | 3 | } |
|
| 108 | |||
| 109 | /** |
||
| 110 | * @param AccessToken $token |
||
| 111 | * |
||
| 112 | * @return mixed |
||
| 113 | */ |
||
| 114 | protected function fetchResourceOwnerDetails(AccessToken $token) |
||
| 115 | 2 | { |
|
| 116 | return json_decode(array_key_exists('user', $_GET) ? $_GET['user'] |
||
| 117 | 2 | : (array_key_exists('user', $_POST) ? $_POST['user'] : '[]'), true) ?: []; |
|
| 118 | 2 | } |
|
| 119 | |||
| 120 | /** |
||
| 121 | * Get authorization url to begin OAuth flow |
||
| 122 | * |
||
| 123 | * @return string |
||
| 124 | */ |
||
| 125 | public function getBaseAuthorizationUrl() |
||
| 126 | 3 | { |
|
| 127 | return 'https://appleid.apple.com/auth/authorize'; |
||
| 128 | 3 | } |
|
| 129 | |||
| 130 | /** |
||
| 131 | * Get access token url to retrieve token |
||
| 132 | * |
||
| 133 | * @return string |
||
| 134 | */ |
||
| 135 | public function getBaseAccessTokenUrl(array $params) |
||
| 136 | 1 | { |
|
| 137 | return 'https://appleid.apple.com/auth/token'; |
||
| 138 | 1 | } |
|
| 139 | |||
| 140 | /** |
||
| 141 | * Get provider url to fetch user details |
||
| 142 | * |
||
| 143 | * @param AccessToken $token |
||
| 144 | * |
||
| 145 | * @return string |
||
| 146 | * @throws Exception |
||
| 147 | */ |
||
| 148 | public function getResourceOwnerDetailsUrl(AccessToken $token) |
||
| 149 | 1 | { |
|
| 150 | throw new Exception('No Apple ID REST API available yet!'); |
||
| 151 | 1 | } |
|
| 152 | |||
| 153 | /** |
||
| 154 | * Get the default scopes used by this provider. |
||
| 155 | * |
||
| 156 | * This should not be a complete list of all scopes, but the minimum |
||
| 157 | * required for the provider user interface! |
||
| 158 | * |
||
| 159 | * @return array |
||
| 160 | */ |
||
| 161 | protected function getDefaultScopes() |
||
| 162 | 2 | { |
|
| 163 | return $this->defaultScopes; |
||
| 164 | 2 | } |
|
| 165 | |||
| 166 | /** |
||
| 167 | * Check a provider response for errors. |
||
| 168 | * |
||
| 169 | * @param ResponseInterface $response |
||
| 170 | * @param array $data Parsed response data |
||
| 171 | * @return void |
||
| 172 | * @throws AppleAccessDeniedException |
||
| 173 | */ |
||
| 174 | protected function checkResponse(ResponseInterface $response, $data) |
||
| 175 | 1 | { |
|
| 176 | if ($response->getStatusCode() >= 400) { |
||
| 177 | 1 | throw new AppleAccessDeniedException( |
|
| 178 | 1 | array_key_exists('error', $data) ? $data['error'] : $response->getReasonPhrase(), |
|
| 179 | 1 | array_key_exists('code', $data) ? $data['code'] : $response->getStatusCode(), |
|
| 180 | 1 | $response |
|
|
0 ignored issues
–
show
|
|||
| 181 | 1 | ); |
|
| 182 | } |
||
| 183 | } |
||
| 184 | |||
| 185 | /** |
||
| 186 | * Generate a user object from a successful user details request. |
||
| 187 | * |
||
| 188 | * @param array $response |
||
| 189 | * @param AccessToken $token |
||
| 190 | * @return AppleResourceOwner |
||
| 191 | */ |
||
| 192 | protected function createResourceOwner(array $response, AccessToken $token) |
||
| 193 | 1 | { |
|
| 194 | return new AppleResourceOwner( |
||
| 195 | 1 | array_merge( |
|
| 196 | 1 | $response, |
|
| 197 | 1 | [ |
|
| 198 | 'email' => isset($token->getValues()['email']) |
||
| 199 | 1 | ? $token->getValues()['email'] : (isset($response['email']) ? $response['email'] : null), |
|
| 200 | 1 | 'isPrivateEmail' => $token instanceof AppleAccessToken ? $token->isPrivateEmail() : null |
|
| 201 | 1 | ] |
|
| 202 | ), |
||
| 203 | $token->getResourceOwnerId() |
||
| 204 | 1 | ); |
|
| 205 | } |
||
| 206 | |||
| 207 | /** |
||
| 208 | * {@inheritDoc} |
||
| 209 | */ |
||
| 210 | public function getAccessToken($grant, array $options = []) |
||
| 211 | { |
||
| 212 | $configuration = $this->getConfiguration(); |
||
| 213 | $time = new \DateTimeImmutable(); |
||
| 214 | $time = $time->setTime($time->format('H'), $time->format('i'), $time->format('s')); |
||
| 215 | $expiresAt = $time->modify('+1 Hour'); |
||
| 216 | $expiresAt = $expiresAt->setTime($expiresAt->format('H'), $expiresAt->format('i'), $expiresAt->format('s')); |
||
| 217 | |||
| 218 | $token = $configuration->builder() |
||
| 219 | ->issuedBy($this->teamId) |
||
| 220 | ->permittedFor('https://appleid.apple.com') |
||
| 221 | ->issuedAt($time) |
||
| 222 | ->expiresAt($expiresAt) |
||
| 223 | ->relatedTo($this->clientId) |
||
| 224 | ->withHeader('alg', 'ES256') |
||
| 225 | ->withHeader('kid', $this->keyFileId) |
||
| 226 | ->getToken($configuration->signer(), $configuration->signingKey()); |
||
| 227 | |||
| 228 | $options += [ |
||
| 229 | 'client_secret' => $token->toString() |
||
| 230 | ]; |
||
| 231 | |||
| 232 | return parent::getAccessToken($grant, $options); |
||
| 233 | } |
||
| 234 | |||
| 235 | /** |
||
| 236 | * @return Configuration |
||
| 237 | */ |
||
| 238 | public function getConfiguration() |
||
| 239 | { |
||
| 240 | return Configuration::forSymmetricSigner( |
||
| 241 | Signer\Ecdsa\Sha256::create(), |
||
| 242 | $this->getLocalKey() |
||
| 243 | ); |
||
| 244 | } |
||
| 245 | |||
| 246 | /** |
||
| 247 | * @return Key |
||
| 248 | */ |
||
| 249 | public function getLocalKey() |
||
| 250 | { |
||
| 251 | return LocalFileReference::file($this->keyFilePath); |
||
| 252 | } |
||
| 253 | } |
||
| 254 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: