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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

oauth.php

Zuletzt modifiziert: 09.10.2024, 12:55 - Dateigröße: 18.85 KiB


 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