Completed
Pull Request — master (#12)
by Ruben
10:34
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 0
Metric Value
wmc 20
lcom 1
cbo 5
dl 0
loc 193
ccs 5
cts 88
cp 0.0568
rs 10
c 0
b 0
f 0

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