Completed
Push — master ( 78d48a...8014f5 )
by Дмитрий
11:07
created

AbstractProvider::getAccessToken()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.0416

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 10
cts 12
cp 0.8333
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 3
nop 1
crap 3.0416
1
<?php
2
/**
3
 * SocialConnect project
4
 * @author: Patsura Dmitry https://github.com/ovr <[email protected]>
5
 */
6
7
namespace SocialConnect\OAuth2;
8
9
use InvalidArgumentException;
10
use SocialConnect\OAuth2\Exception\InvalidState;
11
use SocialConnect\OAuth2\Exception\UnknownAuthorization;
12
use SocialConnect\OAuth2\Exception\UnknownState;
13
use SocialConnect\Provider\AbstractBaseProvider;
14
use SocialConnect\Provider\Exception\InvalidAccessToken;
15
use SocialConnect\Provider\Exception\InvalidResponse;
16
use SocialConnect\Common\Http\Client\Client;
17
18
abstract class AbstractProvider extends AbstractBaseProvider
19
{
20
    /**
21
     * HTTP method for access token request
22
     *
23
     * @var string
24
     */
25
    protected $requestHttpMethod = Client::POST;
26
27
    /**
28
     * @return string
29
     */
30
    abstract public function getAuthorizeUri();
31
32
    /**
33
     * @return string
34
     */
35
    abstract public function getRequestTokenUri();
36
37
    /**
38
     * Default parameters for auth url, can be redeclared inside implementation of the Provider
39
     *
40
     * @return array
41
     */
42 1
    public function getAuthUrlParameters()
43
    {
44
        return [
45 1
            'client_id' => $this->consumer->getKey(),
46 1
            'redirect_uri' => $this->getRedirectUrl(),
47 1
            'response_type' => 'code',
48 1
        ];
49
    }
50
51
    /**
52
     * @return string
53
     */
54 1
    protected function generateState()
55
    {
56 1
        return md5(
57 1
            time() . mt_rand()
58 1
        );
59
    }
60
61
    /**
62
     * @return string
63
     */
64 1
    public function makeAuthUrl()
65
    {
66 1
        $urlParameters = $this->getAuthUrlParameters();
67
68 1
        $this->session->set(
69 1
            'oauth2_state',
70 1
            $urlParameters['state'] = $this->generateState()
71 1
        );
72
73 1
        if (count($this->scope) > 0) {
74
            $urlParameters['scope'] = $this->getScopeInline();
75
        }
76
77 1
        if (count($this->fields) > 0) {
78
            $urlParameters['fields'] = $this->getFieldsInline();
79
        }
80
81 1
        return $this->getAuthorizeUri() . '?' . http_build_query($urlParameters);
82
    }
83
84
    /**
85
     * Parse access token from response's $body
86
     *
87
     * @param string|bool $body
88
     * @return AccessToken
89
     * @throws InvalidAccessToken
90
     */
91
    public function parseToken($body)
92
    {
93
        if (empty($body)) {
94
            throw new InvalidAccessToken('Provider response with empty body');
95
        }
96
97
        parse_str($body, $token);
98
99
        if (!is_array($token) || !isset($token['access_token'])) {
100
            throw new InvalidAccessToken('Provider API returned an unexpected response');
101
        }
102
103
        return new AccessToken($token);
104
    }
105
106
    /**
107
     * @param string $code
108
     * @return \SocialConnect\Common\Http\Request
109
     */
110 2
    protected function makeAccessTokenRequest($code)
111
    {
112
        $parameters = [
113 2
            'client_id' => $this->consumer->getKey(),
114 2
            'client_secret' => $this->consumer->getSecret(),
115 2
            'code' => $code,
116 2
            'grant_type' => 'authorization_code',
117 2
            'redirect_uri' => $this->getRedirectUrl()
118 2
        ];
119
120 2
        return new \SocialConnect\Common\Http\Request(
121 2
            $this->getRequestTokenUri(),
122 2
            $parameters,
123 2
            $this->requestHttpMethod,
124
            [
125
                'Content-Type' => 'application/x-www-form-urlencoded'
126 2
            ]
127 2
        );
128
    }
129
130
    /**
131
     * @param string $code
132
     * @return AccessToken
133
     * @throws InvalidResponse
134
     */
135 2
    public function getAccessToken($code)
136
    {
137 2
        if (!is_string($code)) {
138 1
            throw new InvalidArgumentException('Parameter $code must be a string');
139
        }
140
141 1
        $response = $this->httpClient->fromRequest(
142 1
            $this->makeAccessTokenRequest($code)
143 1
        );
144
145 1
        if (!$response->isSuccess()) {
146 1
            throw new InvalidResponse(
147 1
                'API response with error code',
148
                $response
149 1
            );
150
        }
151
152
        $body = $response->getBody();
153
        return $this->parseToken($body);
154
    }
155
156
157
    /**
158
     * @param array $parameters
159
     * @return AccessToken
160
     * @throws \SocialConnect\OAuth2\Exception\InvalidState
161
     * @throws \SocialConnect\OAuth2\Exception\UnknownState
162
     * @throws \SocialConnect\OAuth2\Exception\UnknownAuthorization
163
     */
164
    public function getAccessTokenByRequestParameters(array $parameters)
165
    {
166
        $state = $this->session->get('oauth2_state');
167
        if (!$state) {
168
            throw new UnknownAuthorization();
169
        }
170
171
        if (!isset($parameters['state'])) {
172
            throw new UnknownState();
173
        }
174
175
        if ($state !== $parameters['state']) {
176
            throw new InvalidState();
177
        }
178
179
        return $this->getAccessToken($parameters['code']);
180
    }
181
}
182