diff --git a/modules/oauth/lib/OAuthStore.php b/modules/oauth/lib/OAuthStore.php index a3bc82f97887593a90fdcc3b70e3c1700f285d70..e1553425f701ed87dac0bb11922bf085500bf75d 100644 --- a/modules/oauth/lib/OAuthStore.php +++ b/modules/oauth/lib/OAuthStore.php @@ -11,170 +11,191 @@ require_once(dirname(dirname(__FILE__)) . '/libextinc/OAuth.php'); * @author Mark Dobrinic, <mdobrinic@cozmanova.com>, Cozmanova bv * @package SimpleSAMLphp */ -class sspmod_oauth_OAuthStore extends OAuthDataStore { - - private $store; - private $config; - private $defaultversion = '1.0'; - - protected $_store_tables = array( - 'consumers' => 'consumer = array with consumer attributes', - 'nonce' => 'nonce+consumer_key = -boolean-', - 'requesttorequest' => 'requestToken.key = array(version,callback,consumerKey,)', - 'authorized' => 'requestToken.key, verifier = array(authenticated-user-attributes)', - 'access' => 'accessToken.key+consumerKey = accesstoken', - 'request' => 'requestToken.key+consumerKey = requesttoken', - ); - - function __construct() { - $this->store = new sspmod_core_Storage_SQLPermanentStorage('oauth'); - $this->config = SimpleSAML_Configuration::getOptionalConfig('module_oauth.php'); +class sspmod_oauth_OAuthStore extends OAuthDataStore +{ + private $store; + private $config; + private $defaultversion = '1.0'; + + protected $_store_tables = array( + 'consumers' => 'consumer = array with consumer attributes', + 'nonce' => 'nonce+consumer_key = -boolean-', + 'requesttorequest' => 'requestToken.key = array(version,callback,consumerKey,)', + 'authorized' => 'requestToken.key, verifier = array(authenticated-user-attributes)', + 'access' => 'accessToken.key+consumerKey = accesstoken', + 'request' => 'requestToken.key+consumerKey = requesttoken', + ); + + public function __construct() + { + $this->store = new sspmod_core_Storage_SQLPermanentStorage('oauth'); + $this->config = SimpleSAML_Configuration::getOptionalConfig('module_oauth.php'); } - - + + /** * Attach the data to the token, and establish the Callback URL and verifier * @param $requestTokenKey RequestToken that was authorized * @param $data Data that is authorized and to be attached to the requestToken * @return array(string:url, string:verifier) ; empty verifier for 1.0-response */ - public function authorize($requestTokenKey, $data) { - $url = null; - - // See whether to remember values from the original requestToken request: - $request_attributes = $this->store->get('requesttorequest', $requestTokenKey, ''); // must be there .. - if ($request_attributes['value']) { - // establish callback to use - if ($request_attributes['value']['callback']) { - $url = $request_attributes['value']['callback']; - } - } - - - // Is there a callback registered? This is leading, even over a supplied oauth_callback-parameter - $oConsumer = $this->lookup_consumer($request_attributes['value']['consumerKey']); - - if ($oConsumer && ($oConsumer->callback_url)) $url = $oConsumer->callback_url; - - $verifier = SimpleSAML\Utils\Random::generateID(); - $url = \SimpleSAML\Utils\HTTP::addURLParameters($url, array("oauth_verifier"=>$verifier)); - - $this->store->set('authorized', $requestTokenKey, $verifier, $data, $this->config->getValue('requestTokenDuration', 60*30) ); - - return array($url, $verifier); - } - - /** - * Perform lookup whether a given token exists in the list of authorized tokens; if a verifier is - * passed as well, the verifier *must* match the verifier that was registered with the token<br/> - * Note that an accessToken should never be stored with a verifier - * @param $requestToken - * @param $verifier - * @return unknown_type - */ - public function isAuthorized($requestToken, $verifier='') { - SimpleSAML\Logger::info('OAuth isAuthorized(' . $requestToken . ')'); - return $this->store->exists('authorized', $requestToken, $verifier); - } - - public function getAuthorizedData($token, $verifier = '') { - SimpleSAML\Logger::info('OAuth getAuthorizedData(' . $token . ')'); - $data = $this->store->get('authorized', $token, $verifier); - return $data['value']; - } - - public function moveAuthorizedData($requestToken, $verifier, $accessTokenKey) { - SimpleSAML\Logger::info('OAuth moveAuthorizedData(' . $requestToken . ', ' . $accessTokenKey . ')'); - - // Retrieve authorizedData from authorized.requestToken (with provider verifier) - $authorizedData = $this->getAuthorizedData($requestToken, $verifier); - - // Remove the requesttoken+verifier from authorized store - $this->store->remove('authorized', $requestToken, $verifier); - - // Add accesstoken with authorizedData to authorized store (with empty verifier) - // accessTokenKey+consumer => accessToken is already registered in 'access'-table - $this->store->set('authorized', $accessTokenKey, '', $authorizedData, $this->config->getValue('accessTokenDuration', 60*60*24)); - } - - public function lookup_consumer($consumer_key) { - SimpleSAML\Logger::info('OAuth lookup_consumer(' . $consumer_key . ')'); - if (! $this->store->exists('consumers', $consumer_key, '')) return NULL; - $consumer = $this->store->get('consumers', $consumer_key, ''); - - $callback = NULL; - if ($consumer['value']['callback_url']) $callback = $consumer['value']['callback_url']; - - if ($consumer['value']['RSAcertificate']) { - return new OAuthConsumer($consumer['value']['key'], $consumer['value']['RSAcertificate'], $callback); - } else { - return new OAuthConsumer($consumer['value']['key'], $consumer['value']['secret'], $callback); - } + public function authorize($requestTokenKey, $data) + { + $url = null; + + // See whether to remember values from the original requestToken request: + $request_attributes = $this->store->get('requesttorequest', $requestTokenKey, ''); + // must be there .. + if ($request_attributes['value']) { + // establish callback to use + if ($request_attributes['value']['callback']) { + $url = $request_attributes['value']['callback']; + } + } + + + // Is there a callback registered? This is leading, even over a supplied oauth_callback-parameter + $oConsumer = $this->lookup_consumer($request_attributes['value']['consumerKey']); + + if ($oConsumer && ($oConsumer->callback_url)) { + $url = $oConsumer->callback_url; + } + + $verifier = SimpleSAML\Utils\Random::generateID(); + $url = \SimpleSAML\Utils\HTTP::addURLParameters($url, array("oauth_verifier"=>$verifier)); + + $this->store->set('authorized', $requestTokenKey, $verifier, $data, $this->config->getValue('requestTokenDuration', 60*30) ); + + return array($url, $verifier); } - function lookup_token($consumer, $tokenType = 'default', $token) { - SimpleSAML\Logger::info('OAuth lookup_token(' . $consumer->key . ', ' . $tokenType. ',' . $token . ')'); - $data = $this->store->get($tokenType, $token, $consumer->key); - if ($data == NULL) throw new Exception('Could not find token'); - return $data['value']; + /** + * Perform lookup whether a given token exists in the list of authorized tokens; if a verifier is + * passed as well, the verifier *must* match the verifier that was registered with the token<br/> + * Note that an accessToken should never be stored with a verifier + * @param $requestToken + * @param $verifier + * @return unknown_type + */ + public function isAuthorized($requestToken, $verifier = '') + { + SimpleSAML\Logger::info('OAuth isAuthorized(' . $requestToken . ')'); + return $this->store->exists('authorized', $requestToken, $verifier); } - function lookup_nonce($consumer, $token, $nonce, $timestamp) { - SimpleSAML\Logger::info('OAuth lookup_nonce(' . $consumer . ', ' . $token. ',' . $nonce . ')'); - if ($this->store->exists('nonce', $nonce, $consumer->key)) return TRUE; - $this->store->set('nonce', $nonce, $consumer->key, TRUE, $this->config->getValue('nonceCache', 60*60*24*14)); - return FALSE; + public function getAuthorizedData($token, $verifier = '') + { + SimpleSAML\Logger::info('OAuth getAuthorizedData(' . $token . ')'); + $data = $this->store->get('authorized', $token, $verifier); + return $data['value']; } - function new_request_token($consumer, $callback = null, $version = null) { - SimpleSAML\Logger::info('OAuth new_request_token(' . $consumer . ')'); - - $lifetime = $this->config->getValue('requestTokenDuration', 60*30); - - $token = new OAuthToken(SimpleSAML\Utils\Random::generateID(), SimpleSAML\Utils\Random::generateID()); - $token->callback = $callback; // OAuth1.0-RevA - $this->store->set('request', $token->key, $consumer->key, $token, $lifetime); - - // also store in requestToken->key => array('callback'=>CallbackURL, 'version'=>oauth_version - $request_attributes = array( - 'callback' => $callback, - 'version' => ($version?$version:$this->defaultversion), - 'consumerKey' => $consumer->key, - ); - $this->store->set('requesttorequest', $token->key, '', $request_attributes, $lifetime); - - // also store in requestToken->key => Consumer->key (enables consumer-lookup during reqToken-authorization stage) - $this->store->set('requesttoconsumer', $token->key, '', $consumer->key, $lifetime); - + public function moveAuthorizedData($requestToken, $verifier, $accessTokenKey) + { + SimpleSAML\Logger::info('OAuth moveAuthorizedData(' . $requestToken . ', ' . $accessTokenKey . ')'); + + // Retrieve authorizedData from authorized.requestToken (with provider verifier) + $authorizedData = $this->getAuthorizedData($requestToken, $verifier); + + // Remove the requesttoken+verifier from authorized store + $this->store->remove('authorized', $requestToken, $verifier); + + // Add accesstoken with authorizedData to authorized store (with empty verifier) + // accessTokenKey+consumer => accessToken is already registered in 'access'-table + $this->store->set('authorized', $accessTokenKey, '', $authorizedData, $this->config->getValue('accessTokenDuration', 60*60*24)); + } + + public function lookup_consumer($consumer_key) + { + SimpleSAML\Logger::info('OAuth lookup_consumer(' . $consumer_key . ')'); + if (!$this->store->exists('consumers', $consumer_key, '')) { + return null; + } + $consumer = $this->store->get('consumers', $consumer_key, ''); + + $callback = null; + if ($consumer['value']['callback_url']) { + $callback = $consumer['value']['callback_url']; + } + + if ($consumer['value']['RSAcertificate']) { + return new OAuthConsumer($consumer['value']['key'], $consumer['value']['RSAcertificate'], $callback); + } else { + return new OAuthConsumer($consumer['value']['key'], $consumer['value']['secret'], $callback); + } + } + + function lookup_token($consumer, $tokenType = 'default', $token) + { + SimpleSAML\Logger::info('OAuth lookup_token(' . $consumer->key . ', ' . $tokenType. ',' . $token . ')'); + $data = $this->store->get($tokenType, $token, $consumer->key); + if ($data == null) { + throw new Exception('Could not find token'); + } + return $data['value']; + } + + function lookup_nonce($consumer, $token, $nonce, $timestamp) + { + SimpleSAML\Logger::info('OAuth lookup_nonce(' . $consumer . ', ' . $token. ',' . $nonce . ')'); + if ($this->store->exists('nonce', $nonce, $consumer->key)) { + return true; + } + $this->store->set('nonce', $nonce, $consumer->key, TRUE, $this->config->getValue('nonceCache', 60*60*24*14)); + return false; + } + + function new_request_token($consumer, $callback = null, $version = null) + { + SimpleSAML\Logger::info('OAuth new_request_token(' . $consumer . ')'); + + $lifetime = $this->config->getValue('requestTokenDuration', 60*30); + + $token = new OAuthToken(SimpleSAML\Utils\Random::generateID(), SimpleSAML\Utils\Random::generateID()); + $token->callback = $callback; // OAuth1.0-RevA + $this->store->set('request', $token->key, $consumer->key, $token, $lifetime); + + // also store in requestToken->key => array('callback'=>CallbackURL, 'version'=>oauth_version + $request_attributes = array( + 'callback' => $callback, + 'version' => ($version?$version:$this->defaultversion), + 'consumerKey' => $consumer->key, + ); + $this->store->set('requesttorequest', $token->key, '', $request_attributes, $lifetime); + + // also store in requestToken->key => Consumer->key (enables consumer-lookup during reqToken-authorization stage) + $this->store->set('requesttoconsumer', $token->key, '', $consumer->key, $lifetime); + return $token; } - function new_access_token($requestToken, $consumer, $verifier = null) { - SimpleSAML\Logger::info('OAuth new_access_token(' . $requestToken . ',' . $consumer . ')'); - $accesstoken = new OAuthToken(SimpleSAML\Utils\Random::generateID(), SimpleSAML\Utils\Random::generateID()); - $this->store->set('access', $accesstoken->key, $consumer->key, $accesstoken, $this->config->getValue('accessTokenDuration', 60*60*24) ); + function new_access_token($requestToken, $consumer, $verifier = null) + { + SimpleSAML\Logger::info('OAuth new_access_token(' . $requestToken . ',' . $consumer . ')'); + $accesstoken = new OAuthToken(SimpleSAML\Utils\Random::generateID(), SimpleSAML\Utils\Random::generateID()); + $this->store->set('access', $accesstoken->key, $consumer->key, $accesstoken, $this->config->getValue('accessTokenDuration', 60*60*24) ); return $accesstoken; } - + /** * Return OAuthConsumer-instance that a given requestToken was issued to * @param $requestTokenKey * @return unknown_type */ - public function lookup_consumer_by_requestToken($requestTokenKey) { - SimpleSAML\Logger::info('OAuth lookup_consumer_by_requestToken(' . $requestTokenKey . ')'); - if (! $this->store->exists('requesttorequest', $requestTokenKey, '')) return NULL; - - $request = $this->store->get('requesttorequest', $requestTokenKey, ''); - $consumerKey = $request['value']['consumerKey']; - if (! $consumerKey) { - return NULL; - } - - $consumer = $this->store->get('consumers', $consumerKey['value'], ''); - return $consumer['value']; - } - - + public function lookup_consumer_by_requestToken($requestTokenKey) + { + SimpleSAML\Logger::info('OAuth lookup_consumer_by_requestToken(' . $requestTokenKey . ')'); + if (!$this->store->exists('requesttorequest', $requestTokenKey, '')) { + return null; + } + $request = $this->store->get('requesttorequest', $requestTokenKey, ''); + $consumerKey = $request['value']['consumerKey']; + if (!$consumerKey) { + return null; + } + + $consumer = $this->store->get('consumers', $consumerKey['value'], ''); + return $consumer['value']; + } }