Passed
Branch php-scrutinizer (9ddcba)
by Jens
09:45
created

Manager::getHttpClient()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

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