[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 namespace phpbb\auth\provider\oauth; 15 16 use OAuth\Common\Consumer\Credentials; 17 18 /** 19 * OAuth authentication provider for phpBB3 20 */ 21 class oauth extends \phpbb\auth\provider\base 22 { 23 /** 24 * Database driver 25 * 26 * @var \phpbb\db\driver\driver_interface 27 */ 28 protected $db; 29 30 /** 31 * phpBB config 32 * 33 * @var \phpbb\config\config 34 */ 35 protected $config; 36 37 /** 38 * phpBB passwords manager 39 * 40 * @var \phpbb\passwords\manager 41 */ 42 protected $passwords_manager; 43 44 /** 45 * phpBB request object 46 * 47 * @var \phpbb\request\request_interface 48 */ 49 protected $request; 50 51 /** 52 * phpBB user 53 * 54 * @var \phpbb\user 55 */ 56 protected $user; 57 58 /** 59 * OAuth token table 60 * 61 * @var string 62 */ 63 protected $auth_provider_oauth_token_storage_table; 64 65 /** 66 * OAuth account association table 67 * 68 * @var string 69 */ 70 protected $auth_provider_oauth_token_account_assoc; 71 72 /** 73 * All OAuth service providers 74 * 75 * @var \phpbb\di\service_collection Contains \phpbb\auth\provider\oauth\service_interface 76 */ 77 protected $service_providers; 78 79 /** 80 * Users table 81 * 82 * @var string 83 */ 84 protected $users_table; 85 86 /** 87 * Cached current uri object 88 * 89 * @var \OAuth\Common\Http\Uri\UriInterface|null 90 */ 91 protected $current_uri; 92 93 /** 94 * DI container 95 * 96 * @var \Symfony\Component\DependencyInjection\ContainerInterface 97 */ 98 protected $phpbb_container; 99 100 /** 101 * phpBB event dispatcher 102 * 103 * @var \phpbb\event\dispatcher_interface 104 */ 105 protected $dispatcher; 106 107 /** 108 * phpBB root path 109 * 110 * @var string 111 */ 112 protected $phpbb_root_path; 113 114 /** 115 * PHP file extension 116 * 117 * @var string 118 */ 119 protected $php_ext; 120 121 /** 122 * OAuth Authentication Constructor 123 * 124 * @param \phpbb\db\driver\driver_interface $db 125 * @param \phpbb\config\config $config 126 * @param \phpbb\passwords\manager $passwords_manager 127 * @param \phpbb\request\request_interface $request 128 * @param \phpbb\user $user 129 * @param string $auth_provider_oauth_token_storage_table 130 * @param string $auth_provider_oauth_token_account_assoc 131 * @param \phpbb\di\service_collection $service_providers Contains \phpbb\auth\provider\oauth\service_interface 132 * @param string $users_table 133 * @param \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container 134 * @param \phpbb\event\dispatcher_interface $dispatcher phpBB event dispatcher 135 * @param string $phpbb_root_path 136 * @param string $php_ext 137 */ 138 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\event\dispatcher_interface $dispatcher, $phpbb_root_path, $php_ext) 139 { 140 $this->db = $db; 141 $this->config = $config; 142 $this->passwords_manager = $passwords_manager; 143 $this->request = $request; 144 $this->user = $user; 145 $this->auth_provider_oauth_token_storage_table = $auth_provider_oauth_token_storage_table; 146 $this->auth_provider_oauth_token_account_assoc = $auth_provider_oauth_token_account_assoc; 147 $this->service_providers = $service_providers; 148 $this->users_table = $users_table; 149 $this->phpbb_container = $phpbb_container; 150 $this->dispatcher = $dispatcher; 151 $this->phpbb_root_path = $phpbb_root_path; 152 $this->php_ext = $php_ext; 153 } 154 155 /** 156 * {@inheritdoc} 157 */ 158 public function init() 159 { 160 // This does not test whether or not the key and secret provided are valid. 161 foreach ($this->service_providers as $service_provider) 162 { 163 $credentials = $service_provider->get_service_credentials(); 164 165 if (($credentials['key'] && !$credentials['secret']) || (!$credentials['key'] && $credentials['secret'])) 166 { 167 return $this->user->lang['AUTH_PROVIDER_OAUTH_ERROR_ELEMENT_MISSING']; 168 } 169 } 170 return false; 171 } 172 173 /** 174 * {@inheritdoc} 175 */ 176 public function login($username, $password) 177 { 178 // Temporary workaround for only having one authentication provider available 179 if (!$this->request->is_set('oauth_service')) 180 { 181 $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); 182 return $provider->login($username, $password); 183 } 184 185 // Requst the name of the OAuth service 186 $service_name_original = $this->request->variable('oauth_service', '', false); 187 $service_name = 'auth.provider.oauth.service.' . strtolower($service_name_original); 188 if ($service_name_original === '' || !array_key_exists($service_name, $this->service_providers)) 189 { 190 return array( 191 'status' => LOGIN_ERROR_EXTERNAL_AUTH, 192 'error_msg' => 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST', 193 'user_row' => array('user_id' => ANONYMOUS), 194 ); 195 } 196 197 // Get the service credentials for the given service 198 $service_credentials = $this->service_providers[$service_name]->get_service_credentials(); 199 200 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); 201 $query = 'mode=login&login=external&oauth_service=' . $service_name_original; 202 $service = $this->get_service($service_name_original, $storage, $service_credentials, $query, $this->service_providers[$service_name]->get_auth_scope()); 203 204 if ($this->request->is_set('code', \phpbb\request\request_interface::GET)) 205 { 206 $this->service_providers[$service_name]->set_external_service_provider($service); 207 $unique_id = $this->service_providers[$service_name]->perform_auth_login(); 208 209 // Check to see if this provider is already assosciated with an account 210 $data = array( 211 'provider' => $service_name_original, 212 'oauth_provider_id' => $unique_id 213 ); 214 $sql = 'SELECT user_id FROM ' . $this->auth_provider_oauth_token_account_assoc . ' 215 WHERE ' . $this->db->sql_build_array('SELECT', $data); 216 $result = $this->db->sql_query($sql); 217 $row = $this->db->sql_fetchrow($result); 218 $this->db->sql_freeresult($result); 219 220 if (!$row) 221 { 222 // The user does not yet exist, ask to link or create profile 223 return array( 224 'status' => LOGIN_SUCCESS_LINK_PROFILE, 225 'error_msg' => 'LOGIN_OAUTH_ACCOUNT_NOT_LINKED', 226 'user_row' => array(), 227 'redirect_data' => array( 228 'auth_provider' => 'oauth', 229 'login_link_oauth_service' => $service_name_original, 230 ), 231 ); 232 } 233 234 // Retrieve the user's account 235 $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts 236 FROM ' . $this->users_table . ' 237 WHERE user_id = ' . (int) $row['user_id']; 238 $result = $this->db->sql_query($sql); 239 $row = $this->db->sql_fetchrow($result); 240 $this->db->sql_freeresult($result); 241 242 if (!$row) 243 { 244 throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY'); 245 } 246 247 // Update token storage to store the user_id 248 $storage->set_user_id($row['user_id']); 249 250 /** 251 * Event is triggered after user is successfuly logged in via OAuth. 252 * 253 * @event core.auth_oauth_login_after 254 * @var array row User row 255 * @since 3.1.11-RC1 256 */ 257 $vars = array( 258 'row', 259 ); 260 extract($this->dispatcher->trigger_event('core.auth_oauth_login_after', compact($vars))); 261 262 // The user is now authenticated and can be logged in 263 return array( 264 'status' => LOGIN_SUCCESS, 265 'error_msg' => false, 266 'user_row' => $row, 267 ); 268 } 269 else 270 { 271 $url = $service->getAuthorizationUri(); 272 header('Location: ' . $url); 273 } 274 } 275 276 /** 277 * Returns the cached current_uri object or creates and caches it if it is 278 * not already created. In each case the query string is updated based on 279 * the $query parameter. 280 * 281 * @param string $service_name The name of the service 282 * @param string $query The query string of the current_uri 283 * used in redirects 284 * @return \OAuth\Common\Http\Uri\UriInterface 285 */ 286 protected function get_current_uri($service_name, $query) 287 { 288 if ($this->current_uri) 289 { 290 $this->current_uri->setQuery($query); 291 return $this->current_uri; 292 } 293 294 $uri_factory = new \OAuth\Common\Http\Uri\UriFactory(); 295 $super_globals = $this->request->get_super_global(\phpbb\request\request_interface::SERVER); 296 if (!empty($super_globals['HTTP_X_FORWARDED_PROTO']) && $super_globals['HTTP_X_FORWARDED_PROTO'] === 'https') 297 { 298 $super_globals['HTTPS'] = 'on'; 299 $super_globals['SERVER_PORT'] = 443; 300 } 301 $current_uri = $uri_factory->createFromSuperGlobalArray($super_globals); 302 $current_uri->setQuery($query); 303 304 $this->current_uri = $current_uri; 305 return $current_uri; 306 } 307 308 /** 309 * Returns a new service object 310 * 311 * @param string $service_name The name of the service 312 * @param \phpbb\auth\provider\oauth\token_storage $storage 313 * @param array $service_credentials {@see \phpbb\auth\provider\oauth\oauth::get_service_credentials} 314 * @param string $query The query string of the 315 * current_uri used in redirection 316 * @param array $scopes The scope of the request against 317 * the api. 318 * @return \OAuth\Common\Service\ServiceInterface 319 * @throws \Exception 320 */ 321 protected function get_service($service_name, \phpbb\auth\provider\oauth\token_storage $storage, array $service_credentials, $query, array $scopes = array()) 322 { 323 $current_uri = $this->get_current_uri($service_name, $query); 324 325 // Setup the credentials for the requests 326 $credentials = new Credentials( 327 $service_credentials['key'], 328 $service_credentials['secret'], 329 $current_uri->getAbsoluteUri() 330 ); 331 332 $service_factory = new \OAuth\ServiceFactory(); 333 $service = $service_factory->createService($service_name, $credentials, $storage, $scopes); 334 335 if (!$service) 336 { 337 throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_SERVICE_NOT_CREATED'); 338 } 339 340 return $service; 341 } 342 343 /** 344 * {@inheritdoc} 345 */ 346 public function get_login_data() 347 { 348 $login_data = array( 349 'TEMPLATE_FILE' => 'login_body_oauth.html', 350 'BLOCK_VAR_NAME' => 'oauth', 351 'BLOCK_VARS' => array(), 352 ); 353 354 foreach ($this->service_providers as $service_name => $service_provider) 355 { 356 // Only include data if the credentials are set 357 $credentials = $service_provider->get_service_credentials(); 358 if ($credentials['key'] && $credentials['secret']) 359 { 360 $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); 361 $redirect_url = build_url(false) . '&login=external&oauth_service=' . $actual_name; 362 $login_data['BLOCK_VARS'][$service_name] = array( 363 'REDIRECT_URL' => redirect($redirect_url, true), 364 'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)], 365 ); 366 } 367 } 368 369 return $login_data; 370 } 371 372 /** 373 * {@inheritdoc} 374 */ 375 public function acp() 376 { 377 $ret = array(); 378 379 foreach ($this->service_providers as $service_name => $service_provider) 380 { 381 $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); 382 $ret[] = 'auth_oauth_' . $actual_name . '_key'; 383 $ret[] = 'auth_oauth_' . $actual_name . '_secret'; 384 } 385 386 return $ret; 387 } 388 389 /** 390 * {@inheritdoc} 391 */ 392 public function get_acp_template($new_config) 393 { 394 $ret = array( 395 'BLOCK_VAR_NAME' => 'oauth_services', 396 'BLOCK_VARS' => array(), 397 'TEMPLATE_FILE' => 'auth_provider_oauth.html', 398 'TEMPLATE_VARS' => array(), 399 ); 400 401 foreach ($this->service_providers as $service_name => $service_provider) 402 { 403 $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); 404 $ret['BLOCK_VARS'][$actual_name] = array( 405 'ACTUAL_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)], 406 'KEY' => $new_config['auth_oauth_' . $actual_name . '_key'], 407 'NAME' => $actual_name, 408 'SECRET' => $new_config['auth_oauth_' . $actual_name . '_secret'], 409 ); 410 } 411 412 return $ret; 413 } 414 415 /** 416 * {@inheritdoc} 417 */ 418 public function login_link_has_necessary_data($login_link_data) 419 { 420 if (empty($login_link_data)) 421 { 422 return 'LOGIN_LINK_NO_DATA_PROVIDED'; 423 } 424 425 if (!array_key_exists('oauth_service', $login_link_data) || !$login_link_data['oauth_service'] || 426 !array_key_exists('link_method', $login_link_data) || !$login_link_data['link_method']) 427 { 428 return 'LOGIN_LINK_MISSING_DATA'; 429 } 430 431 return null; 432 } 433 434 /** 435 * {@inheritdoc} 436 */ 437 public function link_account(array $link_data) 438 { 439 // Check for a valid link method (auth_link or login_link) 440 if (!array_key_exists('link_method', $link_data) || 441 !in_array($link_data['link_method'], array( 442 'auth_link', 443 'login_link', 444 ))) 445 { 446 return 'LOGIN_LINK_MISSING_DATA'; 447 } 448 449 // We must have an oauth_service listed, check for it two ways 450 if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service']) 451 { 452 $link_data['oauth_service'] = $this->request->variable('oauth_service', ''); 453 454 if (!$link_data['oauth_service']) 455 { 456 return 'LOGIN_LINK_MISSING_DATA'; 457 } 458 } 459 460 $service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']); 461 if (!array_key_exists($service_name, $this->service_providers)) 462 { 463 return 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST'; 464 } 465 466 switch ($link_data['link_method']) 467 { 468 case 'auth_link': 469 return $this->link_account_auth_link($link_data, $service_name); 470 case 'login_link': 471 return $this->link_account_login_link($link_data, $service_name); 472 } 473 } 474 475 /** 476 * Performs the account linking for login_link 477 * 478 * @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account} 479 * @param string $service_name The name of the service being used in 480 * linking. 481 * @return string|null Returns a language constant (string) if an error is 482 * encountered, or null on success. 483 */ 484 protected function link_account_login_link(array $link_data, $service_name) 485 { 486 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); 487 488 // Check for an access token, they should have one 489 if (!$storage->has_access_token_by_session($service_name)) 490 { 491 return 'LOGIN_LINK_ERROR_OAUTH_NO_ACCESS_TOKEN'; 492 } 493 494 // Prepare the query string 495 $query = 'mode=login_link&login_link_oauth_service=' . strtolower($link_data['oauth_service']); 496 497 // Prepare for an authentication request 498 $service_credentials = $this->service_providers[$service_name]->get_service_credentials(); 499 $scopes = $this->service_providers[$service_name]->get_auth_scope(); 500 $service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes); 501 $this->service_providers[$service_name]->set_external_service_provider($service); 502 503 // The user has already authenticated successfully, request to authenticate again 504 $unique_id = $this->service_providers[$service_name]->perform_token_auth(); 505 506 // Insert into table, they will be able to log in after this 507 $data = array( 508 'user_id' => $link_data['user_id'], 509 'provider' => strtolower($link_data['oauth_service']), 510 'oauth_provider_id' => $unique_id, 511 ); 512 513 $this->link_account_perform_link($data); 514 // Update token storage to store the user_id 515 $storage->set_user_id($link_data['user_id']); 516 } 517 518 /** 519 * Performs the account linking for auth_link 520 * 521 * @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account} 522 * @param string $service_name The name of the service being used in 523 * linking. 524 * @return string|null Returns a language constant (string) if an error is 525 * encountered, or null on success. 526 */ 527 protected function link_account_auth_link(array $link_data, $service_name) 528 { 529 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); 530 $query = 'i=ucp_auth_link&mode=auth_link&link=1&oauth_service=' . strtolower($link_data['oauth_service']); 531 $service_credentials = $this->service_providers[$service_name]->get_service_credentials(); 532 $scopes = $this->service_providers[$service_name]->get_auth_scope(); 533 $service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes); 534 535 if ($this->request->is_set('code', \phpbb\request\request_interface::GET)) 536 { 537 $this->service_providers[$service_name]->set_external_service_provider($service); 538 $unique_id = $this->service_providers[$service_name]->perform_auth_login(); 539 540 // Insert into table, they will be able to log in after this 541 $data = array( 542 'user_id' => $this->user->data['user_id'], 543 'provider' => strtolower($link_data['oauth_service']), 544 'oauth_provider_id' => $unique_id, 545 ); 546 547 $this->link_account_perform_link($data); 548 } 549 else 550 { 551 $url = $service->getAuthorizationUri(); 552 header('Location: ' . $url); 553 } 554 } 555 556 /** 557 * Performs the query that inserts an account link 558 * 559 * @param array $data This array is passed to db->sql_build_array 560 */ 561 protected function link_account_perform_link(array $data) 562 { 563 $sql = 'INSERT INTO ' . $this->auth_provider_oauth_token_account_assoc . ' 564 ' . $this->db->sql_build_array('INSERT', $data); 565 $this->db->sql_query($sql); 566 567 /** 568 * Event is triggered after user links account. 569 * 570 * @event core.auth_oauth_link_after 571 * @var array data User row 572 * @since 3.1.11-RC1 573 */ 574 $vars = array( 575 'data', 576 ); 577 extract($this->dispatcher->trigger_event('core.auth_oauth_link_after', compact($vars))); 578 } 579 580 /** 581 * {@inheritdoc} 582 */ 583 public function logout($data, $new_session) 584 { 585 // Clear all tokens belonging to the user 586 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); 587 $storage->clearAllTokens(); 588 589 return; 590 } 591 592 /** 593 * {@inheritdoc} 594 */ 595 public function get_auth_link_data($user_id = 0) 596 { 597 $block_vars = array(); 598 599 // Get all external accounts tied to the current user 600 $data = array( 601 'user_id' => ($user_id <= 0) ? (int) $this->user->data['user_id'] : (int) $user_id, 602 ); 603 $sql = 'SELECT oauth_provider_id, provider FROM ' . $this->auth_provider_oauth_token_account_assoc . ' 604 WHERE ' . $this->db->sql_build_array('SELECT', $data); 605 $result = $this->db->sql_query($sql); 606 $rows = $this->db->sql_fetchrowset($result); 607 $this->db->sql_freeresult($result); 608 609 $oauth_user_ids = array(); 610 611 if ($rows !== false && sizeof($rows)) 612 { 613 foreach ($rows as $row) 614 { 615 $oauth_user_ids[$row['provider']] = $row['oauth_provider_id']; 616 } 617 } 618 unset($rows); 619 620 foreach ($this->service_providers as $service_name => $service_provider) 621 { 622 // Only include data if the credentials are set 623 $credentials = $service_provider->get_service_credentials(); 624 if ($credentials['key'] && $credentials['secret']) 625 { 626 $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); 627 628 $block_vars[$service_name] = array( 629 'HIDDEN_FIELDS' => array( 630 'link' => (!isset($oauth_user_ids[$actual_name])), 631 'oauth_service' => $actual_name, 632 ), 633 634 'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)], 635 'UNIQUE_ID' => (isset($oauth_user_ids[$actual_name])) ? $oauth_user_ids[$actual_name] : null, 636 ); 637 } 638 } 639 640 return array( 641 'BLOCK_VAR_NAME' => 'oauth', 642 'BLOCK_VARS' => $block_vars, 643 644 'TEMPLATE_FILE' => 'ucp_auth_link_oauth.html', 645 ); 646 } 647 648 /** 649 * {@inheritdoc} 650 */ 651 public function unlink_account(array $link_data) 652 { 653 if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service']) 654 { 655 return 'LOGIN_LINK_MISSING_DATA'; 656 } 657 658 // Remove user specified in $link_data if possible 659 $user_id = isset($link_data['user_id']) ? $link_data['user_id'] : $this->user->data['user_id']; 660 661 // Remove the link 662 $sql = 'DELETE FROM ' . $this->auth_provider_oauth_token_account_assoc . " 663 WHERE provider = '" . $this->db->sql_escape($link_data['oauth_service']) . "' 664 AND user_id = " . (int) $user_id; 665 $this->db->sql_query($sql); 666 667 // Clear all tokens belonging to the user on this servce 668 $service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']); 669 $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); 670 $storage->clearToken($service_name); 671 } 672 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |