Completed
Push — master ( ae4368...d96fc9 )
by Дмитрий
02:34
created

AbstractProvider   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Test Coverage

Coverage 80%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 13
dl 0
loc 167
ccs 52
cts 65
cp 0.8
rs 10
c 0
b 0
f 0

9 Methods

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