-
Notifications
You must be signed in to change notification settings - Fork 180
/
Copy pathDropboxAuthHelper.php
269 lines (234 loc) · 7.14 KB
/
DropboxAuthHelper.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
<?php
namespace Kunnu\Dropbox\Authentication;
use Kunnu\Dropbox\Models\AccessToken;
use Kunnu\Dropbox\Exceptions\DropboxClientException;
use Kunnu\Dropbox\Store\PersistentDataStoreInterface;
use Kunnu\Dropbox\Security\RandomStringGeneratorInterface;
class DropboxAuthHelper
{
/**
* The length of CSRF string
*
* @const int
*/
const CSRF_LENGTH = 32;
/**
* OAuth2 Client
*
* @var \Kunnu\Dropbox\Authentication\OAuth2Client
*/
protected $oAuth2Client;
/**
* Random String Generator
*
* @var \Kunnu\Dropbox\Security\RandomStringGeneratorInterface
*/
protected $randomStringGenerator;
/**
* Persistent Data Store
*
* @var \Kunnu\Dropbox\Store\PersistentDataStoreInterface
*/
protected $persistentDataStore;
/**
* Additional User Provided State
*
* @var string
*/
protected $urlState = null;
/**
* Create a new DropboxAuthHelper instance
*
* @param \Kunnu\Dropbox\Authentication\OAuth2Client $oAuth2Client
* @param \Kunnu\Dropbox\Security\RandomStringGeneratorInterface $randomStringGenerator
* @param \Kunnu\Dropbox\Store\PersistentDataStoreInterface $persistentDataStore
*/
public function __construct(
OAuth2Client $oAuth2Client,
RandomStringGeneratorInterface $randomStringGenerator = null,
PersistentDataStoreInterface $persistentDataStore = null
) {
$this->oAuth2Client = $oAuth2Client;
$this->randomStringGenerator = $randomStringGenerator;
$this->persistentDataStore = $persistentDataStore;
}
/**
* Get OAuth2Client
*
* @return \Kunnu\Dropbox\Authentication\OAuth2Client
*/
public function getOAuth2Client()
{
return $this->oAuth2Client;
}
/**
* Get the Random String Generator
*
* @return \Kunnu\Dropbox\Security\RandomStringGeneratorInterface
*/
public function getRandomStringGenerator()
{
return $this->randomStringGenerator;
}
/**
* Get the Persistent Data Store
*
* @return \Kunnu\Dropbox\Store\PersistentDataStoreInterface
*/
public function getPersistentDataStore()
{
return $this->persistentDataStore;
}
/**
* Get CSRF Token
*
* @return string
*/
protected function getCsrfToken()
{
$generator = $this->getRandomStringGenerator();
return $generator->generateString(static::CSRF_LENGTH);
}
/**
* Get Authorization URL
*
* @param string $redirectUri Callback URL to redirect to after authorization
* @param array $params Additional Params
* @param string $urlState Additional User Provided State Data
* @param string $tokenAccessType Either `offline` or `online` or null
*
* @link https://www.dropbox.com/developers/documentation/http/documentation#oauth2-authorize
*
* @return string
*/
public function getAuthUrl($redirectUri = null, array $params = [], $urlState = null, $tokenAccessType = null)
{
// If no redirect URI
// is provided, the
// CSRF validation
// is being handled
// explicitly.
$state = null;
// Redirect URI is provided
// thus, CSRF validation
// needs to be handled.
if (!is_null($redirectUri)) {
//Get CSRF State Token
$state = $this->getCsrfToken();
//Set the CSRF State Token in the Persistent Data Store
$this->getPersistentDataStore()->set('state', $state);
//Additional User Provided State Data
if (!is_null($urlState)) {
$state .= "|";
$state .= $urlState;
}
}
//Get OAuth2 Authorization URL
return $this->getOAuth2Client()->getAuthorizationUrl($redirectUri, $state, $params, $tokenAccessType);
}
/**
* Decode State to get the CSRF Token and the URL State
*
* @param string $state State
*
* @return array
*/
protected function decodeState($state)
{
$csrfToken = $state;
$urlState = null;
$splitPos = strpos($state, "|");
if ($splitPos !== false) {
$csrfToken = substr($state, 0, $splitPos);
$urlState = substr($state, $splitPos + 1);
}
return ['csrfToken' => $csrfToken, 'urlState' => $urlState];
}
/**
* Validate CSRF Token
* @param string $csrfToken CSRF Token
*
* @throws DropboxClientException
*
* @return void
*/
protected function validateCSRFToken($csrfToken)
{
$tokenInStore = $this->getPersistentDataStore()->get('state');
//Unable to fetch CSRF Token
if (!$tokenInStore || !$csrfToken) {
throw new DropboxClientException("Invalid CSRF Token. Unable to validate CSRF Token.");
}
//CSRF Token Mismatch
if ($tokenInStore !== $csrfToken) {
throw new DropboxClientException("Invalid CSRF Token. CSRF Token Mismatch.");
}
//Clear the state store
$this->getPersistentDataStore()->clear('state');
}
/**
* Get Access Token
*
* @param string $code Authorization Code
* @param string $state CSRF & URL State
* @param string $redirectUri Redirect URI used while getAuthUrl
*
* @return \Kunnu\Dropbox\Models\AccessToken
* @throws \Kunnu\Dropbox\Exceptions\DropboxClientException
*/
public function getAccessToken($code, $state = null, $redirectUri = null)
{
// No state provided
// Should probably be
// handled explicitly
if (!is_null($state)) {
//Decode the State
$state = $this->decodeState($state);
//CSRF Token
$csrfToken = $state['csrfToken'];
//Set the URL State
$this->urlState = $state['urlState'];
//Validate CSRF Token
$this->validateCSRFToken($csrfToken);
}
//Fetch Access Token
$accessToken = $this->getOAuth2Client()->getAccessToken($code, $redirectUri);
//Make and return the model
return new AccessToken($accessToken);
}
/**
* Get new Access Token by using the refresh token
*
* @param \Kunnu\Dropbox\Models\AccessToken $accessToken - Current access token object
* @param string $grantType ['refresh_token']
*/
public function getRefreshedAccessToken($accessToken, $grantType = 'refresh_token')
{
$newToken = $this->getOAuth2Client()->getAccessToken($accessToken->refresh_token, null, $grantType);
return new AccessToken(
array_merge(
$accessToken->getData(),
$newToken
)
);
}
/**
* Revoke Access Token
*
* @return void
* @throws \Kunnu\Dropbox\Exceptions\DropboxClientException
*/
public function revokeAccessToken()
{
$this->getOAuth2Client()->revokeAccessToken();
}
/**
* Get URL State
*
* @return string
*/
public function getUrlState()
{
return $this->urlState;
}
}