Apple::createResourceOwner()   A
last analyzed

Complexity

Conditions 4
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 8
cts 8
cp 1
rs 9.7998
c 0
b 0
f 0
cc 4
nc 1
nop 2
crap 4
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
Documentation introduced by
$response is of type object<Psr\Http\Message\ResponseInterface>, but the function expects a array|string.

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:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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