Completed
Pull Request — master (#12)
by Ruben
08:48
created

TokenManager::createAccessTokenFromRefreshToken()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 25
ccs 0
cts 17
cp 0
rs 8.8571
cc 1
eloc 16
nc 1
nop 2
crap 2
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
        $response = $this->httpClient->post('auth/login', [
75
            'json' => [
76
                'username' => $this->credentials->getUsername(),
77
                'password' => $this->credentials->getPassword(),
78
            ],
79
            'headers' => [
80
                'accept: application/json',
81
                'cache-control: no-cache',
82
                'content-type: application/json',
83
            ],
84
        ]);
85
86
        $data = \json_decode($response->getBody(), true);
87
        $logger->debug('Successfully retrieved new access & refresh tokens', $data);
88
89
        return [
90
            'accessToken' => new Token(
91
                $data['accessToken'],
92
                $this->tokenExtractor->extract($data['accessToken']),
93
                $data['validForVideoManager']
94
            ),
95
            'refreshToken' => new Token(
96
                $data['refreshToken'],
97
                $this->tokenExtractor->extract($data['refreshToken']),
98
                null
99
            ),
100
        ];
101
    }
102
103
    /**
104
     * Create a new access token for a video manager using a refresh token.
105
     *
106
     * @param Token $refreshToken
107
     * @param int   $videoManagerId
108
     *
109
     * @return Token
110
     */
111
    protected function createAccessTokenFromRefreshToken(Token $refreshToken, $videoManagerId)
112
    {
113
        $logger = $this->getLogger();
114
        $logger->debug('Starting request to create fresh access token from refresh token');
115
116
        $response = $this->httpClient->post(sprintf('auth/refresh/%d', $videoManagerId), [
117
            'json' => [
118
                'refreshToken' => $refreshToken->getTokenString(),
119
            ],
120
            'headers' => [
121
                'accept: application/json',
122
                'cache-control: no-cache',
123
                'content-type: application/json',
124
            ],
125
        ]);
126
127
        $data = \json_decode($response->getBody(), true);
128
        $logger->debug('Successfully retrieved new access token', $data);
129
130
        return new Token(
131
            $data['accessToken'],
132
            $this->tokenExtractor->extract($data['accessToken']),
133
            $videoManagerId
134
        );
135
    }
136
137
    /**
138
     * Log information about which tokens we have.
139
     */
140
    protected function logTokenData()
141
    {
142
        $this->getLogger()->debug('Token information', [
143
            'accessTokenExists' => isset($this->accessToken),
144
            'accessTokenExpiration' => isset($this->accessToken) ? $this->accessToken->getTokenData()['exp'] : null,
145
            'accessTokenHasExpired' => isset($this->accessToken) ? $this->accessToken->expired() : null,
146
            'refreshTokenExists' => isset($this->refreshToken),
147
            'refreshTokenExpiration' => isset($this->refreshToken) ? $this->refreshToken->getTokenData()['exp'] : null,
148
            'refreshTokenHasExpired' => isset($this->refreshToken) ? $this->refreshToken->expired() : null,
149
            'localTime' => time(),
150
        ]);
151
    }
152
153
    /**
154
     * Retrieve a valid token.
155
     *
156
     * @param int $videoManagerId Which video manager a token is requested for
157
     * @TODO Refactor token storage to support multiple re-usable tokens, one per video manager
158
     *
159
     * @return string
160
     */
161
    public function getToken($videoManagerId = null)
162
    {
163
        $logger = $this->getLogger();
164
        $this->logTokenData();
165
166
        // Access token has expired, but expiration token has not expired.
167
        // Issue ourselves a new access token for the same video manager.
168
        if (!is_null($this->accessToken)
169
            && $this->accessToken->expired()
170
            && !$this->refreshToken->expired()) {
171
            $logger->info('Access token has expired - getting new one for same video manager with refresh token');
172
            $tokenData = $this->createAccessTokenFromRefreshToken(
173
                $this->refreshToken,
174
                $this->accessToken->getVideoManagerId()
175
            );
176
177
            $this->accessToken = $tokenData['accessToken'];
178
        } elseif (is_null($this->accessToken)
179
            || (!is_null($this->refreshToken) && $this->refreshToken->expired())) {
180
            // Either we have no token, or the refresh token has expired
181
            // so we will need to generate completely new tokens
182
            $logger->info('No access token, or refresh token has expired - generate completely new ones');
183
            $tokenData = $this->createNewTokens();
184
185
            $this->accessToken = $tokenData['accessToken'];
186
            $this->refreshToken = $tokenData['refreshToken'];
187
        }
188
189
        // Video manager is not matching with the one that our token
190
        // was generated with - issue ourselves a token for the video manager
191
        // we need.
192
        if (!is_null($videoManagerId)
193
            && isset($this->accessToken)
194
            && $this->accessToken->getVideoManagerId() != $videoManagerId) {
195
            $logger->info('Attempting to use token for different video manager - generate valid access token');
196
            $this->accessToken = $this->createAccessTokenFromRefreshToken($this->refreshToken, $videoManagerId);
197
        }
198
199
        return $this->accessToken->getTokenString();
200
    }
201
}
202