Completed
Pull Request — master (#12)
by Ruben
10:32 queued 02:52
created

TokenManager   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 5.68%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 20
c 1
b 0
f 0
lcom 1
cbo 5
dl 0
loc 193
ccs 5
cts 88
cp 0.0568
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
B createNewTokens() 0 37 2
B createAccessTokenFromRefreshToken() 0 29 2
B logTokenData() 0 12 5
D getToken() 0 40 10
1
<?php
2
3
namespace MovingImage\Client\VMPro\Manager;
4
5
use GuzzleHttp\ClientInterface;
6
use MovingImage\Client\VMPro\Entity\ApiCredentials;
7
use MovingImage\Client\VMPro\Entity\Token;
8
use MovingImage\Client\VMPro\Extractor\TokenExtractor;
9
use MovingImage\Util\Logging\Traits\LoggerAwareTrait;
10
use Psr\Log\LoggerAwareInterface;
11
12
/**
13
 * Class TokenManager.
14
 *
15
 * @author Ruben Knol <[email protected]>
16
 */
17
class TokenManager implements LoggerAwareInterface
18
{
19
    use LoggerAwareTrait;
20
21
    /**
22
     * @var ClientInterface
23
     */
24
    private $httpClient;
25
26
    /**
27
     * @var ApiCredentials
28
     */
29
    protected $credentials;
30
31
    /**
32
     * @var TokenExtractor
33
     */
34
    private $tokenExtractor;
35
36
    /**
37
     * @var Token
38
     */
39
    private $accessToken;
40
41
    /**
42
     * @var Token
43
     */
44
    private $refreshToken;
45
46
    /**
47
     * TokenManager constructor.
48
     *
49
     * @param ClientInterface $httpClient
50
     * @param ApiCredentials  $credentials
51
     */
52 2
    public function __construct(
53
        ClientInterface $httpClient,
54
        ApiCredentials $credentials,
55
        TokenExtractor $tokenExtractor
56
    ) {
57 2
        $this->httpClient = $httpClient;
58 2
        $this->credentials = $credentials;
59 2
        $this->tokenExtractor = $tokenExtractor;
60 2
    }
61
62
    /**
63
     * Create completely fresh Access + Refresh tokens.
64
     *
65
     * @TODO Implement proper error handling
66
     *
67
     * @return array
68
     */
69
    protected function createNewTokens()
70
    {
71
        $logger = $this->getLogger();
72
        $logger->debug('Starting request to create fresh access & refresh tokens');
73
74
        try {
75
            $response = $this->httpClient->post('auth/login', [
76
                'json' => [
77
                    'username' => $this->credentials->getUsername(),
78
                    'password' => $this->credentials->getPassword(),
79
                ],
80
                'headers' => [
81
                    'accept: application/json',
82
                    'cache-control: no-cache',
83
                    'content-type: application/json',
84
                ],
85
            ]);
86
87
            $data = \json_decode($response->getBody(), true);
88
            $logger->debug('Successfully retrieved new access & refresh tokens', $data);
89
90
            return [
91
                'accessToken' => new Token(
92
                    $data['accessToken'],
93
                    $this->tokenExtractor->extract($data['accessToken']),
94
                    $data['validForVideoManager']
95
                ),
96
                'refreshToken' => new Token(
97
                    $data['refreshToken'],
98
                    $this->tokenExtractor->extract($data['refreshToken']),
99
                    $data['validForVideoManager']
100
                ),
101
            ];
102
        } catch (\Exception $e) {
103
            throw $e; // Just rethrow for now
104
        }
105
    }
106
107
    /**
108
     * Create a new access token for a video manager using a refresh token.
109
     *
110
     * @param Token $refreshToken
111
     * @param int   $videoManagerId
112
     *
113
     * @return Token
114
     */
115
    protected function createAccessTokenFromRefreshToken(Token $refreshToken, $videoManagerId)
116
    {
117
        $logger = $this->getLogger();
118
        $logger->debug('Starting request to create fresh access & refresh tokens');
119
120
        try {
121
            $response = $this->httpClient->post(sprintf('auth/refresh/%d', $videoManagerId), [
122
                'json' => [
123
                    'refreshToken' => $refreshToken->getTokenString(),
124
                ],
125
                'headers' => [
126
                    'accept: application/json',
127
                    'cache-control: no-cache',
128
                    'content-type: application/json',
129
                ],
130
            ]);
131
132
            $data = \json_decode($response->getBody(), true);
133
            $logger->debug('Successfully retrieved new access token', $data);
134
135
            return new Token(
136
                $data['accessToken'],
137
                $this->tokenExtractor->extract($data['accessToken']),
138
                $videoManagerId
139
            );
140
        } catch (\Exception $e) {
141
            throw $e;
142
        }
143
    }
144
145
    /**
146
     * Log information about which tokens we have.
147
     */
148
    protected function logTokenData()
149
    {
150
        $this->getLogger()->debug('Token information', [
151
            'accessTokenExists' => isset($this->accessToken),
152
            'accessTokenExpiration' => isset($this->accessToken) ? $this->accessToken->getTokenData()['exp'] : null,
153
            'accessTokenHasExpired' => isset($this->accessToken) ? $this->accessToken->expired() : null,
154
            'refreshTokenExists' => isset($this->refreshToken),
155
            'refreshTokenExpiration' => isset($this->refreshToken) ? $this->refreshToken->getTokenData()['exp'] : null,
156
            'refreshTokenHasExpired' => isset($this->refreshToken) ? $this->refreshToken->expired() : null,
157
            'localTime' => time(),
158
        ]);
159
    }
160
161
    /**
162
     * Retrieve a valid token.
163
     *
164
     * @param int $videoManagerId Which video manager a token is requested for
165
     * @TODO Refactor token storage to support multiple re-usable tokens, one per video manager
166
     *
167
     * @return string
168
     */
169
    public function getToken($videoManagerId = null)
170
    {
171
        $logger = $this->getLogger();
172
        $this->logTokenData();
173
174
        // Access token has expired, but expiration token has not expired.
175
        // Issue ourselves a new access token for the same video manager.
176
        if (!is_null($this->accessToken)
177
            && $this->accessToken->expired()
178
            && !$this->refreshToken->expired()) {
179
            $logger->info('Access token has expired - getting new one for same video manager with refresh token');
180
            $tokenData = $this->createAccessTokenFromRefreshToken(
181
                $this->refreshToken,
182
                $this->accessToken->getVideoManagerId()
183
            );
184
185
            $this->accessToken = $tokenData['accessToken'];
186
        } elseif (is_null($this->accessToken)
187
            || (!is_null($this->refreshToken) && $this->refreshToken->expired())) {
188
            // Either we have no token, or the refresh token has expired
189
            // so we will need to generate completely new tokens
190
            $logger->info('No access token, or refresh token has expired - generate completely new ones');
191
            $tokenData = $this->createNewTokens();
192
193
            $this->accessToken = $tokenData['accessToken'];
194
            $this->refreshToken = $tokenData['refreshToken'];
195
        }
196
197
        // Video manager is not matching with the one that our token
198
        // was generated with - issue ourselves a token for the video manager
199
        // we need.
200
        if (!is_null($videoManagerId)
201
            && isset($this->accessToken)
202
            && $this->accessToken->getVideoManagerId() != $videoManagerId) {
203
            $logger->info('Attempting to use token for different video manager - generate valid access token');
204
            $this->accessToken = $this->createAccessTokenFromRefreshToken($this->refreshToken, $videoManagerId);
205
        }
206
207
        return $this->accessToken->getTokenString();
208
    }
209
}
210