Completed
Pull Request — master (#498)
by Dragonqos
02:30
created

AbstractService::init()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
3
namespace OAuth\OAuth1\Service;
4
5
use OAuth\Common\Consumer\CredentialsInterface;
6
use OAuth\Common\Storage\TokenStorageInterface;
7
use OAuth\Common\Http\Exception\TokenResponseException;
8
use OAuth\Common\Http\Client\ClientInterface;
9
use OAuth\Common\Http\Uri\UriInterface;
10
use OAuth\OAuth1\Signature\SignatureInterface;
11
use OAuth\OAuth1\Token\TokenInterface;
12
use OAuth\OAuth1\Token\StdOAuth1Token;
13
use OAuth\Common\Service\AbstractService as BaseAbstractService;
14
15
abstract class AbstractService extends BaseAbstractService implements ServiceInterface
16
{
17
    /** @const OAUTH_VERSION */
18
    const OAUTH_VERSION = 1;
19
20
    /** @var SignatureInterface */
21
    protected $signature;
22
23
    /** @var UriInterface|null */
24
    protected $baseApiUri;
25
26
    /**
27
     * {@inheritDoc}
28
     */
29
    public function __construct(
30
        CredentialsInterface $credentials,
31
        ClientInterface $httpClient,
32
        TokenStorageInterface $storage,
33
        SignatureInterface $signature,
34
        UriInterface $baseApiUri = null,
35
        $account = null
36
    ) {
37
        parent::__construct($credentials, $httpClient, $storage, $account);
38
39
        $this->signature = $signature;
40
        $this->baseApiUri = $baseApiUri;
41
42
        $this->signature->setHashingAlgorithm($this->getSignatureMethod());
43
44
        $this->init();
45
    }
46
47
    /**
48
     * Constructor extended initialization
49
     */
50
    protected function init() {
51
52
    }
53
54
    /**
55
     * {@inheritDoc}
56
     */
57
    public function requestRequestToken()
58
    {
59
        $authorizationHeader = array('Authorization' => $this->buildAuthorizationHeaderForTokenRequest());
60
        $headers = array_merge($authorizationHeader, $this->getExtraOAuthHeaders());
61
62
        $responseBody = $this->httpClient->retrieveResponse($this->getRequestTokenEndpoint(), array(), $headers);
63
64
        $token = $this->parseRequestTokenResponse($responseBody);
65
        $this->storage->storeAccessToken($this->service(), $token, $this->account());
66
67
        return $token;
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73
    public function getAuthorizationUri(array $additionalParameters = array())
74
    {
75
        // Build the url
76
        $url = clone $this->getAuthorizationEndpoint();
77
        foreach ($additionalParameters as $key => $val) {
78
            $url->addToQuery($key, $val);
79
        }
80
81
        return $url;
82
    }
83
84
    /**
85
     * {@inheritDoc}
86
     */
87
    public function requestAccessToken($token, $verifier, $tokenSecret = null)
88
    {
89
        if (is_null($tokenSecret)) {
90
            $storedRequestToken = $this->storage->retrieveAccessToken($this->service(), $this->account());
91
            $tokenSecret = $storedRequestToken->getRequestTokenSecret();
92
        }
93
        $this->signature->setTokenSecret($tokenSecret);
94
95
        $bodyParams = array(
96
            'oauth_verifier' => $verifier,
97
        );
98
99
        $authorizationHeader = array(
100
            'Authorization' => $this->buildAuthorizationHeaderForAPIRequest(
101
                'POST',
102
                $this->getAccessTokenEndpoint(),
103
                $this->storage->retrieveAccessToken($this->service(), $this->account()),
0 ignored issues
show
Compatibility introduced by
$this->storage->retrieve...ce(), $this->account()) of type object<OAuth\Common\Token\TokenInterface> is not a sub-type of object<OAuth\OAuth1\Token\TokenInterface>. It seems like you assume a child interface of the interface OAuth\Common\Token\TokenInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
104
                $bodyParams
105
            )
106
        );
107
108
        $headers = array_merge($authorizationHeader, $this->getExtraOAuthHeaders());
109
110
        $responseBody = $this->httpClient->retrieveResponse($this->getAccessTokenEndpoint(), $bodyParams, $headers);
111
112
        $token = $this->parseAccessTokenResponse($responseBody);
113
        $this->storage->storeAccessToken($this->service(), $token, $this->account());
114
115
        return $token;
116
    }
117
118
    /**
119
     * Refreshes an OAuth1 access token
120
     * @param  TokenInterface $token
121
     * @return TokenInterface $token
122
     */
123
    public function refreshAccessToken(TokenInterface $token)
124
    {
125
    }
126
127
    /**
128
     * Sends an authenticated API request to the path provided.
129
     * If the path provided is not an absolute URI, the base API Uri (must be passed into constructor) will be used.
130
     *
131
     * @param string|UriInterface $path
132
     * @param string              $method       HTTP method
133
     * @param array               $body         Request body if applicable (key/value pairs)
134
     * @param array               $extraHeaders Extra headers if applicable.
135
     *                                          These will override service-specific any defaults.
136
     *
137
     * @return string
138
     */
139
    public function request($path, $method = 'GET', $body = null, array $extraHeaders = array())
140
    {
141
        $uri = $this->determineRequestUriFromPath($path, $this->baseApiUri);
142
143
        /** @var $token StdOAuth1Token */
144
        $token = $this->storage->retrieveAccessToken($this->service(), $this->account());
145
        $extraHeaders = array_merge($this->getExtraApiHeaders(), $extraHeaders);
146
        $authorizationHeader = array(
147
            'Authorization' => $this->buildAuthorizationHeaderForAPIRequest($method, $uri, $token, $body)
148
        );
149
        $headers = array_merge($authorizationHeader, $extraHeaders);
150
151
        return $this->httpClient->retrieveResponse($uri, $body, $headers, $method);
152
    }
153
154
    /**
155
     * Return any additional headers always needed for this service implementation's OAuth calls.
156
     *
157
     * @return array
158
     */
159
    protected function getExtraOAuthHeaders()
160
    {
161
        return array();
162
    }
163
164
    /**
165
     * Return any additional headers always needed for this service implementation's API calls.
166
     *
167
     * @return array
168
     */
169
    protected function getExtraApiHeaders()
170
    {
171
        return array();
172
    }
173
174
    /**
175
     * Builds the authorization header for getting an access or request token.
176
     *
177
     * @param array $extraParameters
178
     *
179
     * @return string
180
     */
181
    protected function buildAuthorizationHeaderForTokenRequest(array $extraParameters = array())
182
    {
183
        $parameters = $this->getBasicAuthorizationHeaderInfo();
184
        $parameters = array_merge($parameters, $extraParameters);
185
        $parameters['oauth_signature'] = $this->signature->getSignature(
186
            $this->getRequestTokenEndpoint(),
187
            $parameters,
188
            'POST'
189
        );
190
191
        $authorizationHeader = 'OAuth ';
192
        $delimiter = '';
193
        foreach ($parameters as $key => $value) {
194
            $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"';
195
196
            $delimiter = ', ';
197
        }
198
199
        return $authorizationHeader;
200
    }
201
202
    /**
203
     * Builds the authorization header for an authenticated API request
204
     *
205
     * @param string         $method
206
     * @param UriInterface   $uri        The uri the request is headed
207
     * @param TokenInterface $token
208
     * @param array          $bodyParams Request body if applicable (key/value pairs)
209
     *
210
     * @return string
211
     */
212
    protected function buildAuthorizationHeaderForAPIRequest(
213
        $method,
214
        UriInterface $uri,
215
        TokenInterface $token,
216
        $bodyParams = null
217
    ) {
218
        $this->signature->setTokenSecret($token->getAccessTokenSecret());
219
        $authParameters = $this->getBasicAuthorizationHeaderInfo();
220
        if (isset($authParameters['oauth_callback'])) {
221
            unset($authParameters['oauth_callback']);
222
        }
223
224
        $authParameters = array_merge($authParameters, array('oauth_token' => $token->getAccessToken()));
225
226
        $signatureParams = (is_array($bodyParams)) ? array_merge($authParameters, $bodyParams) : $authParameters;
227
        $authParameters['oauth_signature'] = $this->signature->getSignature($uri, $signatureParams, $method);
228
229
        if (is_array($bodyParams) && isset($bodyParams['oauth_session_handle'])) {
230
            $authParameters['oauth_session_handle'] = $bodyParams['oauth_session_handle'];
231
            unset($bodyParams['oauth_session_handle']);
232
        }
233
234
        $authorizationHeader = 'OAuth ';
235
        $delimiter = '';
236
237
        foreach ($authParameters as $key => $value) {
238
            $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"';
239
            $delimiter = ', ';
240
        }
241
242
        return $authorizationHeader;
243
    }
244
245
    /**
246
     * Builds the authorization header array.
247
     *
248
     * @return array
249
     */
250
    protected function getBasicAuthorizationHeaderInfo()
251
    {
252
        $dateTime = new \DateTime();
253
        $headerParameters = array(
254
            'oauth_callback'         => $this->credentials->getCallbackUrl(),
255
            'oauth_consumer_key'     => $this->credentials->getConsumerId(),
256
            'oauth_nonce'            => $this->generateNonce(),
257
            'oauth_signature_method' => $this->getSignatureMethod(),
258
            'oauth_timestamp'        => $dateTime->format('U'),
259
            'oauth_version'          => $this->getVersion(),
260
        );
261
262
        return $headerParameters;
263
    }
264
265
    /**
266
     * Pseudo random string generator used to build a unique string to sign each request
267
     *
268
     * @param int $length
269
     *
270
     * @return string
271
     */
272
    protected function generateNonce($length = 32)
273
    {
274
        $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
275
276
        $nonce = '';
277
        $maxRand = strlen($characters)-1;
278
        for ($i = 0; $i < $length; $i++) {
279
            $nonce.= $characters[rand(0, $maxRand)];
280
        }
281
282
        return $nonce;
283
    }
284
285
    /**
286
     * @return string
287
     */
288
    protected function getSignatureMethod()
289
    {
290
        return 'HMAC-SHA1';
291
    }
292
293
    /**
294
     * This returns the version used in the authorization header of the requests
295
     *
296
     * @return string
297
     */
298
    protected function getVersion()
299
    {
300
        return '1.0';
301
    }
302
303
    /**
304
     * Parses the request token response and returns a TokenInterface.
305
     * This is only needed to verify the `oauth_callback_confirmed` parameter. The actual
306
     * parsing logic is contained in the access token parser.
307
     *
308
     * @abstract
309
     *
310
     * @param string $responseBody
311
     *
312
     * @return TokenInterface
313
     *
314
     * @throws TokenResponseException
315
     */
316
    abstract protected function parseRequestTokenResponse($responseBody);
317
318
    /**
319
     * Parses the access token response and returns a TokenInterface.
320
     *
321
     * @abstract
322
     *
323
     * @param string $responseBody
324
     *
325
     * @return TokenInterface
326
     *
327
     * @throws TokenResponseException
328
     */
329
    abstract protected function parseAccessTokenResponse($responseBody);
330
}
331