Completed
Push — master ( 44676f...b7bc18 )
by Jens
13:18
created

Manager::getHttpClient()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 8
cts 8
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
nc 3
nop 1
crap 4
1
<?php
2
/**
3
 * @author @jayS-de <[email protected]>
4
 * @created: 22.01.15, 12:34
5
 */
6
7
namespace Commercetools\Core\Client\OAuth;
8
9
use Commercetools\Core\Client\Adapter\CorrelationIdAware;
10
use Commercetools\Core\Config;
11
use Commercetools\Core\Error\ApiException;
12
use Commercetools\Core\Helper\CorrelationIdProvider;
13
use Psr\Cache\CacheItemPoolInterface;
14
use Psr\Http\Message\ResponseInterface;
15
use Commercetools\Core\AbstractHttpClient;
16
use Commercetools\Core\Cache\CacheAdapterFactory;
17
use Commercetools\Core\Error\InvalidClientCredentialsException;
18
use Psr\SimpleCache\CacheInterface;
19
20
/**
21
 * @package Commercetools\Core\OAuth
22
 * @internal
23
 */
24
class Manager extends AbstractHttpClient implements TokenProvider
25
{
26
    const TOKEN_CACHE_KEY = 'commercetools_io_access_token';
27
28
    const ANONYMOUS_ID = 'anonymous_id';
29
    const REFRESH_TOKEN = 'refresh_token';
30
    const ACCESS_TOKEN = 'access_token';
31
    const EXPIRES_IN = 'expires_in';
32
    const ERROR = 'error';
33
    const SCOPE = 'scope';
34
    const ERROR_DESCRIPTION = 'error_description';
35
36
    /**
37
     * @var array
38
     */
39
    protected $cacheKeys;
40
41
    /**
42
     * @var CacheItemPoolInterface|CacheInterface
43
     */
44
    protected $cacheAdapter;
45
46
    /**
47
     * @var CacheAdapterFactory
48
     */
49
    protected $cacheAdapterFactory;
50
51 78
    public function __construct($config, $cache = null)
52
    {
53 78
        parent::__construct($config);
54 78
        $this->cacheKeys = [];
55 78
        $this->setCacheAdapter($cache);
56 78
    }
57
58
    /**
59
     * @return CacheAdapterFactory
60
     */
61 78
    public function getCacheAdapterFactory()
62
    {
63 78
        if (is_null($this->cacheAdapterFactory)) {
64 78
            $this->cacheAdapterFactory = new CacheAdapterFactory($this->getConfig()->getCacheDir());
65
        }
66 78
        return $this->cacheAdapterFactory;
67
    }
68
69
    /**
70
     * @param $cache
71
     * @return $this
72
     */
73 78
    public function setCacheAdapter($cache)
74
    {
75 78
        $this->cacheAdapter = $this->getCacheAdapterFactory()->get($cache);
76
77 78
        return $this;
78
    }
79
80
    /**
81
     * @return CacheItemPoolInterface|CacheInterface
82
     */
83 504
    protected function getCacheAdapter()
84
    {
85 504
        return $this->cacheAdapter;
86
    }
87
88
    /**
89
     * @return Token
90
     * @throws InvalidClientCredentialsException
91
     */
92 503
    public function getToken()
93
    {
94 503
        $scope = $this->getConfig()->getScope();
95 503
        if ($token = $this->getCacheToken()) {
96 498
            return new Token($token, null, $scope);
97
        }
98
99 39
        return $this->refreshToken();
100
    }
101
102
    /**
103
     * @return Token
104
     * @throws InvalidClientCredentialsException
105
     */
106 44
    public function refreshToken()
107
    {
108 44
        $scope = $this->getConfig()->getScope();
109 44
        $grantType = $this->getConfig()->getGrantType();
110 44
        $data = [Config::GRANT_TYPE => $grantType];
111 44
        if (!empty($scope)) {
112 42
            $data[Config::SCOPE] = $scope;
113
        }
114
115
        switch ($grantType) {
116 44
            case Config::GRANT_TYPE_PASSWORD:
117 19
                $user = $this->getConfig()->getUsername();
118 19
                $password = $this->getConfig()->getPassword();
119 19
                $data[Config::USER_NAME] = $user;
120 19
                $data[Config::PASSWORD] = $password;
121 19
                break;
122 39
            case Config::GRANT_TYPE_REFRESH:
123 1
                $refreshToken = $this->getConfig()->getRefreshToken();
124 1
                $data[Config::REFRESH_TOKEN] = $refreshToken;
125 1
                break;
126 39
            case Config::GRANT_TYPE_ANONYMOUS:
127 11
                $data[Config::GRANT_TYPE] = Config::GRANT_TYPE_CLIENT;
128 11
                $anonymousId = $this->getConfig()->getAnonymousId();
129 11
                if (!empty($anonymousId)) {
130 4
                    $data[Config::ANONYMOUS_ID] = $anonymousId;
131
                }
132
        }
133
134 44
        $token = $this->getBearerToken($data);
135
136
        // ensure token to be invalidated in cache before TTL
137 43
        $ttl = max(1, floor($token->getTtl()/2));
138
139 43
        $this->cache($token, $ttl);
140
141 43
        if ($grantType === Config::GRANT_TYPE_PASSWORD || $grantType == Config::GRANT_TYPE_ANONYMOUS) {
142 28
            $this->getConfig()->setRefreshToken($token->getRefreshToken());
143 28
            $this->cache($token, $ttl, $this->getCacheKey(Config::GRANT_TYPE_REFRESH));
144
        }
145
146 43
        return $token;
147
    }
148
149 43
    protected function cache(Token $token, $ttl, $cacheKey = null)
150
    {
151 43
        if (is_null($cacheKey)) {
152 43
            $cacheKey = $this->getCacheKey();
153
        }
154 43
        $cache = $this->getCacheAdapter();
155 43
        if ($cache instanceof CacheItemPoolInterface) {
156 42
            $item = $cache->getItem($cacheKey)->set($token->getToken())->expiresAfter((int)$ttl);
157 42
            $cache->save($item);
158
        }
159 43
        if ($cache instanceof CacheInterface) {
160 1
            $cache->set($cacheKey, $token->getToken(), (int)$ttl);
161
        }
162 43
    }
163
164 503
    protected function getCacheToken()
165
    {
166 503
        $cache = $this->getCacheAdapter();
167 503
        if ($cache instanceof CacheItemPoolInterface) {
168 501
            $item = $cache->getItem($this->getCacheKey());
169 501
            if ($item->isHit()) {
170 497
                return $item->get();
171
            }
172
        }
173 40
        if ($cache instanceof CacheInterface) {
174 2
            return $cache->get($this->getCacheKey(), false);
175
        }
176
177 38
        return false;
178
    }
179
180
    /**
181
     * @return string
182
     */
183 504
    protected function getCacheKey($grantType = null)
184
    {
185 504
        $scope = $this->getConfig()->getScope();
186 504
        if (is_null($grantType)) {
187 504
            $grantType = $this->getConfig()->getGrantType();
188
        }
189 504
        $cacheScope = $scope . '-' . $grantType;
190
191
        switch ($grantType) {
192 504
            case Config::GRANT_TYPE_PASSWORD:
193 19
                $user = base64_encode($this->getConfig()->getUsername());
194 19
                $cacheScope .= '-' . $user;
195 19
                break;
196 504
            case Config::GRANT_TYPE_REFRESH:
197 28
                $token = $this->getConfig()->getRefreshToken();
198 28
                $cacheScope .= '-' . $token;
199 28
                break;
200 504
            case Config::GRANT_TYPE_ANONYMOUS:
201 10
                $anonymousId = $this->getConfig()->getAnonymousId();
202 10
                if (!empty($anonymousId)) {
203 3
                    $cacheScope .= '-' . $anonymousId;
204
                }
205 10
                break;
206
        }
207
208 504
        if (!isset($this->cacheKeys[$cacheScope])) {
209 41
            $this->cacheKeys[$cacheScope] = static::TOKEN_CACHE_KEY . '_' .
210 41
                sha1($cacheScope);
211
        }
212
213 504
        return $this->cacheKeys[$cacheScope];
214
    }
215
216
    /**
217
     * @param array $data
218
     * @return Token
219
     * @throws ApiException
220
     * @throws \Commercetools\Core\Error\BadGatewayException
221
     * @throws \Commercetools\Core\Error\GatewayTimeoutException
222
     * @throws \Commercetools\Core\Error\ServiceUnavailableException
223
     */
224 44
    protected function getBearerToken(array $data)
225
    {
226
        try {
227 44
            $response = $this->execute($data);
228 3
        } catch (ApiException $exception) {
229 3
            throw ApiException::create($exception->getRequest(), $exception->getResponse());
230
        }
231
232 43
        $result = json_decode($response->getBody(), true);
233
234 43
        $token = new Token($result[static::ACCESS_TOKEN], $result[static::EXPIRES_IN], $result[static::SCOPE]);
235 43
        $token->setValidTo(new \DateTime('now +' . $result[static::EXPIRES_IN] . ' seconds'));
236 43
        if (isset($result[static::REFRESH_TOKEN])) {
237 28
            $token->setRefreshToken($result[static::REFRESH_TOKEN]);
238
        }
239
240 43
        return $token;
241
    }
242
243
    /**
244
     * @inheritDoc
245
     */
246 48
    public function getHttpClient($options = [])
247
    {
248 48
        if (is_null($this->httpClient)) {
249 47
            $client = parent::getHttpClient($options);
250 47
            if ($this->getConfig()->getCorrelationIdProvider() instanceof CorrelationIdProvider
251 47
                && $client instanceof CorrelationIdAware
252
            ) {
253 47
                $client->setCorrelationIdProvider($this->getConfig()->getCorrelationIdProvider());
254
            }
255 47
            $this->httpClient = $client;
256
        }
257 48
        return $this->httpClient;
258
    }
259
260
    /**
261
     * @param $data
262
     * @return ResponseInterface
263
     */
264 45
    public function execute($data)
265
    {
266 45
        return $this->getHttpClient()->authenticate(
267 45
            $this->getConfig()->getOauthUrl(),
268 45
            $this->getConfig()->getClientId(),
269 45
            $this->getConfig()->getClientSecret(),
270 45
            $data
271
        );
272
    }
273
274
    /**
275
     * @return string
276
     */
277 47
    protected function getBaseUrl()
278
    {
279 47
        return $this->getConfig()->getOauthUrl();
280
    }
281
}
282