From fdc66742dae79c787408fb4bb070fae13abd9122 Mon Sep 17 00:00:00 2001 From: Andjelko Horvat <comel@vingd.com> Date: Wed, 4 Jan 2012 12:30:54 +0000 Subject: [PATCH] authfacebook: update base_facebook.php to 3.1.1. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@3006 44740490-163a-0410-bde0-09ae8108e29a --- .../authfacebook/extlibinc/base_facebook.php | 86 ++++++++++++++++--- .../authfacebook/lib/Auth/Source/Facebook.php | 4 +- modules/authfacebook/lib/Facebook.php | 2 +- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/modules/authfacebook/extlibinc/base_facebook.php b/modules/authfacebook/extlibinc/base_facebook.php index 0805c153c..fcf3bff1e 100644 --- a/modules/authfacebook/extlibinc/base_facebook.php +++ b/modules/authfacebook/extlibinc/base_facebook.php @@ -110,7 +110,7 @@ class FacebookApiException extends Exception * Provides access to the Facebook Platform. This class provides * a majority of the functionality needed, but the class is abstract * because it is designed to be sub-classed. The subclass must - * implement the three abstract methods listed at the bottom of + * implement the four abstract methods listed at the bottom of * the file. * * @author Naitik Shah <naitik@facebook.com> @@ -120,7 +120,7 @@ abstract class BaseFacebook /** * Version. */ - const VERSION = '3.0.1'; + const VERSION = '3.1.1'; /** * Default options for curl. @@ -129,7 +129,7 @@ abstract class BaseFacebook CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 60, - CURLOPT_USERAGENT => 'facebook-php-3.0', + CURLOPT_USERAGENT => 'facebook-php-3.1', ); /** @@ -314,7 +314,8 @@ abstract class BaseFacebook // access token, in case we navigate to the /oauth/access_token // endpoint, where SOME access token is required. $this->setAccessToken($this->getApplicationAccessToken()); - if ($user_access_token = $this->getUserAccessToken()) { + $user_access_token = $this->getUserAccessToken(); + if ($user_access_token) { $this->setAccessToken($user_access_token); } @@ -337,12 +338,24 @@ abstract class BaseFacebook // the access token. $signed_request = $this->getSignedRequest(); if ($signed_request) { + // apps.facebook.com hands the access_token in the signed_request if (array_key_exists('oauth_token', $signed_request)) { $access_token = $signed_request['oauth_token']; $this->setPersistentData('access_token', $access_token); return $access_token; } + // the JS SDK puts a code in with the redirect_uri of '' + if (array_key_exists('code', $signed_request)) { + $code = $signed_request['code']; + $access_token = $this->getAccessTokenFromCode($code, ''); + if ($access_token) { + $this->setPersistentData('code', $code); + $this->setPersistentData('access_token', $access_token); + return $access_token; + } + } + // signed request states there's no access token, so anything // stored should be cleared. $this->clearAllPersistentData(); @@ -372,15 +385,19 @@ abstract class BaseFacebook } /** - * Get the data from a signed_request token. + * Retrieve the signed request, either from a request parameter or, + * if not present, from a cookie. * - * @return string The base domain + * @return string the signed request, if available, or null otherwise. */ public function getSignedRequest() { if (!$this->signedRequest) { if (isset($_REQUEST['signed_request'])) { $this->signedRequest = $this->parseSignedRequest( $_REQUEST['signed_request']); + } else if (isset($_COOKIE[$this->getSignedRequestCookieName()])) { + $this->signedRequest = $this->parseSignedRequest( + $_COOKIE[$this->getSignedRequestCookieName()]); } } return $this->signedRequest; @@ -461,6 +478,13 @@ abstract class BaseFacebook public function getLoginUrl($params=array()) { $this->establishCSRFTokenState(); $currentUrl = $this->getCurrentUrl(); + + // if 'scope' is passed as an array, convert to comma separated list + $scopeParams = isset($params['scope']) ? $params['scope'] : null; + if ($scopeParams && is_array($scopeParams)) { + $params['scope'] = implode(',', $scopeParams); + } + return $this->getUrl( 'www', 'dialog/oauth', @@ -530,6 +554,19 @@ abstract class BaseFacebook } } + /** + * Constructs and returns the name of the cookie that + * potentially houses the signed request for the app user. + * The cookie is not set by the BaseFacebook class, but + * it may be set by the JavaScript SDK. + * + * @return string the name of the cookie that would house + * the signed request value. + */ + protected function getSignedRequestCookieName() { + return 'fbsr_'.$this->getAppId(); + } + /** * Get the authorization code from the query parameters, if it exists, * and otherwise return false to signal no authorization code was @@ -611,11 +648,15 @@ abstract class BaseFacebook * @return mixed An access token exchanged for the authorization code, or * false if an access token could not be generated. */ - protected function getAccessTokenFromCode($code) { + protected function getAccessTokenFromCode($code, $redirect_uri = null) { if (empty($code)) { return false; } + if ($redirect_uri === null) { + $redirect_uri = $this->getCurrentUrl(); + } + try { // need to circumvent json_decode by calling _oauthRequest // directly, since response isn't JSON format. @@ -624,7 +665,7 @@ abstract class BaseFacebook $this->getUrl('graph', '/oauth/access_token'), $params = array('client_id' => $this->getAppId(), 'client_secret' => $this->getApiSecret(), - 'redirect_uri' => $this->getCurrentUrl(), + 'redirect_uri' => $redirect_uri, 'code' => $code)); } catch (FacebookApiException $e) { // most likely that user very recently revoked authorization. @@ -665,7 +706,12 @@ abstract class BaseFacebook // results are returned, errors are thrown if (is_array($result) && isset($result['error_code'])) { - throw new FacebookApiException($result); + $this->throwAPIException($result); + } + + if ($params['method'] === 'auth.expireSession' || + $params['method'] === 'auth.revokeAuthorization') { + $this->destroySession(); } return $result; @@ -922,9 +968,14 @@ abstract class BaseFacebook * @return string The current URL */ protected function getCurrentUrl() { - $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' - ? 'https://' - : 'http://'; + if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) + || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' + ) { + $protocol = 'https://'; + } + else { + $protocol = 'http://'; + } $currentUrl = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; $parts = parse_url($currentUrl); @@ -991,6 +1042,8 @@ abstract class BaseFacebook case 'OAuthException': // OAuth 2.0 Draft 10 style case 'invalid_token': + // REST server errors are just Exceptions + case 'Exception': $message = $e->getMessage(); if ((strpos($message, 'Error validating access token') !== false) || (strpos($message, 'Invalid OAuth access token') !== false)) { @@ -1033,6 +1086,15 @@ abstract class BaseFacebook return base64_decode(strtr($input, '-_', '+/')); } + /** + * Destroy the current session + */ + public function destroySession() { + $this->setAccessToken(null); + $this->user = 0; + $this->clearAllPersistentData(); + } + /** * Each of the following four methods should be overridden in * a concrete subclass, as they are in the provided Facebook class. diff --git a/modules/authfacebook/lib/Auth/Source/Facebook.php b/modules/authfacebook/lib/Auth/Source/Facebook.php index 3c9655ef2..642db0bea 100644 --- a/modules/authfacebook/lib/Auth/Source/Facebook.php +++ b/modules/authfacebook/lib/Auth/Source/Facebook.php @@ -74,7 +74,7 @@ class sspmod_authfacebook_Auth_Source_Facebook extends SimpleSAML_Auth_Source { $stateID = SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT); $facebook = new sspmod_authfacebook_Facebook(array('appId' => $this->api_key, 'secret' => $this->secret), $state); - $facebook->clearAllPersistentData(); + $facebook->destroySession(); $linkback = SimpleSAML_Module::getModuleURL('authfacebook/linkback.php', array('AuthState' => $stateID)); $url = $facebook->getLoginUrl(array('redirect_uri' => $linkback, 'scope' => $this->req_perms)); @@ -122,7 +122,7 @@ class sspmod_authfacebook_Auth_Source_Facebook extends SimpleSAML_Auth_Source { $state['Attributes'] = $attributes; - $facebook->clearAllPersistentData(); + $facebook->destroySession(); } } diff --git a/modules/authfacebook/lib/Facebook.php b/modules/authfacebook/lib/Facebook.php index d31e90f29..7fc2ba502 100644 --- a/modules/authfacebook/lib/Facebook.php +++ b/modules/authfacebook/lib/Facebook.php @@ -71,7 +71,7 @@ class sspmod_authfacebook_Facebook extends BaseFacebook } } - public function clearAllPersistentData() { + protected function clearAllPersistentData() { foreach (self::$kSupportedKeys as $key) { $this->clearPersistentData($key); } -- GitLab