Completed
Push — master ( 0c132b...aef04b )
by Patrick
02:32
created

Apple::getBaseAuthorizationUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace League\OAuth2\Client\Provider;
4
5
use Exception;
6
use InvalidArgumentException;
7
use Jose\Component\Core\AlgorithmManager;
8
use Jose\Component\KeyManagement\JWKFactory;
9
use Jose\Component\Signature\Algorithm\ES256;
10
use Jose\Component\Signature\JWSBuilder;
11
use Jose\Component\Signature\Serializer\CompactSerializer;
12
use League\OAuth2\Client\Grant\AbstractGrant;
13
use League\OAuth2\Client\Provider\Exception\AppleAccessDeniedException;
14
use League\OAuth2\Client\Token\AccessToken;
15
use League\OAuth2\Client\Token\AccessTokenInterface;
16
use League\OAuth2\Client\Token\AppleAccessToken;
17
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
18
use Psr\Http\Message\ResponseInterface;
19
20
class Apple extends AbstractProvider
21
{
22
    use BearerAuthorizationTrait;
23
24
    /**
25
     * Default scopes
26
     *
27
     * @var array
28
     */
29
    public $defaultScopes = ['name', 'email'];
30
31
    /**
32
     * @var string the team id
33
     */
34
    protected $teamId;
35
36
    /**
37
     * @var string the key file id
38
     */
39
    protected $keyFileId;
40
41
    /**
42
     * @var string the key file path
43
     */
44
    protected $keyFilePath;
45
46
    /**
47
     * Constructs Apple's OAuth 2.0 service provider.
48
     *
49
     * @param array $options
50
     * @param array $collaborators
51
     */
52 13
    public function __construct(array $options = [], array $collaborators = [])
53
    {
54 13
        if (empty($options['teamId'])) {
55 1
            throw new InvalidArgumentException('Required option not passed: "teamId"');
56
        }
57
58 13
        if (empty($options['keyFileId'])) {
59 1
            throw new InvalidArgumentException('Required option not passed: "keyFileId"');
60
        }
61
62 13
        if (empty($options['keyFilePath'])) {
63 1
            throw new InvalidArgumentException('Required option not passed: "keyFilePath"');
64
        }
65
66 13
        parent::__construct($options, $collaborators);
67 13
    }
68
69
    /**
70
     * Creates an access token from a response.
71
     *
72
     * The grant that was used to fetch the response can be used to provide
73
     * additional context.
74
     *
75
     * @param  array         $response
76
     * @param  AbstractGrant $grant
77
     * @return AccessTokenInterface
78
     */
79
    protected function createAccessToken(array $response, AbstractGrant $grant)
80
    {
81
        return new AppleAccessToken($response);
82
    }
83
84
    /**
85
     * Get the string used to separate scopes.
86
     *
87
     * @return string
88
     */
89 3
    protected function getScopeSeparator()
90
    {
91 3
        return ' ';
92
    }
93
94
    /**
95
     * Change response mode when scope requires it
96
     *
97
     * @param array $options
98
     *
99
     * @return array
100
     */
101 3
    protected function getAuthorizationParameters(array $options)
102
    {
103 3
        $options = parent::getAuthorizationParameters($options);
104 3
        if (strpos($options['scope'], 'name') !== false || strpos($options['scope'], 'email') !== false) {
105 2
            $options['response_mode'] = 'form_post';
106
        }
107 3
        return $options;
108
    }
109
110
    /**
111
     * @param AccessToken $token
112
     *
113
     * @return mixed
114
     */
115 1
    protected function fetchResourceOwnerDetails(AccessToken $token)
116
    {
117 1
        return json_decode(array_key_exists('user', $_GET) ? $_GET['user'] : (array_key_exists('user', $_POST) ? $_POST['user'] : '[]'), true);
118
    }
119
120
    /**
121
     * Get authorization url to begin OAuth flow
122
     *
123
     * @return string
124
     */
125 3
    public function getBaseAuthorizationUrl()
126
    {
127 3
        return 'https://appleid.apple.com/auth/authorize';
128
    }
129
130
    /**
131
     * Get access token url to retrieve token
132
     *
133
     * @return string
134
     */
135 1
    public function getBaseAccessTokenUrl(array $params)
136
    {
137 1
        return 'https://appleid.apple.com/auth/token';
138
    }
139
140
    /**
141
     * Get provider url to fetch user details
142
     *
143
     * @param AccessToken $token
144
     *
145
     * @return string
146
     * @throws Exception
147
     */
148 1
    public function getResourceOwnerDetailsUrl(AccessToken $token)
149
    {
150 1
        throw new Exception('No Apple ID REST API available yet!');
151
    }
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 2
    protected function getDefaultScopes()
162
    {
163 2
        return $this->defaultScopes;
164
    }
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 1
    protected function checkResponse(ResponseInterface $response, $data)
175
    {
176 1
        if ($response->getStatusCode() >= 400) {
177 1
            throw new AppleAccessDeniedException(
178 1
                $data['error'] ?: $response->getReasonPhrase(),
179 1
                $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
            );
182
        }
183
    }
184
185
    /**
186
     * Generate a user object from a successful user details request.
187
     *
188
     * @param  array $response
189
     * @param  Apple $token
190
     * @return AppleResourceOwner
191
     */
192 1
    protected function createResourceOwner(array $response, AccessToken $token)
193
    {
194 1
        return new AppleResourceOwner(
195 1
            array_merge(
196 1
                $response, [
197 1
                'email' => isset($token->getValues()['email'])
198 1
                ? $token->getValues()['email'] : (isset($response['email']) ? $response['email'] : null)
199
                ]
200 1
            ), $token->getResourceOwnerId()
201
        );
202
    }
203
204
    /**
205
     * {@inheritDoc}
206
     */
207
    public function getAccessToken($grant, array $options = [])
208
    {
209
        $algorithmManager = new AlgorithmManager([new ES256()]);
210
        $jwsBuilder = new JWSBuilder($algorithmManager);
211
        $jws = $jwsBuilder
212
            ->create()
213
            ->withPayload(
214
                json_encode(
215
                    [
216
                    'iat' => time(),
217
                    'exp' => time() + 600,
218
                    'iss' => $this->teamId,
219
                    'aud' => 'https://appleid.apple.com',
220
                    'sub' => $this->clientId
221
                    ]
222
                )
223
            )
224
            ->addSignature(
225
                $this->getLocalKey(), [
226
                'alg' => 'ES256',
227
                'kid' => $this->keyFileId
228
                ]
229
            )
230
            ->build();
231
232
        $serializer = new CompactSerializer();
233
        $token = $serializer->serialize($jws);
234
235
        $options += [
236
         'client_secret'    => $token
237
        ];
238
239
        return parent::getAccessToken($grant, $options);
240
    }
241
242
    /**
243
     * @return \Jose\Component\Core\JWK
244
     */
245 1
    public function getLocalKey()
246
    {
247 1
        return JWKFactory::createFromKeyFile($this->keyFilePath);
248
    }
249
}
250