Completed
Pull Request — master (#479)
by Andrey
02:39
created

AbstractService   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 306
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 6
Bugs 3 Features 3
Metric Value
wmc 23
c 6
b 3
f 3
lcom 1
cbo 6
dl 0
loc 306
rs 10

16 Methods

Rating   Name   Duplication   Size   Complexity  
A refreshAccessToken() 0 3 1
B buildAuthorizationHeaderForAPIRequest() 0 32 6
A __construct() 0 14 1
A requestRequestToken() 0 12 1
A getAuthorizationUri() 0 10 2
B requestAccessToken() 0 30 2
A request() 0 14 1
A getExtraOAuthHeaders() 0 4 1
A getExtraApiHeaders() 0 4 1
A buildAuthorizationHeaderForTokenRequest() 0 20 2
A getBasicAuthorizationHeaderInfo() 0 14 1
A generateNonce() 0 12 2
A getSignatureMethod() 0 4 1
A getVersion() 0 4 1
parseRequestTokenResponse() 0 1 ?
parseAccessTokenResponse() 0 1 ?
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
    ) {
36
        parent::__construct($credentials, $httpClient, $storage);
37
38
        $this->signature = $signature;
39
        $this->baseApiUri = $baseApiUri;
40
41
        $this->signature->setHashingAlgorithm($this->getSignatureMethod());
42
    }
43
44
    /**
45
     * {@inheritDoc}
46
     */
47
    public function requestRequestToken()
48
    {
49
        $authorizationHeader = array('Authorization' => $this->buildAuthorizationHeaderForTokenRequest());
50
        $headers = array_merge($authorizationHeader, $this->getExtraOAuthHeaders());
51
52
        $responseBody = $this->httpClient->retrieveResponse($this->getRequestTokenEndpoint(), array(), $headers);
53
54
        $token = $this->parseRequestTokenResponse($responseBody);
55
        $this->storage->storeAccessToken($this->service(), $token);
56
57
        return $token;
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function getAuthorizationUri(array $additionalParameters = array())
64
    {
65
        // Build the url
66
        $url = clone $this->getAuthorizationEndpoint();
67
        foreach ($additionalParameters as $key => $val) {
68
            $url->addToQuery($key, $val);
69
        }
70
71
        return $url;
72
    }
73
74
    /**
75
     * {@inheritDoc}
76
     */
77
    public function requestAccessToken($token, $verifier, $tokenSecret = null)
78
    {
79
        if (is_null($tokenSecret)) {
80
            $storedRequestToken = $this->storage->retrieveAccessToken($this->service());
81
            $tokenSecret = $storedRequestToken->getRequestTokenSecret();
82
        }
83
        $this->signature->setTokenSecret($tokenSecret);
84
85
        $bodyParams = array(
86
            'oauth_verifier' => $verifier,
87
        );
88
89
        $authorizationHeader = array(
90
            'Authorization' => $this->buildAuthorizationHeaderForAPIRequest(
91
                'POST',
92
                $this->getAccessTokenEndpoint(),
93
                $this->storage->retrieveAccessToken($this->service()),
0 ignored issues
show
Compatibility introduced by
$this->storage->retrieve...Token($this->service()) 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...
94
                $bodyParams
95
            )
96
        );
97
98
        $headers = array_merge($authorizationHeader, $this->getExtraOAuthHeaders());
99
100
        $responseBody = $this->httpClient->retrieveResponse($this->getAccessTokenEndpoint(), $bodyParams, $headers);
101
102
        $token = $this->parseAccessTokenResponse($responseBody);
103
        $this->storage->storeAccessToken($this->service(), $token);
104
105
        return $token;
106
    }
107
108
    /**
109
     * Refreshes an OAuth1 access token
110
     * @param  TokenInterface $token
111
     * @return TokenInterface $token
112
     */
113
    public function refreshAccessToken(TokenInterface $token)
114
    {
115
    }
116
117
    /**
118
     * Sends an authenticated API request to the path provided.
119
     * If the path provided is not an absolute URI, the base API Uri (must be passed into constructor) will be used.
120
     *
121
     * @param string|UriInterface $path
122
     * @param string              $method       HTTP method
123
     * @param array               $body         Request body if applicable (key/value pairs)
124
     * @param array               $extraHeaders Extra headers if applicable.
125
     *                                          These will override service-specific any defaults.
126
     *
127
     * @return string
128
     */
129
    public function request($path, $method = 'GET', $body = null, array $extraHeaders = array())
130
    {
131
        $uri = $this->determineRequestUriFromPath($path, $this->baseApiUri);
132
133
        /** @var $token StdOAuth1Token */
134
        $token = $this->storage->retrieveAccessToken($this->service());
135
        $extraHeaders = array_merge($this->getExtraApiHeaders(), $extraHeaders);
136
        $authorizationHeader = array(
137
            'Authorization' => $this->buildAuthorizationHeaderForAPIRequest($method, $uri, $token, $body)
138
        );
139
        $headers = array_merge($authorizationHeader, $extraHeaders);
140
141
        return $this->httpClient->retrieveResponse($uri, $body, $headers, $method);
142
    }
143
144
    /**
145
     * Return any additional headers always needed for this service implementation's OAuth calls.
146
     *
147
     * @return array
148
     */
149
    protected function getExtraOAuthHeaders()
150
    {
151
        return array();
152
    }
153
154
    /**
155
     * Return any additional headers always needed for this service implementation's API calls.
156
     *
157
     * @return array
158
     */
159
    protected function getExtraApiHeaders()
160
    {
161
        return array();
162
    }
163
164
    /**
165
     * Builds the authorization header for getting an access or request token.
166
     *
167
     * @param array $extraParameters
168
     *
169
     * @return string
170
     */
171
    protected function buildAuthorizationHeaderForTokenRequest(array $extraParameters = array())
172
    {
173
        $parameters = $this->getBasicAuthorizationHeaderInfo();
174
        $parameters = array_merge($parameters, $extraParameters);
175
        $parameters['oauth_signature'] = $this->signature->getSignature(
176
            $this->getRequestTokenEndpoint(),
177
            $parameters,
178
            'POST'
179
        );
180
181
        $authorizationHeader = 'OAuth ';
182
        $delimiter = '';
183
        foreach ($parameters as $key => $value) {
184
            $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"';
185
186
            $delimiter = ', ';
187
        }
188
189
        return $authorizationHeader;
190
    }
191
192
    /**
193
     * Builds the authorization header for an authenticated API request
194
     *
195
     * @param string         $method
196
     * @param UriInterface   $uri        The uri the request is headed
197
     * @param TokenInterface $token
198
     * @param array          $bodyParams Request body if applicable (key/value pairs)
199
     *
200
     * @return string
201
     */
202
    protected function buildAuthorizationHeaderForAPIRequest(
203
        $method,
204
        UriInterface $uri,
205
        TokenInterface $token,
206
        $bodyParams = null
207
    ) {
208
        $this->signature->setTokenSecret($token->getAccessTokenSecret());
209
        $authParameters = $this->getBasicAuthorizationHeaderInfo();
210
        if (isset($authParameters['oauth_callback'])) {
211
            unset($authParameters['oauth_callback']);
212
        }
213
214
        $authParameters = array_merge($authParameters, array('oauth_token' => $token->getAccessToken()));
215
216
        $signatureParams = (is_array($bodyParams)) ? array_merge($authParameters, $bodyParams) : $authParameters;
217
        $authParameters['oauth_signature'] = $this->signature->getSignature($uri, $signatureParams, $method);
218
219
        if (is_array($bodyParams) && isset($bodyParams['oauth_session_handle'])) {
220
            $authParameters['oauth_session_handle'] = $bodyParams['oauth_session_handle'];
221
            unset($bodyParams['oauth_session_handle']);
222
        }
223
224
        $authorizationHeader = 'OAuth ';
225
        $delimiter = '';
226
227
        foreach ($authParameters as $key => $value) {
228
            $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"';
229
            $delimiter = ', ';
230
        }
231
232
        return $authorizationHeader;
233
    }
234
235
    /**
236
     * Builds the authorization header array.
237
     *
238
     * @return array
239
     */
240
    protected function getBasicAuthorizationHeaderInfo()
241
    {
242
        $dateTime = new \DateTime();
243
        $headerParameters = array(
244
            'oauth_callback'         => $this->credentials->getCallbackUrl(),
245
            'oauth_consumer_key'     => $this->credentials->getConsumerId(),
246
            'oauth_nonce'            => $this->generateNonce(),
247
            'oauth_signature_method' => $this->getSignatureMethod(),
248
            'oauth_timestamp'        => $dateTime->format('U'),
249
            'oauth_version'          => $this->getVersion(),
250
        );
251
252
        return $headerParameters;
253
    }
254
255
    /**
256
     * Pseudo random string generator used to build a unique string to sign each request
257
     *
258
     * @param int $length
259
     *
260
     * @return string
261
     */
262
    protected function generateNonce($length = 32)
263
    {
264
        $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
265
266
        $nonce = '';
267
        $maxRand = strlen($characters)-1;
268
        for ($i = 0; $i < $length; $i++) {
269
            $nonce.= $characters[rand(0, $maxRand)];
270
        }
271
272
        return $nonce;
273
    }
274
275
    /**
276
     * @return string
277
     */
278
    protected function getSignatureMethod()
279
    {
280
        return 'HMAC-SHA1';
281
    }
282
283
    /**
284
     * This returns the version used in the authorization header of the requests
285
     *
286
     * @return string
287
     */
288
    protected function getVersion()
289
    {
290
        return '1.0';
291
    }
292
293
    /**
294
     * Parses the request token response and returns a TokenInterface.
295
     * This is only needed to verify the `oauth_callback_confirmed` parameter. The actual
296
     * parsing logic is contained in the access token parser.
297
     *
298
     * @abstract
299
     *
300
     * @param string $responseBody
301
     *
302
     * @return TokenInterface
303
     *
304
     * @throws TokenResponseException
305
     */
306
    abstract protected function parseRequestTokenResponse($responseBody);
307
308
    /**
309
     * Parses the access token response and returns a TokenInterface.
310
     *
311
     * @abstract
312
     *
313
     * @param string $responseBody
314
     *
315
     * @return TokenInterface
316
     *
317
     * @throws TokenResponseException
318
     */
319
    abstract protected function parseAccessTokenResponse($responseBody);
320
}
321