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