PluginProbe
ManageWP Worker / 4.0.1
ManageWP Worker v4.0.1
4.9.38 4.9.37 4.9.36 4.9.35 4.9.34 3.8.7 3.8.8 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.22 3.9.23 3.9.24 All 73 releases
worker / src / Dropbox / WebAuth.php

WebAuth.php in ManageWP Worker 4.0.1, at src/Dropbox/WebAuth.php

282 lines 10.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * OAuth 2 "authorization code" flow. (This SDK does not support the "token" flow.)
5 *
6 * Use {@link WebAuth::start()} and {@link WebAuth::finish()} to guide your
7 * user through the process of giving your app access to their Dropbox account.
8 * At the end, you will have an access token, which you can pass to {@link Client}
9 * and start making API calls.
10 *
11 * Example:
12 *
13 * <code>
14 * use \Dropbox as dbx;
15 *
16 * function getWebAuth()
17 * {
18 * $appInfo = dbx\AppInfo::loadFromJsonFile(...);
19 * $clientIdentifier = "my-app/1.0";
20 * $redirectUri = "https://example.org/dropbox-auth-finish";
21 * $csrfTokenStore = new dbx\ArrayEntryStore($_SESSION, 'dropbox-auth-csrf-token');
22 * return new dbx\WebAuth($appInfo, $clientIdentifier, $redirectUri, $csrfTokenStore, ...);
23 * }
24 *
25 * // ----------------------------------------------------------
26 * // In the URL handler for "/dropbox-auth-start"
27 *
28 * $authorizeUrl = getWebAuth()->start();
29 * header("Location: $authorizeUrl");
30 *
31 * // ----------------------------------------------------------
32 * // In the URL handler for "/dropbox-auth-finish"
33 *
34 * try {
35 * list($accessToken, $userId, $urlState) = getWebAuth()->finish($_GET);
36 * assert($urlState === null); // Since we didn't pass anything in start()
37 * }
38 * catch (dbx\WebAuthException_BadRequest $ex) {
39 * error_log("/dropbox-auth-finish: bad request: " . $ex->getMessage());
40 * // Respond with an HTTP 400 and display error page...
41 * }
42 * catch (dbx\WebAuthException_BadState $ex) {
43 * // Auth session expired. Restart the auth process.
44 * header('Location: /dropbox-auth-start');
45 * }
46 * catch (dbx\WebAuthException_Csrf $ex) {
47 * error_log("/dropbox-auth-finish: CSRF mismatch: " . $ex->getMessage());
48 * // Respond with HTTP 403 and display error page...
49 * }
50 * catch (dbx\WebAuthException_NotApproved $ex) {
51 * error_log("/dropbox-auth-finish: not approved: " . $ex->getMessage());
52 * }
53 * catch (dbx\WebAuthException_Provider $ex) {
54 * error_log("/dropbox-auth-finish: error redirect from Dropbox: " . $ex->getMessage());
55 * }
56 * catch (dbx\Exception $ex) {
57 * error_log("/dropbox-auth-finish: error communicating with Dropbox API: " . $ex->getMessage());
58 * }
59 *
60 * // We can now use $accessToken to make API requests.
61 * $client = dbx\Client($accessToken, ...);
62 * </code>
63 *
64 */
65 class Dropbox_WebAuth extends Dropbox_WebAuthBase
66 {
67 /**
68 * The URI that the Dropbox server will redirect the user to after the user finishes
69 * authorizing your app. This URI must be HTTPS-based and
70 * <a href="https://www.dropbox.com/developers/apps">pre-registered with Dropbox</a>,
71 * though "localhost"-based and "127.0.0.1"-based URIs are allowed without pre-registration
72 * and can be either HTTP or HTTPS.
73 *
74 * @return string
75 */
76 public function getRedirectUri()
77 {
78 return $this->redirectUri;
79 }
80
81 /** @var string */
82 private $redirectUri;
83
84 /**
85 * A object that lets us save CSRF token string to the user's session. If you're using the
86 * standard PHP <code>$_SESSION</code>, you can pass in something like
87 * <code>new ArrayEntryStore($_SESSION, 'dropbox-auth-csrf-token')</code>.
88 *
89 * If you're not using $_SESSION, you might have to create your own class that provides
90 * the same <code>get()</code>/<code>set()</code>/<code>clear()</code> methods as
91 * {@link ArrayEntryStore}.
92 *
93 * @return Dropbox_ValueStore
94 */
95 public function getCsrfTokenStore()
96 {
97 return $this->csrfTokenStore;
98 }
99
100 /** @var object */
101 private $csrfTokenStore;
102
103 /**
104 * Constructor.
105 *
106 * @param Dropbox_AppInfo $appInfo
107 * See {@link getAppInfo()}
108 * @param string $clientIdentifier
109 * See {@link getClientIdentifier()}
110 * @param null|string $redirectUri
111 * See {@link getRedirectUri()}
112 * @param null|Dropbox_ValueStore $csrfTokenStore
113 * See {@link getCsrfTokenStore()}
114 * @param null|string $userLocale
115 * See {@link getUserLocale()}
116 */
117 public function __construct($appInfo, $clientIdentifier, $redirectUri, $csrfTokenStore, $userLocale = null)
118 {
119 parent::__construct($appInfo, $clientIdentifier, $userLocale);
120
121 Dropbox_Checker::argStringNonEmpty("redirectUri", $redirectUri);
122
123 $this->csrfTokenStore = $csrfTokenStore;
124 $this->redirectUri = $redirectUri;
125 }
126
127 /**
128 * Starts the OAuth 2 authorization process, which involves redirecting the user to the
129 * returned authorization URL (a URL on the Dropbox website). When the user then
130 * either approves or denies your app access, Dropbox will redirect them to the
131 * <code>$redirectUri</code> given to constructor, at which point you should
132 * call {@link finish()} to complete the authorization process.
133 *
134 * This function will also save a CSRF token using the <code>$csrfTokenStore</code> given to
135 * the constructor. This CSRF token will be checked on {@link finish()} to prevent
136 * request forgery.
137 *
138 * See <a href="https://www.dropbox.com/developers/core/docs#oa2-authorize">/oauth2/authorize</a>.
139 *
140 * @param string|null $urlState
141 * Any data you would like to keep in the URL through the authorization process.
142 * This exact state will be returned to you by {@link finish()}.
143 *
144 * @return array
145 * The URL to redirect the user to.
146 *
147 * @throws Dropbox_Exception
148 */
149 public function start($urlState = null)
150 {
151 Dropbox_Checker::argStringOrNull("urlState", $urlState);
152
153 $csrfToken = self::encodeCsrfToken(Dropbox_Security::getRandomBytes(16));
154 $state = $csrfToken;
155 if ($urlState !== null) {
156 $state .= "|";
157 $state .= $urlState;
158 }
159 $this->csrfTokenStore->set($csrfToken);
160
161 return $this->_getAuthorizeUrl($this->redirectUri, $state);
162 }
163
164 private static function encodeCsrfToken($string)
165 {
166 return strtr(base64_encode($string), '+/', '-_');
167 }
168
169 /**
170 * Call this after the user has visited the authorize URL ({@link start()}), approved your app,
171 * and was redirected to your redirect URI.
172 *
173 * See <a href="https://www.dropbox.com/developers/core/docs#oa2-token">/oauth2/token</a>.
174 *
175 * @param array $queryParams
176 * The query parameters on the GET request to your redirect URI.
177 *
178 * @return array
179 * A <code>list(string $accessToken, string $userId, string $urlState)</code>, where
180 * <code>$accessToken</code> can be used to construct a {@link Client}, <code>$userId</code>
181 * is the user ID of the user's Dropbox account, and <code>$urlState</code> is the
182 * value you originally passed in to {@link start()}.
183 *
184 * @throws Dropbox_Exception
185 * Thrown if there's an error getting the access token from Dropbox.
186 * @throws Dropbox_WebAuthException_BadRequest
187 * @throws Dropbox_WebAuthException_BadState
188 * @throws Dropbox_WebAuthException_Csrf
189 * @throws Dropbox_WebAuthException_NotApproved
190 * @throws Dropbox_WebAuthException_Provider
191 *
192 *
193 */
194 public function finish($queryParams)
195 {
196 Dropbox_Checker::argArray("queryParams", $queryParams);
197
198 $csrfTokenFromSession = $this->csrfTokenStore->get();
199 Dropbox_Checker::argStringOrNull("this->csrfTokenStore->get()", $csrfTokenFromSession);
200
201 // Check well-formedness of request.
202
203 if (!isset($queryParams['state'])) {
204 throw new Dropbox_WebAuthException_BadRequest("Missing query parameter 'state'.");
205 }
206 $state = $queryParams['state'];
207 Dropbox_Checker::argString("queryParams['state']", $state);
208
209 $error = null;
210 $errorDescription = null;
211 if (isset($queryParams['error'])) {
212 $error = $queryParams['error'];
213 Dropbox_Checker::argString("queryParams['error']", $error);
214 if (isset($queryParams['error_description'])) {
215 $errorDescription = $queryParams['error_description'];
216 Dropbox_Checker::argString("queryParams['error_description']", $errorDescription);
217 }
218 }
219
220 $code = null;
221 if (isset($queryParams['code'])) {
222 $code = $queryParams['code'];
223 Dropbox_Checker::argString("queryParams['code']", $code);
224 }
225
226 if ($code !== null && $error !== null) {
227 throw new Dropbox_WebAuthException_BadRequest("Query parameters 'code' and 'error' are both set;".
228 " only one must be set.");
229 }
230 if ($code === null && $error === null) {
231 throw new Dropbox_WebAuthException_BadRequest("Neither query parameter 'code' or 'error' is set.");
232 }
233
234 // Check CSRF token
235
236 if ($csrfTokenFromSession === null) {
237 throw new Dropbox_WebAuthException_BadState();
238 }
239
240 $splitPos = strpos($state, "|");
241 if ($splitPos === false) {
242 $givenCsrfToken = $state;
243 $urlState = null;
244 } else {
245 $givenCsrfToken = substr($state, 0, $splitPos);
246 $urlState = substr($state, $splitPos + 1);
247 }
248 if (!Dropbox_Security::stringEquals($csrfTokenFromSession, $givenCsrfToken)) {
249 throw new Dropbox_WebAuthException_Csrf("Expected ".Dropbox_Client::q($csrfTokenFromSession).
250 ", got ".Dropbox_Client::q($givenCsrfToken).".");
251 }
252 $this->csrfTokenStore->clear();
253
254 // Check for error identifier
255
256 if ($error !== null) {
257 if ($error === 'access_denied') {
258 // When the user clicks "Deny".
259 if ($errorDescription === null) {
260 throw new Dropbox_WebAuthException_NotApproved("No additional description from Dropbox.");
261 } else {
262 throw new Dropbox_WebAuthException_NotApproved("Additional description from Dropbox: $errorDescription");
263 }
264 } else {
265 // All other errors.
266 $fullMessage = $error;
267 if ($errorDescription !== null) {
268 $fullMessage .= ": ";
269 $fullMessage .= $errorDescription;
270 }
271 throw new Dropbox_WebAuthException_Provider($fullMessage);
272 }
273 }
274
275 // If everything went ok, make the network call to get an access token.
276
277 list($accessToken, $userId) = $this->_finish($code, $this->redirectUri);
278
279 return array($accessToken, $userId, $urlState);
280 }
281 }
282