Completed
Push — 3.x ( 497b30...ca6623 )
by Дмитрий
03:36 queued 53s
created

AbstractProvider::createAccessToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * SocialConnect project
4
 * @author: Patsura Dmitry https://github.com/ovr <[email protected]>
5
 */
6
declare(strict_types=1);
7
8
namespace SocialConnect\OAuth2;
9
10
use Psr\Http\Message\RequestInterface;
11
use SocialConnect\OAuth2\Exception\InvalidState;
12
use SocialConnect\OAuth2\Exception\Unauthorized;
13
use SocialConnect\OAuth2\Exception\UnknownAuthorization;
14
use SocialConnect\OAuth2\Exception\UnknownState;
15
use SocialConnect\Provider\AbstractBaseProvider;
16
use SocialConnect\Provider\Exception\InvalidAccessToken;
17
use SocialConnect\Provider\Exception\InvalidResponse;
18
19
abstract class AbstractProvider extends AbstractBaseProvider
20
{
21
    /**
22
     * HTTP method for access token request
23
     *
24
     * @var string
25
     */
26
    protected $requestHttpMethod = '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
     * {@inheritdoc}
40
     */
41 23
    public function getAuthUrlParameters(): array
42
    {
43 23
        $parameters = parent::getAuthUrlParameters();
44
45
        // special parameters only required for OAuth2
46 23
        $parameters['client_id'] = $this->consumer->getKey();
47 23
        $parameters['redirect_uri'] = $this->getRedirectUrl();
48 23
        $parameters['response_type'] = 'code';
49
50 23
        return $parameters;
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56 23
    public function makeAuthUrl(): string
57
    {
58 23
        $urlParameters = $this->getAuthUrlParameters();
59
60 23
        if (!$this->getBoolOption('stateless', false)) {
61 23
            $this->session->set(
62 23
                'oauth2_state',
63 23
                $urlParameters['state'] = $this->generateState()
64
            );
65
        }
66
67 23
        if (count($this->scope) > 0) {
68 23
            $urlParameters['scope'] = $this->getScopeInline();
69
        }
70
71 23
        return $this->getAuthorizeUri() . '?' . http_build_query($urlParameters);
72
    }
73
74
    /**
75
     * Parse access token from response's $body
76
     *
77
     * @param string $body
78
     * @return AccessToken
79
     * @throws InvalidAccessToken
80
     */
81 82
    public function parseToken(string $body)
82
    {
83 82
        if (empty($body)) {
84 20
            throw new InvalidAccessToken('Provider response with empty body');
85
        }
86
87 62
        $token = json_decode($body, true);
88 62
        if ($token) {
89 21
            if (!is_array($token)) {
90
                throw new InvalidAccessToken('Response must be array');
91
            }
92
93 21
            return new AccessToken($token);
94
        }
95
96 41
        throw new InvalidAccessToken('Server response with not valid/empty JSON');
97
    }
98
99
    /**
100
     * @param string $code
101
     * @return RequestInterface
102
     */
103 22
    protected function makeAccessTokenRequest(string $code): RequestInterface
104
    {
105
        $parameters = [
106 22
            'client_id' => $this->consumer->getKey(),
107 22
            'client_secret' => $this->consumer->getSecret(),
108 22
            'code' => $code,
109 22
            'grant_type' => 'authorization_code',
110 22
            'redirect_uri' => $this->getRedirectUrl()
111
        ];
112
113 22
        return $this->httpStack->createRequest($this->requestHttpMethod, $this->getRequestTokenUri())
114 22
            ->withHeader('Content-Type', 'application/x-www-form-urlencoded')
115 22
            ->withBody($this->httpStack->createStream(http_build_query($parameters, '', '&')))
116
        ;
117
    }
118
119
    /**
120
     * @param string $code
121
     * @return AccessToken
122
     * @throws InvalidAccessToken
123
     * @throws InvalidResponse
124
     * @throws \Psr\Http\Client\ClientExceptionInterface
125
     */
126 24
    public function getAccessToken(string $code): AccessToken
127
    {
128 24
        $response = $this->executeRequest(
129 24
            $this->makeAccessTokenRequest($code)
130
        );
131
132
        return $this->parseToken($response->getBody()->getContents());
133
    }
134
135
    /**
136
     * @param array $parameters
137
     * @return AccessToken
138
     * @throws InvalidAccessToken
139
     * @throws InvalidResponse
140
     * @throws InvalidState
141
     * @throws Unauthorized
142
     * @throws UnknownAuthorization
143
     * @throws UnknownState
144
     * @throws \Psr\Http\Client\ClientExceptionInterface
145
     */
146 23
    public function getAccessTokenByRequestParameters(array $parameters)
147
    {
148 23
        if (isset($parameters['error']) && $parameters['error'] === 'access_denied') {
149 23
            throw new Unauthorized();
150
        }
151
152
        if (!isset($parameters['code'])) {
153
            throw new Unauthorized('Unknown code');
154
        }
155
156
        if (!$this->getBoolOption('stateless', false)) {
157
            $state = $this->session->get('oauth2_state');
158
            if (!$state) {
159
                throw new UnknownAuthorization();
160
            }
161
162
            if (!isset($parameters['state'])) {
163
                throw new UnknownState();
164
            }
165
166
            if ($state !== $parameters['state']) {
167
                throw new InvalidState();
168
            }
169
        }
170
171
        return $this->getAccessToken($parameters['code']);
172
    }
173
174
    /**
175
     * {@inheritDoc}
176
     */
177
    public function createAccessToken(array $information)
178
    {
179
        return new AccessToken($information);
180
    }
181
}
182