diff options
| author | Maat <maat-pub@mageia.biz> | 2020-05-08 21:52:11 +0200 | 
|---|---|---|
| committer | Maat <maat-pub@mageia.biz> | 2020-05-08 21:52:11 +0200 | 
| commit | 8ea437e30605e0f66b5220bf904a61d7c1d11ddd (patch) | |
| tree | e0db2bb4a012d5b06a633160b19f62f4868ecd28 /phpBB/phpbb/auth | |
| parent | 36bc1870f21fac04736a1049c1d5b8e127d729f4 (diff) | |
| parent | 2fdd46b36431ae0f58bb2e78e42553168db9a0ff (diff) | |
| download | forums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.tar forums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.tar.gz forums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.tar.bz2 forums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.tar.xz forums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.zip  | |
Merge remote-tracking branch 'upstream/prep-release-3.2.9'
Diffstat (limited to 'phpBB/phpbb/auth')
| -rw-r--r-- | phpBB/phpbb/auth/auth.php | 11 | ||||
| -rw-r--r-- | phpBB/phpbb/auth/provider/db.php | 1 | ||||
| -rw-r--r-- | phpBB/phpbb/auth/provider/ldap.php | 4 | ||||
| -rw-r--r-- | phpBB/phpbb/auth/provider/oauth/oauth.php | 141 | ||||
| -rw-r--r-- | phpBB/phpbb/auth/provider/oauth/service/twitter.php | 102 | ||||
| -rw-r--r-- | phpBB/phpbb/auth/provider/oauth/token_storage.php | 254 | ||||
| -rw-r--r-- | phpBB/phpbb/auth/provider/provider_interface.php | 7 | 
7 files changed, 474 insertions, 46 deletions
diff --git a/phpBB/phpbb/auth/auth.php b/phpBB/phpbb/auth/auth.php index 37d4352c10..f46a21a8ae 100644 --- a/phpBB/phpbb/auth/auth.php +++ b/phpBB/phpbb/auth/auth.php @@ -72,8 +72,8 @@ class auth  		// Verify bitstring length with options provided...  		$renew = false; -		$global_length = sizeof($this->acl_options['global']); -		$local_length = sizeof($this->acl_options['local']); +		$global_length = count($this->acl_options['global']); +		$local_length = count($this->acl_options['local']);  		// Specify comparing length (bitstring is padded to 31 bits)  		$global_length = ($global_length % 31) ? ($global_length - ($global_length % 31) + 31) : $global_length; @@ -236,7 +236,7 @@ class auth  				$sql = 'SELECT forum_id  					FROM ' . FORUMS_TABLE; -				if (sizeof($this->acl)) +				if (count($this->acl))  				{  					$sql .= ' WHERE ' . $db->sql_in_set('forum_id', array_keys($this->acl), true);  				} @@ -278,7 +278,7 @@ class auth  		}  		// If we get forum_ids not having this permission, we need to fill the remaining parts -		if ($negate && sizeof($this->acl_forum_ids)) +		if ($negate && count($this->acl_forum_ids))  		{  			foreach ($this->acl_forum_ids as $f)  			{ @@ -455,7 +455,7 @@ class auth  	{  		$hold_str = ''; -		if (sizeof($hold_ary)) +		if (count($hold_ary))  		{  			ksort($hold_ary); @@ -940,6 +940,7 @@ class auth  		global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;  		global $phpbb_dispatcher; +		/* @var $provider_collection \phpbb\auth\provider_collection */  		$provider_collection = $phpbb_container->get('auth.provider_collection');  		$provider = $provider_collection->get_provider(); diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php index d8c5fb72de..1adf85ee05 100644 --- a/phpBB/phpbb/auth/provider/db.php +++ b/phpBB/phpbb/auth/provider/db.php @@ -155,6 +155,7 @@ class db extends \phpbb\auth\provider\base  		// Every auth module is able to define what to do by itself...  		if ($show_captcha)  		{ +			/* @var $captcha_factory \phpbb\captcha\factory */  			$captcha_factory = $this->phpbb_container->get('captcha.factory');  			$captcha = $captcha_factory->get_instance($this->config['captcha_plugin']);  			$captcha->init(CONFIRM_LOGIN); diff --git a/phpBB/phpbb/auth/provider/ldap.php b/phpBB/phpbb/auth/provider/ldap.php index c48b771ab0..0789a6234d 100644 --- a/phpBB/phpbb/auth/provider/ldap.php +++ b/phpBB/phpbb/auth/provider/ldap.php @@ -99,7 +99,7 @@ class ldap extends \phpbb\auth\provider\base  		@ldap_close($ldap); -		if (!is_array($result) || sizeof($result) < 2) +		if (!is_array($result) || count($result) < 2)  		{  			return sprintf($this->user->lang['LDAP_NO_IDENTITY'], $this->user->data['username']);  		} @@ -192,7 +192,7 @@ class ldap extends \phpbb\auth\provider\base  		$ldap_result = @ldap_get_entries($ldap, $search); -		if (is_array($ldap_result) && sizeof($ldap_result) > 1) +		if (is_array($ldap_result) && count($ldap_result) > 1)  		{  			if (@ldap_bind($ldap, $ldap_result[0]['dn'], htmlspecialchars_decode($password)))  			{ diff --git a/phpBB/phpbb/auth/provider/oauth/oauth.php b/phpBB/phpbb/auth/provider/oauth/oauth.php index bd2a414033..e3f8394bba 100644 --- a/phpBB/phpbb/auth/provider/oauth/oauth.php +++ b/phpBB/phpbb/auth/provider/oauth/oauth.php @@ -63,6 +63,13 @@ class oauth extends \phpbb\auth\provider\base  	protected $auth_provider_oauth_token_storage_table;  	/** +	* OAuth state table +	* +	* @var string +	*/ +	protected $auth_provider_oauth_state_table; + +	/**  	* OAuth account association table  	*  	* @var string @@ -127,6 +134,7 @@ class oauth extends \phpbb\auth\provider\base  	* @param	\phpbb\request\request_interface	$request  	* @param	\phpbb\user		$user  	* @param	string			$auth_provider_oauth_token_storage_table +	* @param	string			$auth_provider_oauth_state_table  	* @param	string			$auth_provider_oauth_token_account_assoc  	* @param	\phpbb\di\service_collection	$service_providers Contains \phpbb\auth\provider\oauth\service_interface  	* @param	string			$users_table @@ -135,7 +143,7 @@ class oauth extends \phpbb\auth\provider\base  	* @param	string			$phpbb_root_path  	* @param	string			$php_ext  	*/ -	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) +	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_state_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)  	{  		$this->db = $db;  		$this->config = $config; @@ -143,6 +151,7 @@ class oauth extends \phpbb\auth\provider\base  		$this->request = $request;  		$this->user = $user;  		$this->auth_provider_oauth_token_storage_table = $auth_provider_oauth_token_storage_table; +		$this->auth_provider_oauth_state_table = $auth_provider_oauth_state_table;  		$this->auth_provider_oauth_token_account_assoc = $auth_provider_oauth_token_account_assoc;  		$this->service_providers = $service_providers;  		$this->users_table = $users_table; @@ -182,7 +191,7 @@ class oauth extends \phpbb\auth\provider\base  			return $provider->login($username, $password);  		} -		// Requst the name of the OAuth service +		// Request the name of the OAuth service  		$service_name_original = $this->request->variable('oauth_service', '', false);  		$service_name = 'auth.provider.oauth.service.' . strtolower($service_name_original);  		if ($service_name_original === '' || !array_key_exists($service_name, $this->service_providers)) @@ -197,26 +206,57 @@ class oauth extends \phpbb\auth\provider\base  		// Get the service credentials for the given service  		$service_credentials = $this->service_providers[$service_name]->get_service_credentials(); -		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); +		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);  		$query = 'mode=login&login=external&oauth_service=' . $service_name_original;  		$service = $this->get_service($service_name_original, $storage, $service_credentials, $query, $this->service_providers[$service_name]->get_auth_scope()); -		if ($this->request->is_set('code', \phpbb\request\request_interface::GET)) +		if (($service::OAUTH_VERSION === 2 && $this->request->is_set('code', \phpbb\request\request_interface::GET)) +			|| ($service::OAUTH_VERSION === 1 && $this->request->is_set('oauth_token', \phpbb\request\request_interface::GET)))  		{  			$this->service_providers[$service_name]->set_external_service_provider($service);  			$unique_id = $this->service_providers[$service_name]->perform_auth_login(); -			// Check to see if this provider is already assosciated with an account +			/** +			 * Check to see if this provider is already associated with an account. +			 * +			 * Enforcing a data type to make data contains strings and not integers, +			 * so values are quoted in the SQL WHERE statement. +			 */  			$data = array( -				'provider'	=> $service_name_original, -				'oauth_provider_id'	=> $unique_id +				'provider'			=> (string) $service_name_original, +				'oauth_provider_id'	=> (string) $unique_id  			); +  			$sql = 'SELECT user_id FROM ' . $this->auth_provider_oauth_token_account_assoc . '  				WHERE ' . $this->db->sql_build_array('SELECT', $data);  			$result = $this->db->sql_query($sql);  			$row = $this->db->sql_fetchrow($result);  			$this->db->sql_freeresult($result); +			$redirect_data = array( +				'auth_provider'				=> 'oauth', +				'login_link_oauth_service'	=> $service_name_original, +			); + +			/** +			* Event is triggered before check if provider is already associated with an account +			* +			* @event core.oauth_login_after_check_if_provider_id_has_match +			* @var	array									row				User row +			* @var	array									data			Provider data +			* @var	array									redirect_data	Data to be appended to the redirect url +			* @var	\OAuth\Common\Service\ServiceInterface	service			OAuth service +			* @since 3.2.3-RC1 +			* @changed 3.2.6-RC1 Added redirect_data +			*/ +			$vars = array( +				'row', +				'data', +				'redirect_data', +				'service', +			); +			extract($this->dispatcher->trigger_event('core.oauth_login_after_check_if_provider_id_has_match', compact($vars))); +  			if (!$row)  			{  				// The user does not yet exist, ask to link or create profile @@ -224,15 +264,12 @@ class oauth extends \phpbb\auth\provider\base  					'status'		=> LOGIN_SUCCESS_LINK_PROFILE,  					'error_msg'		=> 'LOGIN_OAUTH_ACCOUNT_NOT_LINKED',  					'user_row'		=> array(), -					'redirect_data'	=> array( -						'auth_provider'				=> 'oauth', -						'login_link_oauth_service'	=> $service_name_original, -					), +					'redirect_data'	=> $redirect_data,  				);  			}  			// Retrieve the user's account -			$sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts +			$sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_ip, user_type, user_login_attempts  				FROM ' . $this->users_table . '  					WHERE user_id = ' . (int) $row['user_id'];  			$result = $this->db->sql_query($sql); @@ -244,11 +281,36 @@ class oauth extends \phpbb\auth\provider\base  				throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY');  			} +			/** +			 * Check if the user is banned. +			 * The fourth parameter, return, has to be true, +			 * otherwise the OAuth login is still called and +			 * an uncaught exception is thrown as there is no +			 * token stored in the database. +			 */ +			$ban = $this->user->check_ban($row['user_id'], $row['user_ip'], $row['user_email'], true); +			if (!empty($ban)) +			{ +				$till_date = !empty($ban['ban_end']) ? $this->user->format_date($ban['ban_end']) : ''; +				$message = !empty($ban['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM'; + +				$contact_link = phpbb_get_board_contact_link($this->config, $this->phpbb_root_path, $this->php_ext); +				$message = $this->user->lang($message, $till_date, '<a href="' . $contact_link . '">', '</a>'); +				$message .= !empty($ban['ban_give_reason']) ? '<br /><br />' . $this->user->lang('BOARD_BAN_REASON', $ban['ban_give_reason']) : ''; +				$message .= !empty($ban['ban_triggered_by']) ? '<br /><br /><em>' . $this->user->lang('BAN_TRIGGERED_BY_' . strtoupper($ban['ban_triggered_by'])) . '</em>' : ''; + +				return array( +					'status'	=> LOGIN_BREAK, +					'error_msg'	=> $message, +					'user_row'	=> $row, +				); +			} +  			// Update token storage to store the user_id  			$storage->set_user_id($row['user_id']);  			/** -			* Event is triggered after user is successfuly logged in via OAuth. +			* Event is triggered after user is successfully logged in via OAuth.  			*  			* @event core.auth_oauth_login_after  			* @var    array    row    User row @@ -268,7 +330,15 @@ class oauth extends \phpbb\auth\provider\base  		}  		else  		{ -			$url = $service->getAuthorizationUri(); +			if ($service::OAUTH_VERSION === 1) +			{ +				$token = $service->requestRequestToken(); +				$url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken())); +			} +			else +			{ +				$url = $service->getAuthorizationUri(); +			}  			header('Location: ' . $url);  		}  	} @@ -358,7 +428,7 @@ class oauth extends \phpbb\auth\provider\base  			if ($credentials['key'] && $credentials['secret'])  			{  				$actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); -				$redirect_url = build_url(false) . '&login=external&oauth_service=' . $actual_name; +				$redirect_url = generate_board_url() . '/ucp.' . $this->php_ext . '?mode=login&login=external&oauth_service=' . $actual_name;  				$login_data['BLOCK_VARS'][$service_name] = array(  					'REDIRECT_URL'	=> redirect($redirect_url, true),  					'SERVICE_NAME'	=> $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)], @@ -483,7 +553,7 @@ class oauth extends \phpbb\auth\provider\base  	*/  	protected function link_account_login_link(array $link_data, $service_name)  	{ -		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); +		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);  		// Check for an access token, they should have one  		if (!$storage->has_access_token_by_session($service_name)) @@ -526,13 +596,14 @@ class oauth extends \phpbb\auth\provider\base  	*/  	protected function link_account_auth_link(array $link_data, $service_name)  	{ -		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); +		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);  		$query = 'i=ucp_auth_link&mode=auth_link&link=1&oauth_service=' . strtolower($link_data['oauth_service']);  		$service_credentials = $this->service_providers[$service_name]->get_service_credentials();  		$scopes = $this->service_providers[$service_name]->get_auth_scope();  		$service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes); -		if ($this->request->is_set('code', \phpbb\request\request_interface::GET)) +		if (($service::OAUTH_VERSION === 2 && $this->request->is_set('code', \phpbb\request\request_interface::GET)) +			|| ($service::OAUTH_VERSION === 1 && $this->request->is_set('oauth_token', \phpbb\request\request_interface::GET)))  		{  			$this->service_providers[$service_name]->set_external_service_provider($service);  			$unique_id = $this->service_providers[$service_name]->perform_auth_login(); @@ -548,7 +619,15 @@ class oauth extends \phpbb\auth\provider\base  		}  		else  		{ -			$url = $service->getAuthorizationUri(); +			if ($service::OAUTH_VERSION === 1) +			{ +				$token = $service->requestRequestToken(); +				$url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken())); +			} +			else +			{ +				$url = $service->getAuthorizationUri(); +			}  			header('Location: ' . $url);  		}  	} @@ -560,6 +639,21 @@ class oauth extends \phpbb\auth\provider\base  	*/  	protected function link_account_perform_link(array $data)  	{ +		// Check if the external account is already associated with other user +		$sql = 'SELECT user_id +			FROM ' . $this->auth_provider_oauth_token_account_assoc . " +			WHERE provider = '" . $this->db->sql_escape($data['provider']) . "' +				AND oauth_provider_id = '" . $this->db->sql_escape($data['oauth_provider_id']) . "'"; +		$result = $this->db->sql_query($sql); +		$row = $this->db->sql_fetchrow($result); +		$this->db->sql_freeresult($result); + +		if ($row) +		{ +			trigger_error('AUTH_PROVIDER_OAUTH_ERROR_ALREADY_LINKED'); +		} + +		// Link account  		$sql = 'INSERT INTO ' . $this->auth_provider_oauth_token_account_assoc . '  			' . $this->db->sql_build_array('INSERT', $data);  		$this->db->sql_query($sql); @@ -583,7 +677,7 @@ class oauth extends \phpbb\auth\provider\base  	public function logout($data, $new_session)  	{  		// Clear all tokens belonging to the user -		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); +		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);  		$storage->clearAllTokens();  		return; @@ -608,7 +702,7 @@ class oauth extends \phpbb\auth\provider\base  		$oauth_user_ids = array(); -		if ($rows !== false && sizeof($rows)) +		if ($rows !== false && count($rows))  		{  			foreach ($rows as $row)  			{ @@ -631,6 +725,7 @@ class oauth extends \phpbb\auth\provider\base  						'oauth_service' => $actual_name,  					), +					'SERVICE_ID'	=> $actual_name,  					'SERVICE_NAME'	=> $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)],  					'UNIQUE_ID'		=> (isset($oauth_user_ids[$actual_name])) ? $oauth_user_ids[$actual_name] : null,  				); @@ -664,9 +759,9 @@ class oauth extends \phpbb\auth\provider\base  				AND user_id = " . (int) $user_id;  		$this->db->sql_query($sql); -		// Clear all tokens belonging to the user on this servce +		// Clear all tokens belonging to the user on this service  		$service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']); -		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table); +		$storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);  		$storage->clearToken($service_name);  	}  } diff --git a/phpBB/phpbb/auth/provider/oauth/service/twitter.php b/phpBB/phpbb/auth/provider/oauth/service/twitter.php new file mode 100644 index 0000000000..06beac51e2 --- /dev/null +++ b/phpBB/phpbb/auth/provider/oauth/service/twitter.php @@ -0,0 +1,102 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\auth\provider\oauth\service; + +/** +* Twitter OAuth service +*/ +class twitter extends \phpbb\auth\provider\oauth\service\base +{ +	/** +	* phpBB config +	* +	* @var \phpbb\config\config +	*/ +	protected $config; + +	/** +	* phpBB request +	* +	* @var \phpbb\request\request_interface +	*/ +	protected $request; + +	/** +	* Constructor +	* +	* @param	\phpbb\config\config				$config +	* @param	\phpbb\request\request_interface	$request +	*/ +	public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request) +	{ +		$this->config = $config; +		$this->request = $request; +	} + +	/** +	* {@inheritdoc} +	*/ +	public function get_service_credentials() +	{ +		return array( +			'key'		=> $this->config['auth_oauth_twitter_key'], +			'secret'	=> $this->config['auth_oauth_twitter_secret'], +		); +	} + +	/** +	* {@inheritdoc} +	*/ +	public function perform_auth_login() +	{ +		if (!($this->service_provider instanceof \OAuth\OAuth1\Service\Twitter)) +		{ +			throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); +		} + +		$storage = $this->service_provider->getStorage(); +		$token = $storage->retrieveAccessToken('Twitter'); +		$tokensecret = $token->getRequestTokenSecret(); + +		// This was a callback request from twitter, get the token +		$this->service_provider->requestAccessToken( +			$this->request->variable('oauth_token', ''), +			$this->request->variable('oauth_verifier', ''), +			$tokensecret +		); + +		// Send a request with it +		$result = json_decode($this->service_provider->request('account/verify_credentials.json'), true); + +		// Return the unique identifier returned from twitter +		return $result['id']; +	} + +	/** +	* {@inheritdoc} +	*/ +	public function perform_token_auth() +	{ +		if (!($this->service_provider instanceof \OAuth\OAuth1\Service\Twitter)) +		{ +			throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); +		} + +		// Send a request with it +		$result = json_decode($this->service_provider->request('account/verify_credentials.json'), true); + +		// Return the unique identifier returned from twitter +		return $result['id']; +	} +} diff --git a/phpBB/phpbb/auth/provider/oauth/token_storage.php b/phpBB/phpbb/auth/provider/oauth/token_storage.php index 9b6afae255..b0c2fd0d62 100644 --- a/phpBB/phpbb/auth/provider/oauth/token_storage.php +++ b/phpBB/phpbb/auth/provider/oauth/token_storage.php @@ -17,6 +17,7 @@ use OAuth\OAuth1\Token\StdOAuth1Token;  use OAuth\Common\Token\TokenInterface;  use OAuth\Common\Storage\TokenStorageInterface;  use OAuth\Common\Storage\Exception\TokenNotFoundException; +use OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException;  /**  * OAuth storage wrapper for phpbb's cache @@ -42,7 +43,14 @@ class token_storage implements TokenStorageInterface  	*  	* @var string  	*/ -	protected $auth_provider_oauth_table; +	protected $oauth_token_table; + +	/** +	* OAuth state table +	* +	* @var string +	*/ +	protected $oauth_state_table;  	/**  	* @var object|TokenInterface @@ -50,17 +58,24 @@ class token_storage implements TokenStorageInterface  	protected $cachedToken;  	/** +	* @var string +	*/ +	protected $cachedState; + +	/**  	* Creates token storage for phpBB.  	*  	* @param	\phpbb\db\driver\driver_interface	$db  	* @param	\phpbb\user		$user -	* @param	string			$auth_provider_oauth_table +	* @param	string			$oauth_token_table +	* @param	string			$oauth_state_table  	*/ -	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $auth_provider_oauth_table) +	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $oauth_token_table, $oauth_state_table)  	{  		$this->db = $db;  		$this->user = $user; -		$this->auth_provider_oauth_table = $auth_provider_oauth_table; +		$this->oauth_token_table = $oauth_token_table; +		$this->oauth_state_table = $oauth_state_table;  	}  	/** @@ -98,15 +113,31 @@ class token_storage implements TokenStorageInterface  		$this->cachedToken = $token;  		$data = array( -			'user_id'		=> (int) $this->user->data['user_id'], -			'provider'		=> $service,  			'oauth_token'	=> $this->json_encode_token($token), -			'session_id'	=> $this->user->data['session_id'],  		); -		$sql = 'INSERT INTO ' . $this->auth_provider_oauth_table . ' -			' . $this->db->sql_build_array('INSERT', $data); +		$sql = 'UPDATE ' . $this->oauth_token_table . ' +				SET ' . $this->db->sql_build_array('UPDATE', $data) . ' +				WHERE user_id = ' . (int) $this->user->data['user_id'] . ' +					' . ((int) $this->user->data['user_id'] === ANONYMOUS ? "AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'" : '') . " +					AND provider = '" . $this->db->sql_escape($service) . "'";  		$this->db->sql_query($sql); + +		if (!$this->db->sql_affectedrows()) +		{ +			$data = array( +				'user_id'		=> (int) $this->user->data['user_id'], +				'provider'		=> $service, +				'oauth_token'	=> $this->json_encode_token($token), +				'session_id'	=> $this->user->data['session_id'], +			); + +			$sql = 'INSERT INTO ' . $this->oauth_token_table . $this->db->sql_build_array('INSERT', $data); + +			$this->db->sql_query($sql); +		} + +		return $this;  	}  	/** @@ -143,7 +174,7 @@ class token_storage implements TokenStorageInterface  		$this->cachedToken = null; -		$sql = 'DELETE FROM ' . $this->auth_provider_oauth_table . ' +		$sql = 'DELETE FROM ' . $this->oauth_token_table . '  			WHERE user_id = ' . (int) $this->user->data['user_id'] . "  				AND provider = '" . $this->db->sql_escape($service) . "'"; @@ -153,6 +184,8 @@ class token_storage implements TokenStorageInterface  		}  		$this->db->sql_query($sql); + +		return $this;  	}  	/** @@ -162,7 +195,7 @@ class token_storage implements TokenStorageInterface  	{  		$this->cachedToken = null; -		$sql = 'DELETE FROM ' . $this->auth_provider_oauth_table . ' +		$sql = 'DELETE FROM ' . $this->oauth_token_table . '  			WHERE user_id = ' . (int) $this->user->data['user_id'];  		if ((int) $this->user->data['user_id'] === ANONYMOUS) @@ -171,6 +204,124 @@ class token_storage implements TokenStorageInterface  		}  		$this->db->sql_query($sql); + +		return $this; +	} + +	/** +	* {@inheritdoc} +	*/ +	public function storeAuthorizationState($service, $state) +	{ +		$service = $this->get_service_name_for_db($service); + +		$this->cachedState = $state; + +		$data = array( +			'user_id'		=> (int) $this->user->data['user_id'], +			'provider'		=> $service, +			'oauth_state'	=> $state, +			'session_id'	=> $this->user->data['session_id'], +		); + +		$sql = 'INSERT INTO ' . $this->oauth_state_table . ' +			' . $this->db->sql_build_array('INSERT', $data); +		$this->db->sql_query($sql); + +		return $this; +	} + +	/** +	* {@inheritdoc} +	*/ +	public function hasAuthorizationState($service) +	{ +		$service = $this->get_service_name_for_db($service); + +		if ($this->cachedState) +		{ +			return true; +		} + +		$data = array( +			'user_id'	=> (int) $this->user->data['user_id'], +			'provider'	=> $service, +		); + +		if ((int) $this->user->data['user_id'] === ANONYMOUS) +		{ +			$data['session_id']	= $this->user->data['session_id']; +		} + +		return (bool) $this->get_state_row($data); +	} + +	/** +	* {@inheritdoc} +	*/ +	public function retrieveAuthorizationState($service) +	{ +		$service = $this->get_service_name_for_db($service); + +		if ($this->cachedState) +		{ +			return $this->cachedState; +		} + +		$data = array( +			'user_id'	=> (int) $this->user->data['user_id'], +			'provider'	=> $service, +		); + +		if ((int) $this->user->data['user_id'] === ANONYMOUS) +		{ +			$data['session_id']	= $this->user->data['session_id']; +		} + +		return $this->get_state_row($data); +	} + +	/** +	* {@inheritdoc} +	*/ +	public function clearAuthorizationState($service) +	{ +		$service = $this->get_service_name_for_db($service); + +		$this->cachedState = null; + +		$sql = 'DELETE FROM ' . $this->oauth_state_table . ' +			WHERE user_id = ' . (int) $this->user->data['user_id'] . " +				AND provider = '" . $this->db->sql_escape($service) . "'"; + +		if ((int) $this->user->data['user_id'] === ANONYMOUS) +		{ +			$sql .= " AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'"; +		} + +		$this->db->sql_query($sql); + +		return $this; +	} + +	/** +	* {@inheritdoc} +	*/ +	public function clearAllAuthorizationStates() +	{ +		$this->cachedState = null; + +		$sql = 'DELETE FROM ' . $this->oauth_state_table . ' +			WHERE user_id = ' . (int) $this->user->data['user_id']; + +		if ((int) $this->user->data['user_id'] === ANONYMOUS) +		{ +			$sql .= " AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'"; +		} + +		$this->db->sql_query($sql); + +		return $this;  	}  	/** @@ -185,7 +336,7 @@ class token_storage implements TokenStorageInterface  			return;  		} -		$sql = 'UPDATE ' . $this->auth_provider_oauth_table . ' +		$sql = 'UPDATE ' . $this->oauth_token_table . '  			SET ' . $this->db->sql_build_array('UPDATE', array(  					'user_id' => (int) $user_id  				)) . ' @@ -218,6 +369,29 @@ class token_storage implements TokenStorageInterface  	}  	/** +	* Checks to see if a state exists solely by the session_id of the user +	* +	* @param	string	$service	The name of the OAuth service +	* @return	bool	true if they have state, false if they don't +	*/ +	public function has_state_by_session($service) +	{ +		$service = $this->get_service_name_for_db($service); + +		if ($this->cachedState) +		{ +			return true; +		} + +		$data = array( +			'session_id'	=> $this->user->data['session_id'], +			'provider'		=> $service, +		); + +		return (bool) $this->get_state_row($data); +	} + +	/**  	* A helper function that performs the query for has access token functions  	*  	* @param	array	$data @@ -245,6 +419,23 @@ class token_storage implements TokenStorageInterface  		return $this->_retrieve_access_token($data);  	} +	public function retrieve_state_by_session($service) +	{ +		$service = $this->get_service_name_for_db($service); + +		if ($this->cachedState) +		{ +			return $this->cachedState; +		} + +		$data = array( +			'session_id'	=> $this->user->data['session_id'], +			'provider'	=> $service, +		); + +		return $this->_retrieve_state($data); +	} +  	/**  	* A helper function that performs the query for retrieve access token functions  	* Also checks if the token is a valid token @@ -276,6 +467,26 @@ class token_storage implements TokenStorageInterface  	}  	/** +	 * A helper function that performs the query for retrieve state functions +	 * +	 * @param	array	$data +	 * @return	mixed +	 * @throws \OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException +	 */ +	protected function _retrieve_state($data) +	{ +		$row = $this->get_state_row($data); + +		if (!$row) +		{ +			throw new AuthorizationStateNotFoundException(); +		} + +		$this->cachedState = $row['oauth_state']; +		return $this->cachedState; +	} + +	/**  	* A helper function that performs the query for retrieving an access token  	*  	* @param	array	$data @@ -283,7 +494,24 @@ class token_storage implements TokenStorageInterface  	*/  	protected function get_access_token_row($data)  	{ -		$sql = 'SELECT oauth_token FROM ' . $this->auth_provider_oauth_table . ' +		$sql = 'SELECT oauth_token FROM ' . $this->oauth_token_table . ' +			WHERE ' . $this->db->sql_build_array('SELECT', $data); +		$result = $this->db->sql_query($sql); +		$row = $this->db->sql_fetchrow($result); +		$this->db->sql_freeresult($result); + +		return $row; +	} + +	/** +	 * A helper function that performs the query for retrieving a state +	 * +	 * @param	array	$data +	 * @return	mixed +	 */ +	protected function get_state_row($data) +	{ +		$sql = 'SELECT oauth_state FROM ' . $this->oauth_state_table . '  			WHERE ' . $this->db->sql_build_array('SELECT', $data);  		$result = $this->db->sql_query($sql);  		$row = $this->db->sql_fetchrow($result); diff --git a/phpBB/phpbb/auth/provider/provider_interface.php b/phpBB/phpbb/auth/provider/provider_interface.php index 35e0f559a1..463324ff46 100644 --- a/phpBB/phpbb/auth/provider/provider_interface.php +++ b/phpBB/phpbb/auth/provider/provider_interface.php @@ -71,9 +71,10 @@ interface provider_interface  	 * options with whatever configuraton values are passed to it as an array.  	 * It then returns the name of the acp file related to this authentication  	 * provider. -	 * @param	array	$new_config Contains the new configuration values that -	 *								have been set in acp_board. -	 * @return	array|null		Returns null if not implemented or an array with +	 * +	 * @param \phpbb\config\config	$new_config	Contains the new configuration values +	 * 											that have been set in acp_board. +	 * @return array|null		Returns null if not implemented or an array with  	 *							the template file name and an array of the vars  	 *							that the template needs that must conform to the  	 *							following example:  | 
