Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
41.67% |
10 / 24 |
CRAP | |
55.36% |
129 / 233 |
| token_storage | |
0.00% |
0 / 1 |
|
41.67% |
10 / 24 |
272.32 | |
55.36% |
129 / 233 |
| __construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
| retrieveAccessToken | |
100.00% |
1 / 1 |
3 | |
100.00% |
12 / 12 |
|||
| storeAccessToken | |
100.00% |
1 / 1 |
3 | |
100.00% |
21 / 21 |
|||
| hasAccessToken | |
100.00% |
1 / 1 |
3 | |
100.00% |
12 / 12 |
|||
| clearToken | |
100.00% |
1 / 1 |
2 | |
100.00% |
11 / 11 |
|||
| clearAllTokens | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 9 |
|||
| storeAuthorizationState | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 11 |
|||
| hasAuthorizationState | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 12 |
|||
| retrieveAuthorizationState | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 12 |
|||
| clearAuthorizationState | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 11 |
|||
| clearAllAuthorizationStates | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 9 |
|||
| set_user_id | |
0.00% |
0 / 1 |
2.00 | |
90.00% |
9 / 10 |
|||
| has_access_token_by_session | |
100.00% |
1 / 1 |
2 | |
100.00% |
8 / 8 |
|||
| has_state_by_session | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 8 |
|||
| _has_acess_token | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| retrieve_access_token_by_session | |
100.00% |
1 / 1 |
2 | |
100.00% |
8 / 8 |
|||
| retrieve_state_by_session | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 8 |
|||
| _retrieve_access_token | |
100.00% |
1 / 1 |
3 | |
100.00% |
11 / 11 |
|||
| _retrieve_state | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 6 |
|||
| get_access_token_row | |
100.00% |
1 / 1 |
1 | |
100.00% |
6 / 6 |
|||
| get_state_row | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 6 |
|||
| json_encode_token | |
0.00% |
0 / 1 |
2.12 | |
69.23% |
9 / 13 |
|||
| json_decode_token | |
0.00% |
0 / 1 |
3.19 | |
72.22% |
13 / 18 |
|||
| get_service_name_for_db | |
0.00% |
0 / 1 |
2.26 | |
60.00% |
3 / 5 |
|||
| <?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; | |
| 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 | |
| */ | |
| class token_storage implements TokenStorageInterface | |
| { | |
| /** | |
| * Cache driver. | |
| * | |
| * @var \phpbb\db\driver\driver_interface | |
| */ | |
| protected $db; | |
| /** | |
| * phpBB user | |
| * | |
| * @var \phpbb\user | |
| */ | |
| protected $user; | |
| /** | |
| * OAuth token table | |
| * | |
| * @var string | |
| */ | |
| protected $oauth_token_table; | |
| /** | |
| * OAuth state table | |
| * | |
| * @var string | |
| */ | |
| protected $oauth_state_table; | |
| /** | |
| * @var object|TokenInterface | |
| */ | |
| protected $cachedToken; | |
| /** | |
| * @var string | |
| */ | |
| protected $cachedState; | |
| /** | |
| * Creates token storage for phpBB. | |
| * | |
| * @param \phpbb\db\driver\driver_interface $db | |
| * @param \phpbb\user $user | |
| * @param string $oauth_token_table | |
| * @param string $oauth_state_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->oauth_token_table = $oauth_token_table; | |
| $this->oauth_state_table = $oauth_state_table; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function retrieveAccessToken($service) | |
| { | |
| $service = $this->get_service_name_for_db($service); | |
| if ($this->cachedToken instanceof TokenInterface) | |
| { | |
| return $this->cachedToken; | |
| } | |
| $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->_retrieve_access_token($data); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function storeAccessToken($service, TokenInterface $token) | |
| { | |
| $service = $this->get_service_name_for_db($service); | |
| $this->cachedToken = $token; | |
| $data = array( | |
| 'oauth_token' => $this->json_encode_token($token), | |
| ); | |
| $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; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function hasAccessToken($service) | |
| { | |
| $service = $this->get_service_name_for_db($service); | |
| if ($this->cachedToken) | |
| { | |
| 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 $this->_has_acess_token($data); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function clearToken($service) | |
| { | |
| $service = $this->get_service_name_for_db($service); | |
| $this->cachedToken = null; | |
| $sql = 'DELETE FROM ' . $this->oauth_token_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 clearAllTokens() | |
| { | |
| $this->cachedToken = null; | |
| $sql = 'DELETE FROM ' . $this->oauth_token_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; | |
| } | |
| /** | |
| * {@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; | |
| } | |
| /** | |
| * Updates the user_id field in the database assosciated with the token | |
| * | |
| * @param int $user_id | |
| */ | |
| public function set_user_id($user_id) | |
| { | |
| if (!$this->cachedToken) | |
| { | |
| return; | |
| } | |
| $sql = 'UPDATE ' . $this->oauth_token_table . ' | |
| SET ' . $this->db->sql_build_array('UPDATE', array( | |
| 'user_id' => (int) $user_id | |
| )) . ' | |
| WHERE user_id = ' . (int) $this->user->data['user_id'] . " | |
| AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'"; | |
| $this->db->sql_query($sql); | |
| } | |
| /** | |
| * Checks to see if an access token exists solely by the session_id of the user | |
| * | |
| * @param string $service The name of the OAuth service | |
| * @return bool true if they have token, false if they don't | |
| */ | |
| public function has_access_token_by_session($service) | |
| { | |
| $service = $this->get_service_name_for_db($service); | |
| if ($this->cachedToken) | |
| { | |
| return true; | |
| } | |
| $data = array( | |
| 'session_id' => $this->user->data['session_id'], | |
| 'provider' => $service, | |
| ); | |
| return $this->_has_acess_token($data); | |
| } | |
| /** | |
| * 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 | |
| * @return bool | |
| */ | |
| protected function _has_acess_token($data) | |
| { | |
| return (bool) $this->get_access_token_row($data); | |
| } | |
| public function retrieve_access_token_by_session($service) | |
| { | |
| $service = $this->get_service_name_for_db($service); | |
| if ($this->cachedToken instanceof TokenInterface) | |
| { | |
| return $this->cachedToken; | |
| } | |
| $data = array( | |
| 'session_id' => $this->user->data['session_id'], | |
| 'provider' => $service, | |
| ); | |
| 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 | |
| * | |
| * @param array $data | |
| * @return mixed | |
| * @throws \OAuth\Common\Storage\Exception\TokenNotFoundException | |
| */ | |
| protected function _retrieve_access_token($data) | |
| { | |
| $row = $this->get_access_token_row($data); | |
| if (!$row) | |
| { | |
| throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_NOT_STORED'); | |
| } | |
| $token = $this->json_decode_token($row['oauth_token']); | |
| // Ensure that the token was serialized/unserialized correctly | |
| if (!($token instanceof TokenInterface)) | |
| { | |
| $this->clearToken($data['provider']); | |
| throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED'); | |
| } | |
| $this->cachedToken = $token; | |
| return $token; | |
| } | |
| /** | |
| * 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 | |
| * @return mixed | |
| */ | |
| protected function get_access_token_row($data) | |
| { | |
| $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); | |
| $this->db->sql_freeresult($result); | |
| return $row; | |
| } | |
| public function json_encode_token(TokenInterface $token) | |
| { | |
| $members = array( | |
| 'accessToken' => $token->getAccessToken(), | |
| 'endOfLife' => $token->getEndOfLife(), | |
| 'extraParams' => $token->getExtraParams(), | |
| 'refreshToken' => $token->getRefreshToken(), | |
| 'token_class' => get_class($token), | |
| ); | |
| // Handle additional data needed for OAuth1 tokens | |
| if ($token instanceof StdOAuth1Token) | |
| { | |
| $members['requestToken'] = $token->getRequestToken(); | |
| $members['requestTokenSecret'] = $token->getRequestTokenSecret(); | |
| $members['accessTokenSecret'] = $token->getAccessTokenSecret(); | |
| } | |
| return json_encode($members); | |
| } | |
| public function json_decode_token($json) | |
| { | |
| $token_data = json_decode($json, true); | |
| if ($token_data === null) | |
| { | |
| throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED'); | |
| } | |
| $token_class = $token_data['token_class']; | |
| $access_token = $token_data['accessToken']; | |
| $refresh_token = $token_data['refreshToken']; | |
| $endOfLife = $token_data['endOfLife']; | |
| $extra_params = $token_data['extraParams']; | |
| // Create the token | |
| $token = new $token_class($access_token, $refresh_token, TokenInterface::EOL_NEVER_EXPIRES, $extra_params); | |
| $token->setEndOfLife($endOfLife); | |
| // Handle OAuth 1.0 specific elements | |
| if ($token instanceof StdOAuth1Token) | |
| { | |
| $token->setRequestToken($token_data['requestToken']); | |
| $token->setRequestTokenSecret($token_data['requestTokenSecret']); | |
| $token->setAccessTokenSecret($token_data['accessTokenSecret']); | |
| } | |
| return $token; | |
| } | |
| /** | |
| * Returns the name of the service as it must be stored in the database. | |
| * | |
| * @param string $service The name of the OAuth service | |
| * @return string The name of the OAuth service as it needs to be stored | |
| * in the database. | |
| */ | |
| protected function get_service_name_for_db($service) | |
| { | |
| // Enforce the naming convention for oauth services | |
| if (strpos($service, 'auth.provider.oauth.service.') !== 0) | |
| { | |
| $service = 'auth.provider.oauth.service.' . strtolower($service); | |
| } | |
| return $service; | |
| } | |
| } |