Completed
Push — develop ( e77623...3cc0f7 )
by Jens
09:01
created

Manager::getCacheKey()   C

Complexity

Conditions 7
Paths 20

Size

Total Lines 32
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 7

Importance

Changes 4
Bugs 0 Features 1
Metric Value
c 4
b 0
f 1
dl 0
loc 32
ccs 22
cts 22
cp 1
rs 6.7272
cc 7
eloc 23
nc 20
nop 1
crap 7
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 Cache\Adapter\Common\CacheItem;
10
use Commercetools\Core\Config;
11
use Commercetools\Core\Error\ApiException;
12
use Psr\Cache\CacheItemPoolInterface;
13
use Psr\Http\Message\ResponseInterface;
14
use Commercetools\Core\AbstractHttpClient;
15
use Commercetools\Core\Cache\CacheAdapterFactory;
16
use Commercetools\Core\Cache\CacheAdapterInterface;
17
use Commercetools\Core\Error\InvalidClientCredentialsException;
18
19
/**
20
 * @package Commercetools\Core\OAuth
21
 * @internal
22
 */
23
class Manager extends AbstractHttpClient
24
{
25
    const TOKEN_CACHE_KEY = 'commercetools_io_access_token';
26
27
    const ANONYMOUS_ID = 'anonymous_id';
28
    const REFRESH_TOKEN = 'refresh_token';
29
    const ACCESS_TOKEN = 'access_token';
30
    const EXPIRES_IN = 'expires_in';
31
    const ERROR = 'error';
32
    const SCOPE = 'scope';
33
    const ERROR_DESCRIPTION = 'error_description';
34
35
    /**
36
     * @var array
37
     */
38
    protected $cacheKeys;
39
40
    /**
41
     * @var CacheAdapterInterface|CacheItemPoolInterface
42
     */
43
    protected $cacheAdapter;
44
45
    /**
46
     * @var CacheAdapterFactory
47
     */
48
    protected $cacheAdapterFactory;
49
50 65
    public function __construct($config, $cache = null)
51
    {
52 65
        parent::__construct($config);
53 65
        $this->cacheKeys = [];
54 65
        $this->setCacheAdapter($cache);
55 65
    }
56
57
    /**
58
     * @return CacheAdapterFactory
59
     */
60 65
    public function getCacheAdapterFactory()
61
    {
62 65
        if (is_null($this->cacheAdapterFactory)) {
63 65
            $this->cacheAdapterFactory = new CacheAdapterFactory($this->getConfig()->getCacheDir());
64
        }
65 65
        return $this->cacheAdapterFactory;
66
    }
67
68
    /**
69
     * @param $cache
70
     * @return $this
71
     */
72 65
    public function setCacheAdapter($cache)
73
    {
74 65
        $this->cacheAdapter = $this->getCacheAdapterFactory()->get($cache);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getCacheAdapterFactory()->get($cache) can also be of type object<Commercetools\Cor...\CacheAdapterInterface>. However, the property $cacheAdapter is declared as type object<Psr\Cache\CacheItemPoolInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
75
76 65
        return $this;
77
    }
78
79
    /**
80
     * @internal will become protected in version 2.0
81
     * @return CacheAdapterInterface|CacheItemPoolInterface
82
     */
83 345
    public function getCacheAdapter()
84
    {
85 345
        return $this->cacheAdapter;
86
    }
87
88
    /**
89
     * @return Token
90
     * @throws InvalidClientCredentialsException
91
     */
92 343
    public function getToken()
93
    {
94 343
        $scope = $this->getConfig()->getScope();
95 343
        if ($token = $this->getCacheToken()) {
96 342
            return new Token($token, null, $scope);
97
        }
98
99 31
        return $this->refreshToken();
100
    }
101
102
    /**
103
     * @return Token
104
     * @throws InvalidClientCredentialsException
105
     */
106 38
    public function refreshToken()
107
    {
108 38
        $scope = $this->getConfig()->getScope();
109 38
        $grantType = $this->getConfig()->getGrantType();
110 38
        $data = [Config::SCOPE => $scope, Config::GRANT_TYPE => $grantType];
111
112
        switch ($grantType) {
113 38
            case Config::GRANT_TYPE_PASSWORD:
114 17
                $user = $this->getConfig()->getUsername();
115 17
                $password = $this->getConfig()->getPassword();
116 17
                $data[Config::USER_NAME] = $user;
117 17
                $data[Config::PASSWORD] = $password;
118 17
                break;
119 33
            case Config::GRANT_TYPE_REFRESH:
120 1
                $refreshToken = $this->getConfig()->getRefreshToken();
121 1
                $data[Config::REFRESH_TOKEN] = $refreshToken;
122 1
                break;
123 33
            case Config::GRANT_TYPE_ANONYMOUS:
124 9
                $data[Config::GRANT_TYPE] = Config::GRANT_TYPE_CLIENT;
125 9
                $anonymousId = $this->getConfig()->getAnonymousId();
126 9
                if (!empty($anonymousId)) {
127 4
                    $data[Config::ANONYMOUS_ID] = $anonymousId;
128
                }
129
        }
130
131 38
        $token = $this->getBearerToken($data);
132
133
        // ensure token to be invalidated in cache before TTL
134 37
        $ttl = max(1, floor($token->getTtl()/2));
135
136 37
        $this->cache($token, $ttl);
137
138 37
        if ($grantType === Config::GRANT_TYPE_PASSWORD || $grantType == Config::GRANT_TYPE_ANONYMOUS) {
139 24
            $this->getConfig()->setRefreshToken($token->getRefreshToken());
140 24
            $this->cache($token, $ttl, $this->getCacheKey(Config::GRANT_TYPE_REFRESH));
141
        }
142
143 37
        return $token;
144
    }
145
146 37
    protected function cache(Token $token, $ttl, $cacheKey = null)
147
    {
148 37
        if (is_null($cacheKey)) {
149 37
            $cacheKey = $this->getCacheKey();
150
        }
151 37
        $cache = $this->getCacheAdapter();
152 37
        if ($cache instanceof CacheAdapterInterface) {
153 5
            $cache->store($cacheKey, $token->getToken(), (int)$ttl);
154
        }
155 37
        if ($cache instanceof CacheItemPoolInterface) {
156 32
            $item = new CacheItem($cacheKey, true, $token->getToken());
157 32
            $item->expiresAfter((int)$ttl);
158 32
            $cache->save($item);
159
        }
160 37
    }
161
162 343
    protected function getCacheToken()
163
    {
164 343
        $cache = $this->getCacheAdapter();
165 343
        if ($cache instanceof CacheAdapterInterface) {
166 6
            return $cache->fetch($this->getCacheKey());
167
        }
168 338
        if ($cache instanceof CacheItemPoolInterface) {
169 338
            $item = $cache->getItem($this->getCacheKey());
170 338
            if ($item->isHit()) {
171 338
                return $item->get();
172
            }
173
        }
174
175 26
        return false;
176
    }
177
178
    /**
179
     * @return string
180
     */
181 343
    protected function getCacheKey($grantType = null)
182
    {
183 343
        $scope = $this->getConfig()->getScope();
184 343
        if (is_null($grantType)) {
185 343
            $grantType = $this->getConfig()->getGrantType();
186
        }
187 343
        $cacheScope = $scope . '-' . $grantType;
188
189
        switch ($grantType) {
190 343
            case Config::GRANT_TYPE_PASSWORD:
191 17
                $user = base64_encode($this->getConfig()->getUsername());
192 17
                $cacheScope .= '-' . $user;
193 17
                break;
194 343
            case Config::GRANT_TYPE_REFRESH:
195 24
                $token = $this->getConfig()->getRefreshToken();
196 24
                $cacheScope .= '-' . $token;
197 24
                break;
198 343
            case Config::GRANT_TYPE_ANONYMOUS:
199 8
                $anonymousId = $this->getConfig()->getAnonymousId();
200 8
                if (!empty($anonymousId)) {
201 3
                    $cacheScope .= '-' . $anonymousId;
202
                }
203 8
                break;
204
        }
205
206 343
        if (!isset($this->cacheKeys[$cacheScope])) {
207 31
            $this->cacheKeys[$cacheScope] = static::TOKEN_CACHE_KEY . '_' .
208 31
                sha1($cacheScope);
209
        }
210
211 343
        return $this->cacheKeys[$cacheScope];
212
    }
213
214
    /**
215
     * @param array $data
216
     * @return Token
217
     * @throws ApiException
218
     * @throws \Commercetools\Core\Error\BadGatewayException
219
     * @throws \Commercetools\Core\Error\GatewayTimeoutException
220
     * @throws \Commercetools\Core\Error\ServiceUnavailableException
221
     */
222 38
    protected function getBearerToken(array $data)
223
    {
224
        try {
225 38
            $response = $this->execute($data);
226 3
        } catch (ApiException $exception) {
227 3
            throw ApiException::create($exception->getRequest(), $exception->getResponse());
228
        }
229
230 37
        $result = json_decode($response->getBody(), true);
231
232 37
        $token = new Token($result[static::ACCESS_TOKEN], $result[static::EXPIRES_IN], $result[static::SCOPE]);
233 37
        $token->setValidTo(new \DateTime('now +' . $result[static::EXPIRES_IN] . ' seconds'));
234 37
        if (isset($result[static::REFRESH_TOKEN])) {
235 24
            $token->setRefreshToken($result[static::REFRESH_TOKEN]);
236
        }
237
238 37
        return $token;
239
    }
240
241
    /**
242
     * @param $data
243
     * @return ResponseInterface
244
     */
245 38
    public function execute($data)
246
    {
247 38
        return $this->getHttpClient()->authenticate(
248 38
            $this->getConfig()->getOauthUrl(),
249 38
            $this->getConfig()->getClientId(),
250 38
            $this->getConfig()->getClientSecret(),
251
            $data
252
        );
253
    }
254
255
    /**
256
     * @return string
257
     */
258 37
    protected function getBaseUrl()
259
    {
260 37
        return $this->getConfig()->getOauthUrl();
261
    }
262
}
263