Verzeichnisstruktur phpBB-3.1.0
- Veröffentlicht
- 27.10.2014
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
oauth.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\auth\provider\oauth;
015
016 use OAuth\Common\Consumer\Credentials;
017
018 /**
019 * OAuth authentication provider for phpBB3
020 */
021 class oauth extends \phpbb\auth\provider\base
022 {
023 /**
024 * Database driver
025 *
026 * @var \phpbb\db\driver\driver_interface
027 */
028 protected $db;
029
030 /**
031 * phpBB config
032 *
033 * @var \phpbb\config\config
034 */
035 protected $config;
036
037 /**
038 * phpBB passwords manager
039 *
040 * @var \phpbb\passwords\manager
041 */
042 protected $passwords_manager;
043
044 /**
045 * phpBB request object
046 *
047 * @var \phpbb\request\request_interface
048 */
049 protected $request;
050
051 /**
052 * phpBB user
053 *
054 * @var \phpbb\user
055 */
056 protected $user;
057
058 /**
059 * OAuth token table
060 *
061 * @var string
062 */
063 protected $auth_provider_oauth_token_storage_table;
064
065 /**
066 * OAuth account association table
067 *
068 * @var string
069 */
070 protected $auth_provider_oauth_token_account_assoc;
071
072 /**
073 * All OAuth service providers
074 *
075 * @var \phpbb\di\service_collection Contains \phpbb\auth\provider\oauth\service_interface
076 */
077 protected $service_providers;
078
079 /**
080 * Users table
081 *
082 * @var string
083 */
084 protected $users_table;
085
086 /**
087 * Cached current uri object
088 *
089 * @var \OAuth\Common\Http\Uri\UriInterface|null
090 */
091 protected $current_uri;
092
093 /**
094 * DI container
095 *
096 * @var \Symfony\Component\DependencyInjection\ContainerInterface
097 */
098 protected $phpbb_container;
099
100 /**
101 * phpBB root path
102 *
103 * @var string
104 */
105 protected $phpbb_root_path;
106
107 /**
108 * PHP file extension
109 *
110 * @var string
111 */
112 protected $php_ext;
113
114 /**
115 * OAuth Authentication Constructor
116 *
117 * @param \phpbb\db\driver\driver_interface $db
118 * @param \phpbb\config\config $config
119 * @param \phpbb\passwords\manager $passwords_manager
120 * @param \phpbb\request\request_interface $request
121 * @param \phpbb\user $user
122 * @param string $auth_provider_oauth_token_storage_table
123 * @param string $auth_provider_oauth_token_account_assoc
124 * @param \phpbb\di\service_collection $service_providers Contains \phpbb\auth\provider\oauth\service_interface
125 * @param string $users_table
126 * @param \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container
127 * @param string $phpbb_root_path
128 * @param string $php_ext
129 */
130 public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request_interface $request, \phpbb\user $user, $auth_provider_oauth_token_storage_table, $auth_provider_oauth_token_account_assoc, \phpbb\di\service_collection $service_providers, $users_table, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, $phpbb_root_path, $php_ext)
131 {
132 $this->db = $db;
133 $this->config = $config;
134 $this->passwords_manager = $passwords_manager;
135 $this->request = $request;
136 $this->user = $user;
137 $this->auth_provider_oauth_token_storage_table = $auth_provider_oauth_token_storage_table;
138 $this->auth_provider_oauth_token_account_assoc = $auth_provider_oauth_token_account_assoc;
139 $this->service_providers = $service_providers;
140 $this->users_table = $users_table;
141 $this->phpbb_container = $phpbb_container;
142 $this->phpbb_root_path = $phpbb_root_path;
143 $this->php_ext = $php_ext;
144 }
145
146 /**
147 * {@inheritdoc}
148 */
149 public function init()
150 {
151 // This does not test whether or not the key and secret provided are valid.
152 foreach ($this->service_providers as $service_provider)
153 {
154 $credentials = $service_provider->get_service_credentials();
155
156 if (($credentials['key'] && !$credentials['secret']) || (!$credentials['key'] && $credentials['secret']))
157 {
158 return $this->user->lang['AUTH_PROVIDER_OAUTH_ERROR_ELEMENT_MISSING'];
159 }
160 }
161 return false;
162 }
163
164 /**
165 * {@inheritdoc}
166 */
167 public function login($username, $password)
168 {
169 // Temporary workaround for only having one authentication provider available
170 if (!$this->request->is_set('oauth_service'))
171 {
172 $provider = new \phpbb\auth\provider\db($this->db, $this->config, $this->passwords_manager, $this->request, $this->user, $this->phpbb_container, $this->phpbb_root_path, $this->php_ext);
173 return $provider->login($username, $password);
174 }
175
176 // Requst the name of the OAuth service
177 $service_name_original = $this->request->variable('oauth_service', '', false);
178 $service_name = 'auth.provider.oauth.service.' . strtolower($service_name_original);
179 if ($service_name_original === '' || !array_key_exists($service_name, $this->service_providers))
180 {
181 return array(
182 'status' => LOGIN_ERROR_EXTERNAL_AUTH,
183 'error_msg' => 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST',
184 'user_row' => array('user_id' => ANONYMOUS),
185 );
186 }
187
188 // Get the service credentials for the given service
189 $service_credentials = $this->service_providers[$service_name]->get_service_credentials();
190
191 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
192 $query = 'mode=login&login=external&oauth_service=' . $service_name_original;
193 $service = $this->get_service($service_name_original, $storage, $service_credentials, $query, $this->service_providers[$service_name]->get_auth_scope());
194
195 if ($this->request->is_set('code', \phpbb\request\request_interface::GET))
196 {
197 $this->service_providers[$service_name]->set_external_service_provider($service);
198 $unique_id = $this->service_providers[$service_name]->perform_auth_login();
199
200 // Check to see if this provider is already assosciated with an account
201 $data = array(
202 'provider' => $service_name_original,
203 'oauth_provider_id' => $unique_id
204 );
205 $sql = 'SELECT user_id FROM ' . $this->auth_provider_oauth_token_account_assoc . '
206 WHERE ' . $this->db->sql_build_array('SELECT', $data);
207 $result = $this->db->sql_query($sql);
208 $row = $this->db->sql_fetchrow($result);
209 $this->db->sql_freeresult($result);
210
211 if (!$row)
212 {
213 // The user does not yet exist, ask to link or create profile
214 return array(
215 'status' => LOGIN_SUCCESS_LINK_PROFILE,
216 'error_msg' => 'LOGIN_OAUTH_ACCOUNT_NOT_LINKED',
217 'user_row' => array(),
218 'redirect_data' => array(
219 'auth_provider' => 'oauth',
220 'login_link_oauth_service' => $service_name_original,
221 ),
222 );
223 }
224
225 // Retrieve the user's account
226 $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts
227 FROM ' . $this->users_table . '
228 WHERE user_id = ' . (int) $row['user_id'];
229 $result = $this->db->sql_query($sql);
230 $row = $this->db->sql_fetchrow($result);
231 $this->db->sql_freeresult($result);
232
233 if (!$row)
234 {
235 throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY');
236 }
237
238 // Update token storage to store the user_id
239 $storage->set_user_id($row['user_id']);
240
241 // The user is now authenticated and can be logged in
242 return array(
243 'status' => LOGIN_SUCCESS,
244 'error_msg' => false,
245 'user_row' => $row,
246 );
247 }
248 else
249 {
250 $url = $service->getAuthorizationUri();
251 header('Location: ' . $url);
252 }
253 }
254
255 /**
256 * Returns the cached current_uri object or creates and caches it if it is
257 * not already created. In each case the query string is updated based on
258 * the $query parameter.
259 *
260 * @param string $service_name The name of the service
261 * @param string $query The query string of the current_uri
262 * used in redirects
263 * @return \OAuth\Common\Http\Uri\UriInterface
264 */
265 protected function get_current_uri($service_name, $query)
266 {
267 if ($this->current_uri)
268 {
269 $this->current_uri->setQuery($query);
270 return $this->current_uri;
271 }
272
273 $uri_factory = new \OAuth\Common\Http\Uri\UriFactory();
274 $current_uri = $uri_factory->createFromSuperGlobalArray($this->request->get_super_global(\phpbb\request\request_interface::SERVER));
275 $current_uri->setQuery($query);
276
277 $this->current_uri = $current_uri;
278 return $current_uri;
279 }
280
281 /**
282 * Returns a new service object
283 *
284 * @param string $service_name The name of the service
285 * @param \phpbb\auth\provider\oauth\token_storage $storage
286 * @param array $service_credentials {@see \phpbb\auth\provider\oauth\oauth::get_service_credentials}
287 * @param string $query The query string of the
288 * current_uri used in redirection
289 * @param array $scopes The scope of the request against
290 * the api.
291 * @return \OAuth\Common\Service\ServiceInterface
292 * @throws \Exception
293 */
294 protected function get_service($service_name, \phpbb\auth\provider\oauth\token_storage $storage, array $service_credentials, $query, array $scopes = array())
295 {
296 $current_uri = $this->get_current_uri($service_name, $query);
297
298 // Setup the credentials for the requests
299 $credentials = new Credentials(
300 $service_credentials['key'],
301 $service_credentials['secret'],
302 $current_uri->getAbsoluteUri()
303 );
304
305 $service_factory = new \OAuth\ServiceFactory();
306 $service = $service_factory->createService($service_name, $credentials, $storage, $scopes);
307
308 if (!$service)
309 {
310 throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_SERVICE_NOT_CREATED');
311 }
312
313 return $service;
314 }
315
316 /**
317 * {@inheritdoc}
318 */
319 public function get_login_data()
320 {
321 $login_data = array(
322 'TEMPLATE_FILE' => 'login_body_oauth.html',
323 'BLOCK_VAR_NAME' => 'oauth',
324 'BLOCK_VARS' => array(),
325 );
326
327 foreach ($this->service_providers as $service_name => $service_provider)
328 {
329 // Only include data if the credentials are set
330 $credentials = $service_provider->get_service_credentials();
331 if ($credentials['key'] && $credentials['secret'])
332 {
333 $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name);
334 $redirect_url = build_url(false) . '&login=external&oauth_service=' . $actual_name;
335 $login_data['BLOCK_VARS'][$service_name] = array(
336 'REDIRECT_URL' => redirect($redirect_url, true),
337 'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)],
338 );
339 }
340 }
341
342 return $login_data;
343 }
344
345 /**
346 * {@inheritdoc}
347 */
348 public function acp()
349 {
350 $ret = array();
351
352 foreach ($this->service_providers as $service_name => $service_provider)
353 {
354 $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name);
355 $ret[] = 'auth_oauth_' . $actual_name . '_key';
356 $ret[] = 'auth_oauth_' . $actual_name . '_secret';
357 }
358
359 return $ret;
360 }
361
362 /**
363 * {@inheritdoc}
364 */
365 public function get_acp_template($new_config)
366 {
367 $ret = array(
368 'BLOCK_VAR_NAME' => 'oauth_services',
369 'BLOCK_VARS' => array(),
370 'TEMPLATE_FILE' => 'auth_provider_oauth.html',
371 'TEMPLATE_VARS' => array(),
372 );
373
374 foreach ($this->service_providers as $service_name => $service_provider)
375 {
376 $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name);
377 $ret['BLOCK_VARS'][$actual_name] = array(
378 'ACTUAL_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)],
379 'KEY' => $new_config['auth_oauth_' . $actual_name . '_key'],
380 'NAME' => $actual_name,
381 'SECRET' => $new_config['auth_oauth_' . $actual_name . '_secret'],
382 );
383 }
384
385 return $ret;
386 }
387
388 /**
389 * {@inheritdoc}
390 */
391 public function login_link_has_necessary_data($login_link_data)
392 {
393 if (empty($login_link_data))
394 {
395 return 'LOGIN_LINK_NO_DATA_PROVIDED';
396 }
397
398 if (!array_key_exists('oauth_service', $login_link_data) || !$login_link_data['oauth_service'] ||
399 !array_key_exists('link_method', $login_link_data) || !$login_link_data['link_method'])
400 {
401 return 'LOGIN_LINK_MISSING_DATA';
402 }
403
404 return null;
405 }
406
407 /**
408 * {@inheritdoc}
409 */
410 public function link_account(array $link_data)
411 {
412 // Check for a valid link method (auth_link or login_link)
413 if (!array_key_exists('link_method', $link_data) ||
414 !in_array($link_data['link_method'], array(
415 'auth_link',
416 'login_link',
417 )))
418 {
419 return 'LOGIN_LINK_MISSING_DATA';
420 }
421
422 // We must have an oauth_service listed, check for it two ways
423 if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service'])
424 {
425 $link_data['oauth_service'] = $this->request->variable('oauth_service', '');
426
427 if (!$link_data['oauth_service'])
428 {
429 return 'LOGIN_LINK_MISSING_DATA';
430 }
431 }
432
433 $service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']);
434 if (!array_key_exists($service_name, $this->service_providers))
435 {
436 return 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST';
437 }
438
439 switch ($link_data['link_method'])
440 {
441 case 'auth_link':
442 return $this->link_account_auth_link($link_data, $service_name);
443 case 'login_link':
444 return $this->link_account_login_link($link_data, $service_name);
445 }
446 }
447
448 /**
449 * Performs the account linking for login_link
450 *
451 * @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account}
452 * @param string $service_name The name of the service being used in
453 * linking.
454 * @return string|null Returns a language constant (string) if an error is
455 * encountered, or null on success.
456 */
457 protected function link_account_login_link(array $link_data, $service_name)
458 {
459 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
460
461 // Check for an access token, they should have one
462 if (!$storage->has_access_token_by_session($service_name))
463 {
464 return 'LOGIN_LINK_ERROR_OAUTH_NO_ACCESS_TOKEN';
465 }
466
467 // Prepare the query string
468 $query = 'mode=login_link&login_link_oauth_service=' . strtolower($link_data['oauth_service']);
469
470 // Prepare for an authentication request
471 $service_credentials = $this->service_providers[$service_name]->get_service_credentials();
472 $scopes = $this->service_providers[$service_name]->get_auth_scope();
473 $service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes);
474 $this->service_providers[$service_name]->set_external_service_provider($service);
475
476 // The user has already authenticated successfully, request to authenticate again
477 $unique_id = $this->service_providers[$service_name]->perform_token_auth();
478
479 // Insert into table, they will be able to log in after this
480 $data = array(
481 'user_id' => $link_data['user_id'],
482 'provider' => strtolower($link_data['oauth_service']),
483 'oauth_provider_id' => $unique_id,
484 );
485
486 $this->link_account_perform_link($data);
487 // Update token storage to store the user_id
488 $storage->set_user_id($link_data['user_id']);
489 }
490
491 /**
492 * Performs the account linking for auth_link
493 *
494 * @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account}
495 * @param string $service_name The name of the service being used in
496 * linking.
497 * @return string|null Returns a language constant (string) if an error is
498 * encountered, or null on success.
499 */
500 protected function link_account_auth_link(array $link_data, $service_name)
501 {
502 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
503 $query = 'i=ucp_auth_link&mode=auth_link&link=1&oauth_service=' . strtolower($link_data['oauth_service']);
504 $service_credentials = $this->service_providers[$service_name]->get_service_credentials();
505 $scopes = $this->service_providers[$service_name]->get_auth_scope();
506 $service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes);
507
508 if ($this->request->is_set('code', \phpbb\request\request_interface::GET))
509 {
510 $this->service_providers[$service_name]->set_external_service_provider($service);
511 $unique_id = $this->service_providers[$service_name]->perform_auth_login();
512
513 // Insert into table, they will be able to log in after this
514 $data = array(
515 'user_id' => $this->user->data['user_id'],
516 'provider' => strtolower($link_data['oauth_service']),
517 'oauth_provider_id' => $unique_id,
518 );
519
520 $this->link_account_perform_link($data);
521 }
522 else
523 {
524 $url = $service->getAuthorizationUri();
525 header('Location: ' . $url);
526 }
527 }
528
529 /**
530 * Performs the query that inserts an account link
531 *
532 * @param array $data This array is passed to db->sql_build_array
533 */
534 protected function link_account_perform_link(array $data)
535 {
536 $sql = 'INSERT INTO ' . $this->auth_provider_oauth_token_account_assoc . '
537 ' . $this->db->sql_build_array('INSERT', $data);
538 $this->db->sql_query($sql);
539 }
540
541 /**
542 * {@inheritdoc}
543 */
544 public function logout($data, $new_session)
545 {
546 // Clear all tokens belonging to the user
547 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
548 $storage->clearAllTokens();
549
550 return;
551 }
552
553 /**
554 * {@inheritdoc}
555 */
556 public function get_auth_link_data()
557 {
558 $block_vars = array();
559
560 // Get all external accounts tied to the current user
561 $data = array(
562 'user_id' => (int) $this->user->data['user_id'],
563 );
564 $sql = 'SELECT oauth_provider_id, provider FROM ' . $this->auth_provider_oauth_token_account_assoc . '
565 WHERE ' . $this->db->sql_build_array('SELECT', $data);
566 $result = $this->db->sql_query($sql);
567 $rows = $this->db->sql_fetchrowset($result);
568 $this->db->sql_freeresult($result);
569
570 $oauth_user_ids = array();
571
572 if ($rows !== false && sizeof($rows))
573 {
574 foreach ($rows as $row)
575 {
576 $oauth_user_ids[$row['provider']] = $row['oauth_provider_id'];
577 }
578 }
579 unset($rows);
580
581 foreach ($this->service_providers as $service_name => $service_provider)
582 {
583 // Only include data if the credentials are set
584 $credentials = $service_provider->get_service_credentials();
585 if ($credentials['key'] && $credentials['secret'])
586 {
587 $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name);
588
589 $block_vars[$service_name] = array(
590 'HIDDEN_FIELDS' => array(
591 'link' => (!isset($oauth_user_ids[$actual_name])),
592 'oauth_service' => $actual_name,
593 ),
594
595 'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)],
596 'UNIQUE_ID' => (isset($oauth_user_ids[$actual_name])) ? $oauth_user_ids[$actual_name] : null,
597 );
598 }
599 }
600
601 return array(
602 'BLOCK_VAR_NAME' => 'oauth',
603 'BLOCK_VARS' => $block_vars,
604
605 'TEMPLATE_FILE' => 'ucp_auth_link_oauth.html',
606 );
607 }
608
609 /**
610 * {@inheritdoc}
611 */
612 public function unlink_account(array $link_data)
613 {
614 if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service'])
615 {
616 return 'LOGIN_LINK_MISSING_DATA';
617 }
618
619 // Remove the link
620 $sql = 'DELETE FROM ' . $this->auth_provider_oauth_token_account_assoc . "
621 WHERE provider = '" . $this->db->sql_escape($link_data['oauth_service']) . "'
622 AND user_id = " . (int) $this->user->data['user_id'];
623 $this->db->sql_query($sql);
624
625 // Clear all tokens belonging to the user on this servce
626 $service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']);
627 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
628 $storage->clearToken($service_name);
629 }
630 }
631