diff --git a/e107_handlers/hybridauth/Hybrid/Auth.php b/e107_handlers/hybridauth/Hybrid/Auth.php index 27db93cd7..b62238694 100644 --- a/e107_handlers/hybridauth/Hybrid/Auth.php +++ b/e107_handlers/hybridauth/Hybrid/Auth.php @@ -1,8 +1,8 @@ get($key) to retrieves the data for the given key, or calling * Hybrid_Auth::storage()->set($key, $value) to store the key => $value set. */ @@ -249,7 +252,7 @@ class Hybrid_Auth if( ! $params ){ $params = Hybrid_Auth::storage()->get( "hauth_session.$providerId.id_provider_params" ); - Hybrid_Logger::debug( "Hybrid_Auth::setup( $providerId ), no params given. Trying to get the sotred for this provider.", $params ); + Hybrid_Logger::debug( "Hybrid_Auth::setup( $providerId ), no params given. Trying to get the stored for this provider.", $params ); } if( ! $params ){ @@ -258,11 +261,11 @@ class Hybrid_Auth Hybrid_Logger::info( "Hybrid_Auth::setup( $providerId ), no stored params found for this provider. Initialize a new one for new session" ); } - if( ! isset( $params["hauth_return_to"] ) ){ + if( is_array($params) && ! isset( $params["hauth_return_to"] ) ){ $params["hauth_return_to"] = Hybrid_Auth::getCurrentUrl(); - } - Hybrid_Logger::debug( "Hybrid_Auth::setup( $providerId ). HybridAuth Callback URL set to: ", $params["hauth_return_to"] ); + Hybrid_Logger::debug( "Hybrid_Auth::setup( $providerId ). HybridAuth Callback URL set to: ", $params["hauth_return_to"] ); + } # instantiate a new IDProvider Adapter $provider = new Hybrid_Provider_Adapter(); @@ -385,14 +388,6 @@ class Hybrid_Auth $url = $protocol . $_SERVER['HTTP_HOST']; - // use port if non default - if( isset( $_SERVER['SERVER_PORT'] ) && strpos( $url, ':'.$_SERVER['SERVER_PORT'] ) === FALSE ) { - $url .= ($protocol === 'http://' && $_SERVER['SERVER_PORT'] != 80 && !isset( $_SERVER['HTTP_X_FORWARDED_PROTO'])) - || ($protocol === 'https://' && $_SERVER['SERVER_PORT'] != 443 && !isset( $_SERVER['HTTP_X_FORWARDED_PROTO'])) - ? ':' . $_SERVER['SERVER_PORT'] - : ''; - } - if( $request_uri ){ $url .= $_SERVER['REQUEST_URI']; } diff --git a/e107_handlers/hybridauth/Hybrid/Endpoint.php b/e107_handlers/hybridauth/Hybrid/Endpoint.php index d27c06a3b..d59824ce2 100644 --- a/e107_handlers/hybridauth/Hybrid/Endpoint.php +++ b/e107_handlers/hybridauth/Hybrid/Endpoint.php @@ -1,8 +1,8 @@ get( "hauth_session.$provider_id.hauth_endpoint" ) ) { Hybrid_Logger::error( "Endpoint: hauth_endpoint parameter is not defined on hauth_start, halt login process!" ); - header( "HTTP/1.0 404 Not Found" ); - die( "You cannot access this page directly." ); + throw new Hybrid_Exception( "You cannot access this page directly." ); } # define:hybrid.endpoint.php step 2. @@ -130,8 +129,7 @@ class Hybrid_Endpoint { if( ! $hauth ) { Hybrid_Logger::error( "Endpoint: Invalid parameter on hauth_start!" ); - header( "HTTP/1.0 404 Not Found" ); - die( "Invalid parameter! Please return to the login page and try again." ); + throw new Hybrid_Exception( "Invalid parameter! Please return to the login page and try again." ); } try { @@ -141,7 +139,7 @@ class Hybrid_Endpoint { } catch ( Exception $e ) { Hybrid_Logger::error( "Exception:" . $e->getMessage(), $e ); - Hybrid_Error::setError( $e->getMessage(), $e->getCode(), $e->getTraceAsString(), $e ); + Hybrid_Error::setError( $e->getMessage(), $e->getCode(), $e->getTraceAsString(), $e->getPrevious() ); $hauth->returnToCallbackUrl(); } @@ -165,8 +163,7 @@ class Hybrid_Endpoint { $hauth->adapter->setUserUnconnected(); - header("HTTP/1.0 404 Not Found"); - die( "Invalid parameter! Please return to the login page and try again." ); + throw new Hybrid_Exception( "Invalid parameter! Please return to the login page and try again." ); } try { @@ -176,7 +173,7 @@ class Hybrid_Endpoint { } catch( Exception $e ){ Hybrid_Logger::error( "Exception:" . $e->getMessage(), $e ); - Hybrid_Error::setError( $e->getMessage(), $e->getCode(), $e->getTraceAsString(), $e ); + Hybrid_Error::setError( $e->getMessage(), $e->getCode(), $e->getTraceAsString(), $e->getPrevious()); $hauth->adapter->setUserUnconnected(); } @@ -194,23 +191,25 @@ class Hybrid_Endpoint { # Init Hybrid_Auth try { - require_once realpath( dirname( __FILE__ ) ) . "/Storage.php"; + if(!class_exists("Hybrid_Storage")){ + require_once realpath( dirname( __FILE__ ) ) . "/Storage.php"; + } $storage = new Hybrid_Storage(); // Check if Hybrid_Auth session already exist - if ( ! $storage->config( "CONFIG" ) ) { - header( "HTTP/1.0 404 Not Found" ); - die( "You cannot access this page directly." ); + if ( ! $storage->config( "CONFIG" ) ) { + Hybrid_Logger::error( "Endpoint: Config storage not found when trying to init Hyrid_Auth. " ); + + throw new Hybrid_Exception( "You cannot access this page directly." ); } Hybrid_Auth::initialize( $storage->config( "CONFIG" ) ); } catch ( Exception $e ){ - Hybrid_Logger::error( "Endpoint: Error while trying to init Hybrid_Auth" ); + Hybrid_Logger::error( "Endpoint: Error while trying to init Hybrid_Auth: " . $e->getMessage()); - header( "HTTP/1.0 404 Not Found" ); - die( "Oophs. Error!" ); + throw new Hybrid_Exception( "Oophs. Error!" ); } } } diff --git a/e107_handlers/hybridauth/Hybrid/Error.php b/e107_handlers/hybridauth/Hybrid/Error.php index 571dfce8a..eac09ce94 100644 --- a/e107_handlers/hybridauth/Hybrid/Error.php +++ b/e107_handlers/hybridauth/Hybrid/Error.php @@ -1,8 +1,8 @@ format(DATE_ATOM); @@ -51,10 +67,15 @@ class Hybrid_Logger ); } } - + + /** + * Error + * @param String $message Error message + * @param Object $object + */ public static function error($message, $object = NULL) { - if( Hybrid_Auth::$config["debug_mode"] ){ + if(isset(Hybrid_Auth::$config["debug_mode"]) && in_array(Hybrid_Auth::$config["debug_mode"], array(true, 'info', 'error'), true) ){ $datetime = new DateTime(); $datetime = $datetime->format(DATE_ATOM); diff --git a/e107_handlers/hybridauth/Hybrid/Provider_Adapter.php b/e107_handlers/hybridauth/Hybrid/Provider_Adapter.php index e39dce283..038d99d82 100644 --- a/e107_handlers/hybridauth/Hybrid/Provider_Adapter.php +++ b/e107_handlers/hybridauth/Hybrid/Provider_Adapter.php @@ -1,15 +1,15 @@ config["wrapper"] ) && is_array( $this->config["wrapper"] ) ){ - require_once $this->config["wrapper"]["path"]; + if (isset( $this->config["wrapper"]["path"] )) { + require_once $this->config["wrapper"]["path"]; + } if( ! class_exists( $this->config["wrapper"]["class"] ) ){ throw new Exception( "Unable to load the adapter class.", 3 ); @@ -112,7 +129,21 @@ class Hybrid_Provider_Adapter $this->logout(); # get hybridauth base url - $HYBRID_AUTH_URL_BASE = Hybrid_Auth::$config["base_url"]; + if (empty(Hybrid_Auth::$config["base_url"])) { + // the base url wasn't provide, so we must use the current + // url (which makes sense actually) + $url = empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == 'off' ? 'http' : 'https'; + $url .= '://' . $_SERVER['HTTP_HOST']; + $url .= $_SERVER['REQUEST_URI']; + $HYBRID_AUTH_URL_BASE = $url; + } else { + $HYBRID_AUTH_URL_BASE = Hybrid_Auth::$config["base_url"]; + } + + // make sure params is array + if( !is_array( $this->params ) ){ + $this->params = array(); + } # we make use of session_id() as storage hash to identify the current user # using session_regenerate_id() will be a problem, but .. @@ -130,9 +161,13 @@ class Hybrid_Provider_Adapter # auth.done required the IDp ID $this->params["login_done"] = $HYBRID_AUTH_URL_BASE . ( strpos( $HYBRID_AUTH_URL_BASE, '?' ) ? '&' : '?' ) . "hauth.done={$this->id}"; - Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.hauth_return_to" , $this->params["hauth_return_to"] ); - Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.hauth_endpoint" , $this->params["login_done"] ); - Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.id_provider_params" , $this->params ); + if( isset( $this->params["hauth_return_to"] ) ){ + Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.hauth_return_to", $this->params["hauth_return_to"] ); + } + if( isset( $this->params["login_done"] ) ){ + Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.hauth_endpoint" , $this->params["login_done"] ); + } + Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.id_provider_params" , $this->params ); // store config to be used by the end point Hybrid_Auth::storage()->config( "CONFIG", Hybrid_Auth::$config ); @@ -184,12 +219,16 @@ class Hybrid_Provider_Adapter throw new Exception( "Call to undefined function Hybrid_Providers_{$this->id}::$name()." ); } - if( count( $arguments ) ){ - return $this->adapter->$name( $arguments[0] ); - } - else{ - return $this->adapter->$name(); - } + $counter = count( $arguments ); + if( $counter == 1 ){ + return $this->adapter->$name( $arguments[0] ); + } + elseif( $counter == 2 ){ + return $this->adapter->$name( $arguments[0], $arguments[1] ); + } + else{ + return $this->adapter->$name(); + } } // -------------------------------------------------------------------- @@ -242,7 +281,7 @@ class Hybrid_Provider_Adapter // get the stored callback url $callback_url = Hybrid_Auth::storage()->get( "hauth_session.{$this->id}.hauth_return_to" ); - // remove some unneed'd stored data + // remove some unneeded stored data Hybrid_Auth::storage()->delete( "hauth_session.{$this->id}.hauth_return_to" ); Hybrid_Auth::storage()->delete( "hauth_session.{$this->id}.hauth_endpoint" ); Hybrid_Auth::storage()->delete( "hauth_session.{$this->id}.id_provider_params" ); diff --git a/e107_handlers/hybridauth/Hybrid/Provider_Model.php b/e107_handlers/hybridauth/Hybrid/Provider_Model.php index 276b5cffb..f3fb347d8 100644 --- a/e107_handlers/hybridauth/Hybrid/Provider_Model.php +++ b/e107_handlers/hybridauth/Hybrid/Provider_Model.php @@ -1,8 +1,8 @@ params) by this IDp api client * - create and setup an instance of the IDp api client on $this->api @@ -119,7 +140,7 @@ abstract class Hybrid_Provider_Model */ function getUserProfile() { - Hybrid_Logger::error( "HybridAuth do not provide users contats list for {$this->providerId} yet." ); + Hybrid_Logger::error( "HybridAuth do not provide users contacts list for {$this->providerId} yet." ); throw new Exception( "Provider does not support this feature.", 8 ); } @@ -131,7 +152,7 @@ abstract class Hybrid_Provider_Model */ function getUserContacts() { - Hybrid_Logger::error( "HybridAuth do not provide users contats list for {$this->providerId} yet." ); + Hybrid_Logger::error( "HybridAuth do not provide users contacts list for {$this->providerId} yet." ); throw new Exception( "Provider does not support this feature.", 8 ); } @@ -151,7 +172,7 @@ abstract class Hybrid_Provider_Model // -------------------------------------------------------------------- /** - * return the user activity stream + * set user status */ function setUserStatus( $status ) { @@ -160,6 +181,17 @@ abstract class Hybrid_Provider_Model throw new Exception( "Provider does not support this feature.", 8 ); } + + /** + * return the user status + */ + function getUserStatus( $statusid ) + { + Hybrid_Logger::error( "HybridAuth do not provide user's status for {$this->providerId} yet." ); + + throw new Exception( "Provider does not support this feature.", 8 ); + } + // -------------------------------------------------------------------- /** @@ -222,7 +254,7 @@ abstract class Hybrid_Provider_Model // -------------------------------------------------------------------- /** - * clear all existen tokens for this provider + * clear all existent tokens for this provider */ public function clearTokens() { diff --git a/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth1.php b/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth1.php index e77d2e4ba..4b245cbf3 100644 --- a/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth1.php +++ b/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth1.php @@ -1,15 +1,15 @@ api->requestToken( $this->endpoint ); - // request tokens as recived from provider + // request tokens as received from provider $this->request_tokens_raw = $tokens; // check the last HTTP status code returned @@ -134,7 +144,7 @@ class Hybrid_Provider_Model_OAuth1 extends Hybrid_Provider_Model // request an access token $tokens = $this->api->accessToken( $oauth_verifier ); - // access tokens as recived from provider + // access tokens as received from provider $this->access_tokens_raw = $tokens; // check the last HTTP status code returned @@ -147,11 +157,11 @@ class Hybrid_Provider_Model_OAuth1 extends Hybrid_Provider_Model throw new Exception( "Authentication failed! {$this->providerId} returned an invalid access token.", 5 ); } - // we no more need to store requet tokens + // we no more need to store request tokens $this->deleteToken( "request_token" ); $this->deleteToken( "request_token_secret" ); - // sotre access_token for later user + // store access_token for later user $this->token( "access_token" , $tokens['oauth_token'] ); $this->token( "access_token_secret" , $tokens['oauth_token_secret'] ); diff --git a/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth2.php b/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth2.php index eec4c2009..fc35a24b8 100644 --- a/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth2.php +++ b/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth2.php @@ -1,15 +1,15 @@ providerId} returned an error: $error", 5 ); } - // try to authenicate user + // try to authenticate user $code = (array_key_exists('code',$_REQUEST))?$_REQUEST['code']:""; try{ diff --git a/e107_handlers/hybridauth/Hybrid/Provider_Model_OpenID.php b/e107_handlers/hybridauth/Hybrid/Provider_Model_OpenID.php index cb79fd8fc..39dd3b3cb 100644 --- a/e107_handlers/hybridauth/Hybrid/Provider_Model_OpenID.php +++ b/e107_handlers/hybridauth/Hybrid/Provider_Model_OpenID.php @@ -1,14 +1,14 @@ public $openidIdentifier = ""; * @@ -17,13 +17,16 @@ */ class Hybrid_Provider_Model_OpenID extends Hybrid_Provider_Model { - /* Openid provider identifier */ - public $openidIdentifier = ""; + /** + * Openid provider identifier + * @var string + */ + public $openidIdentifier = ""; // -------------------------------------------------------------------- /** - * adapter initializer + * adapter initializer */ function initialize() { @@ -32,18 +35,26 @@ class Hybrid_Provider_Model_OpenID extends Hybrid_Provider_Model } // include LightOpenID lib - require_once Hybrid_Auth::$config["path_libraries"] . "OpenID/LightOpenID.php"; - + require_once Hybrid_Auth::$config["path_libraries"] . "OpenID/LightOpenID.php"; + // An error was occurring when proxy wasn't set. Not sure where proxy was meant to be set/initialized. Hybrid_Auth::$config['proxy'] = isset(Hybrid_Auth::$config['proxy'])?Hybrid_Auth::$config['proxy']:''; - - $this->api = new LightOpenID( parse_url( Hybrid_Auth::$config["base_url"], PHP_URL_HOST), Hybrid_Auth::$config["proxy"] ); + + $hostPort = parse_url( Hybrid_Auth::$config["base_url"], PHP_URL_PORT); + $hostUrl = parse_url( Hybrid_Auth::$config["base_url"], PHP_URL_HOST); + + // Check for port on url + if($hostPort) { + $hostUrl .= ':'.$hostPort; + } + + $this->api = new LightOpenID( $hostUrl, Hybrid_Auth::$config["proxy"] ); } // -------------------------------------------------------------------- /** - * begin login step + * begin login step */ function loginBegin() { @@ -53,7 +64,7 @@ class Hybrid_Provider_Model_OpenID extends Hybrid_Provider_Model $this->api->identity = $this->openidIdentifier; $this->api->returnUrl = $this->endpoint; - $this->api->required = ARRAY( + $this->api->required = ARRAY( 'namePerson/first' , 'namePerson/last' , 'namePerson/friendly' , @@ -67,11 +78,11 @@ class Hybrid_Provider_Model_OpenID extends Hybrid_Provider_Model 'birthDate/birthYear' , 'person/gender' , - 'pref/language' , + 'pref/language' , 'contact/postalCode/home', 'contact/city/home' , - 'contact/country/home' , + 'contact/country/home' , 'media/image/default' , ); @@ -83,24 +94,24 @@ class Hybrid_Provider_Model_OpenID extends Hybrid_Provider_Model // -------------------------------------------------------------------- /** - * finish login step + * finish login step */ function loginFinish() { - # if user don't garant acess of their data to your site, halt with an Exception + # if user don't grant access of their data to your site, halt with an Exception if( $this->api->mode == 'cancel'){ throw new Exception( "Authentication failed! User has canceled authentication!", 5 ); } # if something goes wrong if( ! $this->api->validate() ){ - throw new Exception( "Authentication failed. Invalid request recived!", 5 ); + throw new Exception( "Authentication failed. Invalid request received!", 5 ); } - # fetch recived user data + # fetch received user data $response = $this->api->getAttributes(); - # sotre the user profile + # store the user profile $this->user->profile->identifier = $this->api->identity; $this->user->profile->firstName = (array_key_exists("namePerson/first",$response))?$response["namePerson/first"]:""; @@ -108,25 +119,21 @@ class Hybrid_Provider_Model_OpenID extends Hybrid_Provider_Model $this->user->profile->displayName = (array_key_exists("namePerson",$response))?$response["namePerson"]:""; $this->user->profile->email = (array_key_exists("contact/email",$response))?$response["contact/email"]:""; $this->user->profile->language = (array_key_exists("pref/language",$response))?$response["pref/language"]:""; - $this->user->profile->country = (array_key_exists("contact/country/home",$response))?$response["contact/country/home"]:""; - $this->user->profile->zip = (array_key_exists("contact/postalCode/home",$response))?$response["contact/postalCode/home"]:""; - $this->user->profile->gender = (array_key_exists("person/gender",$response))?$response["person/gender"]:""; - $this->user->profile->photoURL = (array_key_exists("media/image/default",$response))?$response["media/image/default"]:""; + $this->user->profile->country = (array_key_exists("contact/country/home",$response))?$response["contact/country/home"]:""; + $this->user->profile->zip = (array_key_exists("contact/postalCode/home",$response))?$response["contact/postalCode/home"]:""; + $this->user->profile->gender = (array_key_exists("person/gender",$response))?$response["person/gender"]:""; + $this->user->profile->photoURL = (array_key_exists("media/image/default",$response))?$response["media/image/default"]:""; - $this->user->profile->birthDay = (array_key_exists("birthDate/birthDay",$response))?$response["birthDate/birthDay"]:""; - $this->user->profile->birthMonth = (array_key_exists("birthDate/birthMonth",$response))?$response["birthDate/birthMonth"]:""; - $this->user->profile->birthYear = (array_key_exists("birthDate/birthDate",$response))?$response["birthDate/birthDate"]:""; + $this->user->profile->birthDay = (array_key_exists("birthDate/birthDay",$response))?$response["birthDate/birthDay"]:""; + $this->user->profile->birthMonth = (array_key_exists("birthDate/birthMonth",$response))?$response["birthDate/birthMonth"]:""; + $this->user->profile->birthYear = (array_key_exists("birthDate/birthDate",$response))?$response["birthDate/birthDate"]:""; - if( ! $this->user->profile->displayName ) { - $this->user->profile->displayName = trim( $this->user->profile->lastName . " " . $this->user->profile->firstName ); - } - - if( isset( $response['namePerson/friendly'] ) && ! empty( $response['namePerson/friendly'] ) && ! $this->user->profile->displayName ) { - $this->user->profile->displayName = (array_key_exists("namePerson/friendly",$response))?$response["namePerson/friendly"]:"" ; + if( isset( $response['namePerson/friendly'] ) && ! empty( $response['namePerson/friendly'] ) && ! $this->user->profile->displayName ) { + $this->user->profile->displayName = $response["namePerson/friendly"]; } if( isset( $response['birthDate'] ) && ! empty( $response['birthDate'] ) && ! $this->user->profile->birthDay ) { - list( $birthday_year, $birthday_month, $birthday_day ) = (array_key_exists('birthDate',$response))?$response['birthDate']:""; + list( $birthday_year, $birthday_month, $birthday_day ) = $response['birthDate']; $this->user->profile->birthDay = (int) $birthday_day; $this->user->profile->birthMonth = (int) $birthday_month; @@ -143,12 +150,12 @@ class Hybrid_Provider_Model_OpenID extends Hybrid_Provider_Model if( $this->user->profile->gender == "m" ){ $this->user->profile->gender = "male"; - } + } // set user as logged in $this->setUserConnected(); - // with openid providers we get the user profile only once, so store it + // with openid providers we get the user profile only once, so store it Hybrid_Auth::storage()->set( "hauth_session.{$this->providerId}.user", $this->user ); } @@ -165,7 +172,7 @@ class Hybrid_Provider_Model_OpenID extends Hybrid_Provider_Model // if not found if ( ! is_object( $this->user ) ){ throw new Exception( "User profile request failed! User is not connected to {$this->providerId} or his session has expired.", 6 ); - } + } return $this->user->profile; } diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Facebook.php b/e107_handlers/hybridauth/Hybrid/Providers/Facebook.php index 167c5c51f..6faed9264 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Facebook.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Facebook.php @@ -14,8 +14,8 @@ */ class Hybrid_Providers_Facebook extends Hybrid_Provider_Model { - // default permissions, and alot of them. You can change them from the configuration by setting the scope to what you want/need - public $scope = "email, user_about_me, user_birthday, user_hometown, user_website, read_stream, offline_access, publish_stream, read_friendlists"; + // default permissions, and a lot of them. You can change them from the configuration by setting the scope to what you want/need + public $scope = "email, user_about_me, user_birthday, user_hometown, user_website, read_stream, publish_actions, read_friendlists"; /** * IDp wrappers initializer @@ -35,7 +35,8 @@ class Hybrid_Providers_Facebook extends Hybrid_Provider_Model BaseFacebook::$CURL_OPTS[CURLOPT_PROXY] = Hybrid_Auth::$config["proxy"]; } - $this->api = new Facebook( ARRAY( 'appId' => $this->config["keys"]["id"], 'secret' => $this->config["keys"]["secret"] ) ); + $trustForwarded = isset( $this->config['trustForwarded'] ) ? (bool) $this->config['trustForwarded'] : false; + $this->api = new Facebook( ARRAY( 'appId' => $this->config["keys"]["id"], 'secret' => $this->config["keys"]["secret"], 'trustForwarded' => $trustForwarded ) ); if ( $this->token("access_token") ) { $this->api->setAccessToken( $this->token("access_token") ); @@ -61,14 +62,29 @@ class Hybrid_Providers_Facebook extends Hybrid_Provider_Model function loginBegin() { $parameters = array("scope" => $this->scope, "redirect_uri" => $this->endpoint, "display" => "page"); - $optionals = array("scope", "redirect_uri", "display"); + $optionals = array("scope", "redirect_uri", "display", "auth_type"); foreach ($optionals as $parameter){ if( isset( $this->config[$parameter] ) && ! empty( $this->config[$parameter] ) ){ $parameters[$parameter] = $this->config[$parameter]; + + //If the auth_type parameter is used, we need to generate a nonce and include it as a parameter + if($parameter == "auth_type"){ + $nonce = md5(uniqid(mt_rand(), true)); + $parameters['auth_nonce'] = $nonce; + + Hybrid_Auth::storage()->set('fb_auth_nonce', $nonce); + } } } + if( isset( $this->config[ 'force' ] ) && $this->config[ 'force' ] === true ){ + $parameters[ 'auth_type' ] = 'reauthenticate'; + $parameters[ 'auth_nonce' ] = md5( uniqid( mt_rand(), true ) ); + + Hybrid_Auth::storage()->set( 'fb_auth_nonce', $parameters[ 'auth_nonce' ] ); + } + // get the login url $url = $this->api->getLoginUrl( $parameters ); @@ -86,6 +102,35 @@ class Hybrid_Providers_Facebook extends Hybrid_Provider_Model throw new Exception( "Authentication failed! The user denied your request.", 5 ); } + // in case we are using iOS/Facebook reverse authentication + if(isset($_REQUEST['access_token'])){ + $this->token("access_token", $_REQUEST['access_token'] ); + $this->api->setAccessToken( $this->token("access_token") ); + $this->api->setExtendedAccessToken(); + $access_token = $this->api->getAccessToken(); + + if( $access_token ){ + $this->token("access_token", $access_token ); + $this->api->setAccessToken( $access_token ); + } + + $this->api->setAccessToken( $this->token("access_token") ); + } + + + // if auth_type is used, then an auth_nonce is passed back, and we need to check it. + if(isset($_REQUEST['auth_nonce'])){ + + $nonce = Hybrid_Auth::storage()->get('fb_auth_nonce'); + + //Delete the nonce + Hybrid_Auth::storage()->delete('fb_auth_nonce'); + + if($_REQUEST['auth_nonce'] != $nonce){ + throw new Exception( "Authentication failed! Invalid nonce used for reauthentication.", 5 ); + } + } + // try to get the UID of the connected user from fb, should be > 0 if ( ! $this->api->getUser() ){ throw new Exception( "Authentication failed! {$this->providerId} returned an invalid user id.", 5 ); @@ -121,25 +166,36 @@ class Hybrid_Providers_Facebook extends Hybrid_Provider_Model throw new Exception( "User profile request failed! {$this->providerId} returned an error: $e", 6 ); } - // if the provider identifier is not recived, we assume the auth has failed + // if the provider identifier is not received, we assume the auth has failed if ( ! isset( $data["id"] ) ){ throw new Exception( "User profile request failed! {$this->providerId} api returned an invalid response.", 6 ); } # store the user profile. $this->user->profile->identifier = (array_key_exists('id',$data))?$data['id']:""; + $this->user->profile->username = (array_key_exists('username',$data))?$data['username']:""; $this->user->profile->displayName = (array_key_exists('name',$data))?$data['name']:""; $this->user->profile->firstName = (array_key_exists('first_name',$data))?$data['first_name']:""; $this->user->profile->lastName = (array_key_exists('last_name',$data))?$data['last_name']:""; $this->user->profile->photoURL = "https://graph.facebook.com/" . $this->user->profile->identifier . "/picture?width=150&height=150"; + $this->user->profile->coverInfoURL = "https://graph.facebook.com/" . $this->user->profile->identifier . "?fields=cover"; $this->user->profile->profileURL = (array_key_exists('link',$data))?$data['link']:""; $this->user->profile->webSiteURL = (array_key_exists('website',$data))?$data['website']:""; $this->user->profile->gender = (array_key_exists('gender',$data))?$data['gender']:""; - $this->user->profile->description = (array_key_exists('bio',$data))?$data['bio']:""; + $this->user->profile->language = (array_key_exists('locale',$data))?$data['locale']:""; + $this->user->profile->description = (array_key_exists('about',$data))?$data['about']:""; $this->user->profile->email = (array_key_exists('email',$data))?$data['email']:""; $this->user->profile->emailVerified = (array_key_exists('email',$data))?$data['email']:""; $this->user->profile->region = (array_key_exists("hometown",$data)&&array_key_exists("name",$data['hometown']))?$data['hometown']["name"]:""; - + + if(!empty($this->user->profile->region )){ + $regionArr = explode(',',$this->user->profile->region ); + if(count($regionArr) > 1){ + $this->user->profile->city = trim($regionArr[0]); + $this->user->profile->country = trim($regionArr[1]); + } + } + if( array_key_exists('birthday',$data) ) { list($birthday_month, $birthday_day, $birthday_year) = explode( "/", $data['birthday'] ); @@ -151,30 +207,67 @@ class Hybrid_Providers_Facebook extends Hybrid_Provider_Model return $this->user->profile; } + /** + * Attempt to retrieve the url to the cover image given the coverInfoURL + * + * @param string $coverInfoURL coverInfoURL variable + * @retval string url to the cover image OR blank string + */ + function getCoverURL($coverInfoURL) + { + try { + $headers = get_headers($coverInfoURL); + if(substr($headers[0], 9, 3) != "404") { + $coverOBJ = json_decode(file_get_contents($coverInfoURL)); + if(array_key_exists('cover', $coverOBJ)) { + return $coverOBJ->cover->source; + } + } + } catch (Exception $e) { } + + return ""; + } + /** * load the user contacts */ function getUserContacts() { - try{ - $response = $this->api->api('/me/friends'); - } - catch( FacebookApiException $e ){ - throw new Exception( "User contacts request failed! {$this->providerId} returned an error: $e" ); - } - - if( ! $response || ! count( $response["data"] ) ){ - return ARRAY(); + $apiCall = '?fields=link,name'; + $returnedContacts = array(); + $pagedList = false; + + do { + try{ + $response = $this->api->api('/me/friends' . $apiCall); + } + catch( FacebookApiException $e ){ + throw new Exception( 'User contacts request failed! {$this->providerId} returned an error: $e' ); + } + + // Prepare the next call if paging links have been returned + if (array_key_exists('paging', $response) && array_key_exists('next', $response['paging'])) { + $pagedList = true; + $next_page = explode('friends', $response['paging']['next']); + $apiCall = $next_page[1]; + } + else{ + $pagedList = false; + } + + // Add the new page contacts + $returnedContacts = array_merge($returnedContacts, $response['data']); } + while ($pagedList == true); $contacts = ARRAY(); - foreach( $response["data"] as $item ){ + foreach( $returnedContacts as $item ){ $uc = new Hybrid_User_Contact(); $uc->identifier = (array_key_exists("id",$item))?$item["id"]:""; $uc->displayName = (array_key_exists("name",$item))?$item["name"]:""; - $uc->profileURL = "https://www.facebook.com/profile.php?id=" . $uc->identifier; + $uc->profileURL = (array_key_exists("link",$item))?$item["link"]:"https://www.facebook.com/profile.php?id=" . $uc->identifier; $uc->photoURL = "https://graph.facebook.com/" . $uc->identifier . "/picture?width=150&height=150"; $contacts[] = $uc; @@ -183,27 +276,96 @@ class Hybrid_Providers_Facebook extends Hybrid_Provider_Model return $contacts; } + /** + * update user status + * + * @param string $pageid (optional) User page id + */ + function setUserStatus( $status, $pageid = null ) + { + if( !is_array( $status ) ){ + $status = array( 'message' => $status ); + } + + if( is_null( $pageid ) ){ + $pageid = 'me'; + + // if post on page, get access_token page + }else{ + $access_token = null; + foreach( $this->getUserPages( true ) as $p ){ + if( isset( $p[ 'id' ] ) && intval( $p['id'] ) == intval( $pageid ) ){ + $access_token = $p[ 'access_token' ]; + break; + } + } + + if( is_null( $access_token ) ){ + throw new Exception( "Update user page failed, page not found or not writable!" ); + } + + $status[ 'access_token' ] = $access_token; + } + + try{ + $response = $this->api->api( '/' . $pageid . '/feed', 'post', $status ); + } + catch( FacebookApiException $e ){ + throw new Exception( "Update user status failed! {$this->providerId} returned an error: $e" ); + } + + return $response; + } + + /** - * update user status + * get user status */ - function setUserStatus( $status ) - { - $parameters = array(); - - if( is_array( $status ) ){ - $parameters = $status; - } - else{ - $parameters["message"] = $status; - } - - try{ - $response = $this->api->api( "/me/feed", "post", $parameters ); - } + function getUserStatus( $postid ) + { + try{ + $postinfo = $this->api->api( "/" . $postid ); + } catch( FacebookApiException $e ){ - throw new Exception( "Update user status failed! {$this->providerId} returned an error: $e" ); + throw new Exception( "Cannot retrieve user status! {$this->providerId} returned an error: $e" ); } - } + + return $postinfo; + } + + + /** + * get user pages + */ + function getUserPages( $writableonly = false ) + { + if( ( isset( $this->config[ 'scope' ] ) && strpos( $this->config[ 'scope' ], 'manage_pages' ) === false ) || ( !isset( $this->config[ 'scope' ] ) && strpos( $this->scope, 'manage_pages' ) === false ) ) + throw new Exception( "User status requires manage_page permission!" ); + + try{ + $pages = $this->api->api( "/me/accounts", 'get' ); + } + catch( FacebookApiException $e ){ + throw new Exception( "Cannot retrieve user pages! {$this->providerId} returned an error: $e" ); + } + + if( !isset( $pages[ 'data' ] ) ){ + return array(); + } + + if( !$writableonly ){ + return $pages[ 'data' ]; + } + + $wrpages = array(); + foreach( $pages[ 'data' ] as $p ){ + if( isset( $p[ 'perms' ] ) && in_array( 'CREATE_CONTENT', $p[ 'perms' ] ) ){ + $wrpages[] = $p; + } + } + + return $wrpages; + } /** * load the user latest activity diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Foursquare.php b/e107_handlers/hybridauth/Hybrid/Providers/Foursquare.php index fa4373a02..45ae1e42e 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Foursquare.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Foursquare.php @@ -10,6 +10,21 @@ * * http://hybridauth.sourceforge.net/userguide/IDProvider_info_Foursquare.html */ + +/** + * Howto define profile photo size: + * - add params key into hybridauth config + * ... + * "Foursquare" => array ( + * "enabled" => true, + * "keys" => ..., + * "params" => array( "photo_size" => "16x16" ) + * ), + * ... + * - list of valid photo_size values is described here https://developer.foursquare.com/docs/responses/photo.html + * - default photo_size is 100x100 + */ + class Hybrid_Providers_Foursquare extends Hybrid_Provider_Model_OAuth2 { /** @@ -32,7 +47,7 @@ class Hybrid_Providers_Foursquare extends Hybrid_Provider_Model_OAuth2 */ function getUserProfile() { - $data = $this->api->api( "users/self" ); + $data = $this->api->api( "users/self", "GET", array( "v" => "20120610" ) ); if ( ! isset( $data->response->user->id ) ){ throw new Exception( "User profile request failed! {$this->providerId} returned an invalid response.", 6 ); @@ -40,11 +55,14 @@ class Hybrid_Providers_Foursquare extends Hybrid_Provider_Model_OAuth2 $data = $data->response->user; + // get profile photo size from config + $photoSize = ((isset($this->config["params"]["photo_size"]))?($this->config["params"]["photo_size"]):("100x100")); + $this->user->profile->identifier = $data->id; $this->user->profile->firstName = $data->firstName; $this->user->profile->lastName = $data->lastName; $this->user->profile->displayName = trim( $this->user->profile->firstName . " " . $this->user->profile->lastName ); - $this->user->profile->photoURL = $data->photo; + $this->user->profile->photoURL = $data->photo->prefix.$photoSize.$data->photo->suffix; $this->user->profile->profileURL = "https://www.foursquare.com/user/" . $data->id; $this->user->profile->gender = $data->gender; $this->user->profile->city = $data->homeCity; diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Google.php b/e107_handlers/hybridauth/Hybrid/Providers/Google.php index 5ced00358..313b0b6ad 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Google.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Google.php @@ -2,7 +2,7 @@ /*! * HybridAuth * http://hybridauth.sourceforge.net | http://github.com/hybridauth/hybridauth -* (c) 2009-2012, HybridAuth authors | http://hybridauth.sourceforge.net/licenses.html +* (c) 2009-2014, HybridAuth authors | http://hybridauth.sourceforge.net/licenses.html */ /** @@ -12,8 +12,11 @@ */ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 { + // > more infos on google APIs: http://developer.google.com (official site) + // or here: http://discovery-check.appspot.com/ (unofficial but up to date) + // default permissions - public $scope = "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://www.google.com/m8/feeds/"; + public $scope = "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.profile.emails.read https://www.google.com/m8/feeds/"; /** * IDp wrappers initializer @@ -25,7 +28,13 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 // Provider api end-points $this->api->authorize_url = "https://accounts.google.com/o/oauth2/auth"; $this->api->token_url = "https://accounts.google.com/o/oauth2/token"; - $this->api->token_info_url = "https://www.googleapis.com/oauth2/v1/tokeninfo"; + $this->api->token_info_url = "https://www.googleapis.com/oauth2/v2/tokeninfo"; + + // Override the redirect uri when it's set in the config parameters. This way we prevent + // redirect uri mismatches when authenticating with Google. + if( isset( $this->config['redirect_uri'] ) && ! empty( $this->config['redirect_uri'] ) ){ + $this->api->redirect_uri = $this->config['redirect_uri']; + } } /** @@ -34,14 +43,21 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 function loginBegin() { $parameters = array("scope" => $this->scope, "access_type" => "offline"); - $optionals = array("scope", "access_type", "redirect_uri", "approval_prompt", "hd"); + $optionals = array("scope", "access_type", "redirect_uri", "approval_prompt", "hd", "state"); foreach ($optionals as $parameter){ if( isset( $this->config[$parameter] ) && ! empty( $this->config[$parameter] ) ){ $parameters[$parameter] = $this->config[$parameter]; } + if( isset( $this->config["scope"] ) && ! empty( $this->config["scope"] ) ){ + $this->scope = $this->config["scope"]; + } } + if( isset( $this->config[ 'force' ] ) && $this->config[ 'force' ] === true ){ + $parameters[ 'approval_prompt' ] = 'force'; + } + Hybrid_Auth::redirect( $this->api->authorizeUrl( $parameters ) ); } @@ -54,36 +70,104 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 $this->refreshToken(); // ask google api for user infos - $response = $this->api->api( "https://www.googleapis.com/oauth2/v1/userinfo" ); + if (strpos($this->scope, '/auth/plus.profile.emails.read') !== false) { + $verified = $this->api->api( "https://www.googleapis.com/plus/v1/people/me" ); + if ( ! isset( $verified->id ) || isset( $verified->error ) ) + $verified = new stdClass(); + } else { + $verified = $this->api->api( "https://www.googleapis.com/plus/v1/people/me/openIdConnect" ); + + if ( ! isset( $verified->sub ) || isset( $verified->error ) ) + $verified = new stdClass(); + } + + $response = $this->api->api( "https://www.googleapis.com/plus/v1/people/me" ); if ( ! isset( $response->id ) || isset( $response->error ) ){ throw new Exception( "User profile request failed! {$this->providerId} returned an invalid response.", 6 ); } - $this->user->profile->identifier = (property_exists($response,'id'))?$response->id:""; - $this->user->profile->firstName = (property_exists($response,'given_name'))?$response->given_name:""; - $this->user->profile->lastName = (property_exists($response,'family_name'))?$response->family_name:""; - $this->user->profile->displayName = (property_exists($response,'name'))?$response->name:""; - $this->user->profile->photoURL = (property_exists($response,'picture'))?$response->picture:""; - $this->user->profile->profileURL = "https://profiles.google.com/" . $this->user->profile->identifier; + $this->user->profile->identifier = (property_exists($verified,'id'))?$verified->id:((property_exists($response,'id'))?$response->id:""); + $this->user->profile->firstName = (property_exists($response,'name'))?$response->name->givenName:""; + $this->user->profile->lastName = (property_exists($response,'name'))?$response->name->familyName:""; + $this->user->profile->displayName = (property_exists($response,'displayName'))?$response->displayName:""; + $this->user->profile->photoURL = (property_exists($response,'image'))?((property_exists($response->image,'url'))?substr($response->image->url, 0, -2)."200":''):''; + $this->user->profile->profileURL = (property_exists($response,'url'))?$response->url:""; + $this->user->profile->description = (property_exists($response,'aboutMe'))?$response->aboutMe:""; $this->user->profile->gender = (property_exists($response,'gender'))?$response->gender:""; - $this->user->profile->email = (property_exists($response,'email'))?$response->email:""; - $this->user->profile->emailVerified = (property_exists($response,'email'))?$response->email:""; - $this->user->profile->language = (property_exists($response,'locale'))?$response->locale:""; - + $this->user->profile->language = (property_exists($response,'locale'))?$response->locale:((property_exists($verified,'locale'))?$verified->locale:""); + $this->user->profile->email = (property_exists($response,'email'))?$response->email:((property_exists($verified,'email'))?$verified->email:""); + $this->user->profile->emailVerified = (property_exists($verified,'email'))?$verified->email:""; + if (property_exists($response, 'emails')) { + if (count($response->emails) == 1) { + $this->user->profile->email = $response->emails[0]->value; + } else { + foreach ($response->emails as $email) { + if ($email->type == 'account') { + $this->user->profile->email = $email->value; + break; + } + } + } + } + $this->user->profile->phone = (property_exists($response,'phone'))?$response->phone:""; + $this->user->profile->country = (property_exists($response,'country'))?$response->country:""; + $this->user->profile->region = (property_exists($response,'region'))?$response->region:""; + $this->user->profile->zip = (property_exists($response,'zip'))?$response->zip:""; + if( property_exists($response,'placesLived') ){ + $this->user->profile->city = ""; + $this->user->profile->address = ""; + foreach($response->placesLived as $c){ + if(property_exists($c,'primary')){ + if($c->primary == true){ + $this->user->profile->address = $c->value; + $this->user->profile->city = $c->value; + break; + } + }else{ + if(property_exists($c,'value')){ + $this->user->profile->address = $c->value; + $this->user->profile->city = $c->value; + } + } + } + } + + // google API returns multiple urls, but a "website" only if it is verified + // see http://support.google.com/plus/answer/1713826?hl=en + if( property_exists($response,'urls') ){ + foreach($response->urls as $u){ + if(property_exists($u, 'primary') && $u->primary == true) $this->user->profile->webSiteURL = $u->value; + } + } else { + $this->user->profile->webSiteURL = ''; + } + // google API returns age ranges or min. age only (with plus.login scope) + if( property_exists($response,'ageRange') ){ + if( property_exists($response->ageRange,'min') && property_exists($response->ageRange,'max') ){ + $this->user->profile->age = $response->ageRange->min.' - '.$response->ageRange->max; + } else { + $this->user->profile->age = '> '.$response->ageRange->min; + } + } else { + $this->user->profile->age = ''; + } + // google API returns birthdays only if a user set 'show in my account' if( property_exists($response,'birthday') ){ list($birthday_year, $birthday_month, $birthday_day) = explode( '-', $response->birthday ); $this->user->profile->birthDay = (int) $birthday_day; $this->user->profile->birthMonth = (int) $birthday_month; $this->user->profile->birthYear = (int) $birthday_year; + } else { + $this->user->profile->birthDay=0;$this->user->profile->birthMonth=0;$this->user->profile->birthYear=0; } - + return $this->user->profile; } /** - * load the user (Gmail) contacts + * load the user (Gmail and google plus) contacts * ..toComplete */ function getUserContacts() @@ -91,29 +175,106 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 // refresh tokens if needed $this->refreshToken(); + $contacts = array(); if( ! isset( $this->config['contacts_param'] ) ){ $this->config['contacts_param'] = array( "max-results" => 500 ); } + + // Google Gmail and Android contacts + if (strpos($this->scope, '/m8/feeds/') !== false) { + + $response = $this->api->api( "https://www.google.com/m8/feeds/contacts/default/full?" + . http_build_query( array_merge( array('alt' => 'json', 'v' => '3.0'), $this->config['contacts_param'] ) ) ); + + if( ! $response ){ + return ARRAY(); + } - $response = $this->api->api( "https://www.google.com/m8/feeds/contacts/default/full?" - . http_build_query( array_merge( array('alt' => 'json'), $this->config['contacts_param'] ) ) ); + if (isset($response->feed->entry)) { + foreach( $response->feed->entry as $idx => $entry ){ + $uc = new Hybrid_User_Contact(); + $uc->email = isset($entry->{'gd$email'}[0]->address) ? (string) $entry->{'gd$email'}[0]->address : ''; + $uc->displayName = isset($entry->title->{'$t'}) ? (string) $entry->title->{'$t'} : ''; + $uc->identifier = ($uc->email!='')?$uc->email:''; + $uc->description = ''; + if( property_exists($entry,'link') ){ + /** + * sign links with access_token + */ + if(is_array($entry->link)){ + foreach($entry->link as $l){ + if( property_exists($l,'gd$etag') && $l->type=="image/*"){ + $uc->photoURL = $this->addUrlParam($l->href, array('access_token' => $this->api->access_token)); + } else if($l->type=="self"){ + $uc->profileURL = $this->addUrlParam($l->href, array('access_token' => $this->api->access_token)); + } + } + } + } else { + $uc->profileURL = ''; + } + if( property_exists($response,'website') ){ + if(is_array($response->website)){ + foreach($response->website as $w){ + if($w->primary == true) $uc->webSiteURL = $w->value; + } + } else { + $uc->webSiteURL = $response->website->value; + } + } else { + $uc->webSiteURL = ''; + } - if( ! $response ){ - return ARRAY(); + $contacts[] = $uc; + } + } } - - $contacts = ARRAY(); - - foreach( $response->feed->entry as $idx => $entry ){ - $uc = new Hybrid_User_Contact(); - - $uc->email = isset($entry->{'gd$email'}[0]->address) ? (string) $entry->{'gd$email'}[0]->address : ''; - $uc->displayName = isset($entry->title->{'$t'}) ? (string) $entry->title->{'$t'} : ''; - $uc->identifier = $uc->email; - - $contacts[] = $uc; - } - + + // Google social contacts + if (strpos($this->scope, '/auth/plus.login') !== false) { + + $response = $this->api->api( "https://www.googleapis.com/plus/v1/people/me/people/visible?" + . http_build_query( $this->config['contacts_param'] ) ); + + if( ! $response ){ + return ARRAY(); + } + + foreach( $response->items as $idx => $item ){ + $uc = new Hybrid_User_Contact(); + $uc->email = (property_exists($item,'email'))?$item->email:''; + $uc->displayName = (property_exists($item,'displayName'))?$item->displayName:''; + $uc->identifier = (property_exists($item,'id'))?$item->id:''; + + $uc->description = (property_exists($item,'objectType'))?$item->objectType:''; + $uc->photoURL = (property_exists($item,'image'))?((property_exists($item->image,'url'))?$item->image->url:''):''; + $uc->profileURL = (property_exists($item,'url'))?$item->url:''; + $uc->webSiteURL = ''; + + $contacts[] = $uc; + } + + } + return $contacts; } + + /** + * Add to the $url new parameters + * @param string $url + * @param array $params + * @return string + */ + function addUrlParam($url, array $params) + { + $query = parse_url($url, PHP_URL_QUERY); + + // Returns the URL string with new parameters + if( $query ) { + $url .= '&' . http_build_query( $params ); + } else { + $url .= '?' . http_build_query( $params ); + } + return $url; + } } diff --git a/e107_handlers/hybridauth/Hybrid/Providers/LinkedIn.php b/e107_handlers/hybridauth/Hybrid/Providers/LinkedIn.php index 873f5817c..28b5bd757 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/LinkedIn.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/LinkedIn.php @@ -22,8 +22,9 @@ class Hybrid_Providers_LinkedIn extends Hybrid_Provider_Model if ( ! $this->config["keys"]["key"] || ! $this->config["keys"]["secret"] ){ throw new Exception( "Your application key and secret are required in order to connect to {$this->providerId}.", 4 ); } - - require_once Hybrid_Auth::$config["path_libraries"] . "OAuth/OAuth.php"; + if ( ! class_exists('OAuthConsumer') ) { + require_once Hybrid_Auth::$config["path_libraries"] . "OAuth/OAuth.php"; + } require_once Hybrid_Auth::$config["path_libraries"] . "LinkedIn/LinkedIn.php"; $this->api = new LinkedIn( array( 'appKey' => $this->config["keys"]["key"], 'appSecret' => $this->config["keys"]["secret"], 'callbackUrl' => $this->endpoint ) ); @@ -200,6 +201,8 @@ class Hybrid_Providers_LinkedIn extends Hybrid_Provider_Model { throw new Exception( "Update user status update failed! {$this->providerId} returned an error." ); } + + return $response; } /** diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Live.php b/e107_handlers/hybridauth/Hybrid/Providers/Live.php index 6f9812655..47e9e8126 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Live.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Live.php @@ -20,7 +20,7 @@ class Hybrid_Providers_Live extends Hybrid_Provider_Model_OAuth2 { // default permissions - public $scope = "wl.basic wl.emails wl.signin wl.share wl.birthday"; + public $scope = "wl.basic wl.contacts_emails wl.emails wl.signin wl.share wl.birthday"; /** @@ -46,7 +46,7 @@ class Hybrid_Providers_Live extends Hybrid_Provider_Model_OAuth2 $data = $this->api->get( "me" ); if ( ! isset( $data->id ) ){ - throw new Exception( "User profile request failed! {$this->providerId} returned an invalide response.", 6 ); + throw new Exception( "User profile request failed! {$this->providerId} returned an invalid response.", 6 ); } $this->user->profile->identifier = (property_exists($data,'id'))?$data->id:""; @@ -85,7 +85,7 @@ class Hybrid_Providers_Live extends Hybrid_Provider_Model_OAuth2 throw new Exception( 'User contacts request failed! ' . $this->providerId . ' returned an error: ' . $this->errorMessageByStatus( $this->api->http_code ) ); } - if ( ! $response->data && ( $response->error != 0 ) ) + if ( !isset($response->data) || ( isset($response->errcode) && $response->errcode != 0 ) ) { return array(); } @@ -97,7 +97,7 @@ class Hybrid_Providers_Live extends Hybrid_Provider_Model_OAuth2 $uc->identifier = (property_exists($item,'id'))?$item->id:""; $uc->displayName = (property_exists($item,'name'))?$item->name:""; - + $uc->email = (property_exists($item,'emails'))?$item->emails->preferred:""; $contacts[] = $uc; } diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Twitter.php b/e107_handlers/hybridauth/Hybrid/Providers/Twitter.php index 5afed69c5..8089f53bc 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Twitter.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Twitter.php @@ -39,25 +39,37 @@ class Hybrid_Providers_Twitter extends Hybrid_Provider_Model_OAuth1 */ function loginBegin() { + // Initiate the Reverse Auth flow; cf. https://dev.twitter.com/docs/ios/using-reverse-auth + if (isset($_REQUEST['reverse_auth']) && ($_REQUEST['reverse_auth'] == 'yes')){ + $stage1 = $this->api->signedRequest( $this->api->request_token_url, 'POST', array( 'x_auth_mode' => 'reverse_auth' ) ); + if ( $this->api->http_code != 200 ){ + throw new Exception( "Authentication failed! {$this->providerId} returned an error. " . $this->errorMessageByStatus( $this->api->http_code ), 5 ); + } + $responseObj = array( 'x_reverse_auth_parameters' => $stage1, 'x_reverse_auth_target' => $this->config["keys"]["key"] ); + $response = json_encode($responseObj); + header( "Content-Type: application/json", true, 200 ) ; + echo $response; + die(); + } $tokens = $this->api->requestToken( $this->endpoint ); - // request tokens as recived from provider + // request tokens as received from provider $this->request_tokens_raw = $tokens; // check the last HTTP status code returned if ( $this->api->http_code != 200 ){ - throw new Exception( "Authentification failed! {$this->providerId} returned an error. " . $this->errorMessageByStatus( $this->api->http_code ), 5 ); + throw new Exception( "Authentication failed! {$this->providerId} returned an error. " . $this->errorMessageByStatus( $this->api->http_code ), 5 ); } if ( ! isset( $tokens["oauth_token"] ) ){ - throw new Exception( "Authentification failed! {$this->providerId} returned an invalid oauth token.", 5 ); + throw new Exception( "Authentication failed! {$this->providerId} returned an invalid oauth token.", 5 ); } $this->token( "request_token" , $tokens["oauth_token"] ); $this->token( "request_token_secret", $tokens["oauth_token_secret"] ); // redirect the user to the provider authentication url with force_login - if ( isset( $this->config['force_login'] ) && $this->config['force_login'] ){ + if ( ( isset( $this->config['force_login'] ) && $this->config['force_login'] ) || ( isset( $this->config[ 'force' ] ) && $this->config[ 'force' ] === true ) ){ Hybrid_Auth::redirect( $this->api->authorizeUrl( $tokens, array( 'force_login' => true ) ) ); } @@ -65,6 +77,37 @@ class Hybrid_Providers_Twitter extends Hybrid_Provider_Model_OAuth1 Hybrid_Auth::redirect( $this->api->authorizeUrl( $tokens ) ); } + /** + * finish login step + */ + function loginFinish() + { + // in case we are completing a Reverse Auth flow; cf. https://dev.twitter.com/docs/ios/using-reverse-auth + if(isset($_REQUEST['oauth_token_secret'])){ + $tokens = $_REQUEST; + $this->access_tokens_raw = $tokens; + + // we should have an access_token unless something has gone wrong + if ( ! isset( $tokens["oauth_token"] ) ){ + throw new Exception( "Authentication failed! {$this->providerId} returned an invalid access token.", 5 ); + } + + // Get rid of tokens we don't need + $this->deleteToken( "request_token" ); + $this->deleteToken( "request_token_secret" ); + + // Store access_token and secret for later use + $this->token( "access_token" , $tokens['oauth_token'] ); + $this->token( "access_token_secret" , $tokens['oauth_token_secret'] ); + + // set user as logged in to the current provider + $this->setUserConnected(); + return; + } + parent::loginFinish(); + } + + /** * load the user profile from the IDp api client */ @@ -86,7 +129,7 @@ class Hybrid_Providers_Twitter extends Hybrid_Provider_Model_OAuth1 $this->user->profile->displayName = (property_exists($response,'screen_name'))?$response->screen_name:""; $this->user->profile->description = (property_exists($response,'description'))?$response->description:""; $this->user->profile->firstName = (property_exists($response,'name'))?$response->name:""; - $this->user->profile->photoURL = (property_exists($response,'profile_image_url'))?$response->profile_image_url:""; + $this->user->profile->photoURL = (property_exists($response,'profile_image_url'))?(str_replace('_normal', '', $response->profile_image_url)):""; $this->user->profile->profileURL = (property_exists($response,'screen_name'))?("http://twitter.com/".$response->screen_name):""; $this->user->profile->webSiteURL = (property_exists($response,'url'))?$response->url:""; $this->user->profile->region = (property_exists($response,'location'))?$response->location:""; @@ -143,19 +186,42 @@ class Hybrid_Providers_Twitter extends Hybrid_Provider_Model_OAuth1 return $contacts; } - /** - * update user status - */ - function setUserStatus( $status ) - { - $parameters = array( 'status' => $status ); - $response = $this->api->post( 'statuses/update.json', $parameters ); + /** + * update user status + */ + function setUserStatus( $status ) + { + + if( is_array( $status ) && isset( $status[ 'message' ] ) && isset( $status[ 'picture' ] ) ){ + $response = $this->api->post( 'statuses/update_with_media.json', array( 'status' => $status[ 'message' ], 'media[]' => file_get_contents( $status[ 'picture' ] ) ), null, null, true ); + }else{ + $response = $this->api->post( 'statuses/update.json', array( 'status' => $status ) ); + } + + // check the last HTTP status code returned + if ( $this->api->http_code != 200 ){ + throw new Exception( "Update user status failed! {$this->providerId} returned an error. " . $this->errorMessageByStatus( $this->api->http_code ) ); + } + + return $response; + } + + + /** + * get user status + */ + function getUserStatus( $tweetid ) + { + $info = $this->api->get( 'statuses/show.json?id=' . $tweetid . '&include_entities=true' ); + + // check the last HTTP status code returned + if ( $this->api->http_code != 200 || !isset( $info->id ) ){ + throw new Exception( "Cannot retrieve user status! {$this->providerId} returned an error. " . $this->errorMessageByStatus( $this->api->http_code ) ); + } + + return $info; + } - // check the last HTTP status code returned - if ( $this->api->http_code != 200 ){ - throw new Exception( "Update user status failed! {$this->providerId} returned an error. " . $this->errorMessageByStatus( $this->api->http_code ) ); - } - } /** * load the user latest activity diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Yahoo.php b/e107_handlers/hybridauth/Hybrid/Providers/Yahoo.php index 0efddd0cc..3f4b9bb75 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Yahoo.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Yahoo.php @@ -24,7 +24,7 @@ class Hybrid_Providers_Yahoo extends Hybrid_Provider_Model_OAuth1 parent::initialize(); // Provider api end-points - $this->api->api_base_url = 'http://social.yahooapis.com/v1/'; + $this->api->api_base_url = 'https://social.yahooapis.com/v1/'; $this->api->authorize_url = 'https://api.login.yahoo.com/oauth/v2/request_auth'; $this->api->request_token_url = 'https://api.login.yahoo.com/oauth/v2/get_request_token'; $this->api->access_token_url = 'https://api.login.yahoo.com/oauth/v2/get_token'; @@ -101,7 +101,7 @@ class Hybrid_Providers_Yahoo extends Hybrid_Provider_Model_OAuth1 throw new Exception( 'User contacts request failed! ' . $this->providerId . ' returned an error: ' . $this->errorMessageByStatus( $this->api->http_code ) ); } - if ( !$response->contacts->contact && ( $response->errcode != 0 ) ) + if ( !isset($response->contacts) || !isset($response->contacts->contact) || ( isset($response->errcode) && $response->errcode != 0 ) ) { return array(); } @@ -218,6 +218,11 @@ class Hybrid_Providers_Yahoo extends Hybrid_Provider_Model_OAuth1 function selectEmail( $v ) { $s = $this->select($v, 'email'); + if(empty($s)){ + $s = $this->select($v, 'yahooid'); + if(!empty($s) && isset($s->value) && strpos($s->value,"@")===FALSE) + $s->value .= "@yahoo.com"; + } return ($s)?$s->value:""; } diff --git a/e107_handlers/hybridauth/Hybrid/Storage.php b/e107_handlers/hybridauth/Hybrid/Storage.php index cd17c43a7..9f5e3f8ca 100644 --- a/e107_handlers/hybridauth/Hybrid/Storage.php +++ b/e107_handlers/hybridauth/Hybrid/Storage.php @@ -1,15 +1,20 @@ config( "php_session_id", session_id() ); $this->config( "version", Hybrid_Auth::$version ); } - - public function config($key, $value=null) + + /** + * Config + * @param String $key + * @param String $value + */ + public function config($key, $value = null) { $key = strtolower( $key ); @@ -35,7 +45,11 @@ class Hybrid_Storage return NULL; } - + + /** + * Get a key + * @param String $key + */ public function get($key) { $key = strtolower( $key ); @@ -46,19 +60,31 @@ class Hybrid_Storage return NULL; } - + + /** + * GEt a set of key and value + * @param String $key + * @param String $value + */ public function set( $key, $value ) { - $key = strtolower( $key ); + $key = strtolower( $key ); - $_SESSION["HA::STORE"][$key] = serialize( $value ); + $_SESSION["HA::STORE"][$key] = serialize( $value ); } - + + /** + * Clear session storage + */ function clear() { $_SESSION["HA::STORE"] = ARRAY(); - } - + } + + /** + * Delete a specific key + * @param String $key + */ function delete($key) { $key = strtolower( $key ); @@ -69,7 +95,11 @@ class Hybrid_Storage $_SESSION["HA::STORE"] = $f; } } - + + /** + * Delete a set + * @param String $key + */ function deleteMatch($key) { $key = strtolower( $key ); @@ -85,7 +115,11 @@ class Hybrid_Storage } } - + + /** + * Get the storage session data into an array + * @return Array + */ function getSessionData() { if( isset( $_SESSION["HA::STORE"] ) ){ @@ -94,7 +128,11 @@ class Hybrid_Storage return NULL; } - + + /** + * Restore the storage back into session from an array + * @param Array $sessiondata + */ function restoreSessionData( $sessiondata = NULL ) { $_SESSION["HA::STORE"] = unserialize( $sessiondata ); diff --git a/e107_handlers/hybridauth/Hybrid/StorageInterface.php b/e107_handlers/hybridauth/Hybrid/StorageInterface.php new file mode 100644 index 000000000..d80c1c1c1 --- /dev/null +++ b/e107_handlers/hybridauth/Hybrid/StorageInterface.php @@ -0,0 +1,28 @@ +user = new stdClass(); diff --git a/e107_handlers/hybridauth/Hybrid/User_Contact.php b/e107_handlers/hybridauth/Hybrid/User_Contact.php index 7c6ad8d17..9ee405d12 100644 --- a/e107_handlers/hybridauth/Hybrid/User_Contact.php +++ b/e107_handlers/hybridauth/Hybrid/User_Contact.php @@ -1,8 +1,8 @@ result = $result; - $code = isset($result['error_code']) ? $result['error_code'] : 0; + $code = 0; + if (isset($result['error_code']) && is_int($result['error_code'])) { + $code = $result['error_code']; + } if (isset($result['error_description'])) { // OAuth 2.0 Draft 10 style @@ -120,7 +125,7 @@ abstract class BaseFacebook /** * Version. */ - const VERSION = '3.2.2'; + const VERSION = '3.2.3'; /** * Signed Request Algorithm. @@ -129,6 +134,8 @@ abstract class BaseFacebook /** * Default options for curl. + * + * @var array */ public static $CURL_OPTS = array( CURLOPT_CONNECTTIMEOUT => 10, @@ -140,6 +147,8 @@ abstract class BaseFacebook /** * List of query parameters that get automatically dropped when rebuilding * the current URL. + * + * @var array */ protected static $DROP_QUERY_PARAMS = array( 'code', @@ -149,6 +158,8 @@ abstract class BaseFacebook /** * Maps aliases to Facebook domains. + * + * @var array */ public static $DOMAIN_MAP = array( 'api' => 'https://api.facebook.com/', @@ -182,11 +193,15 @@ abstract class BaseFacebook /** * The data from the signed_request token. + * + * @var string */ protected $signedRequest; /** * A CSRF state variable to assist in the defense against CSRF attacks. + * + * @var string */ protected $state; @@ -212,6 +227,13 @@ abstract class BaseFacebook */ protected $trustForwarded = false; + /** + * Indicates if signed_request is allowed in query parameters. + * + * @var boolean + */ + protected $allowSignedRequest = true; + /** * Initialize a Facebook Application. * @@ -219,6 +241,9 @@ abstract class BaseFacebook * - appId: the application ID * - secret: the application secret * - fileUpload: (optional) boolean indicating if file uploads are enabled + * - allowSignedRequest: (optional) boolean indicating if signed_request is + * allowed in query parameters or POST body. Should be + * false for non-canvas apps. Defaults to true. * * @param array $config The application configuration */ @@ -231,6 +256,10 @@ abstract class BaseFacebook if (isset($config['trustForwarded']) && $config['trustForwarded']) { $this->trustForwarded = true; } + if (isset($config['allowSignedRequest']) + && !$config['allowSignedRequest']) { + $this->allowSignedRequest = false; + } $state = $this->getPersistentData('state'); if (!empty($state)) { $this->state = $state; @@ -241,6 +270,7 @@ abstract class BaseFacebook * Set the Application ID. * * @param string $appId The Application ID + * * @return BaseFacebook */ public function setAppId($appId) { @@ -261,8 +291,10 @@ abstract class BaseFacebook * Set the App Secret. * * @param string $apiSecret The App Secret + * * @return BaseFacebook - * @deprecated + * @deprecated Use setAppSecret instead. + * @see setAppSecret() */ public function setApiSecret($apiSecret) { $this->setAppSecret($apiSecret); @@ -273,6 +305,7 @@ abstract class BaseFacebook * Set the App Secret. * * @param string $appSecret The App Secret + * * @return BaseFacebook */ public function setAppSecret($appSecret) { @@ -284,7 +317,9 @@ abstract class BaseFacebook * Get the App Secret. * * @return string the App Secret - * @deprecated + * + * @deprecated Use getAppSecret instead. + * @see getAppSecret() */ public function getApiSecret() { return $this->getAppSecret(); @@ -303,6 +338,7 @@ abstract class BaseFacebook * Set the file upload support status. * * @param boolean $fileUploadSupport The file upload support status. + * * @return BaseFacebook */ public function setFileUploadSupport($fileUploadSupport) { @@ -320,11 +356,12 @@ abstract class BaseFacebook } /** - * DEPRECATED! Please use getFileUploadSupport instead. - * * Get the file upload support status. * * @return boolean true if and only if the server supports file upload. + * + * @deprecated Use getFileUploadSupport instead. + * @see getFileUploadSupport() */ public function useFileUploadSupport() { return $this->getFileUploadSupport(); @@ -336,6 +373,7 @@ abstract class BaseFacebook * to use it. * * @param string $access_token an access token. + * * @return BaseFacebook */ public function setAccessToken($access_token) { @@ -488,9 +526,10 @@ abstract class BaseFacebook */ public function getSignedRequest() { if (!$this->signedRequest) { - if (!empty($_REQUEST['signed_request'])) { + if ($this->allowSignedRequest && !empty($_REQUEST['signed_request'])) { $this->signedRequest = $this->parseSignedRequest( - $_REQUEST['signed_request']); + $_REQUEST['signed_request'] + ); } else if (!empty($_COOKIE[$this->getSignedRequestCookieName()])) { $this->signedRequest = $this->parseSignedRequest( $_COOKIE[$this->getSignedRequestCookieName()]); @@ -529,6 +568,11 @@ abstract class BaseFacebook if ($signed_request) { if (array_key_exists('user_id', $signed_request)) { $user = $signed_request['user_id']; + + if($user != $this->getPersistentData('user_id')){ + $this->clearAllPersistentData(); + } + $this->setPersistentData('user_id', $signed_request['user_id']); return $user; } @@ -584,11 +628,15 @@ abstract class BaseFacebook return $this->getUrl( 'www', 'dialog/oauth', - array_merge(array( - 'client_id' => $this->getAppId(), - 'redirect_uri' => $currentUrl, // possibly overwritten - 'state' => $this->state), - $params)); + array_merge( + array( + 'client_id' => $this->getAppId(), + 'redirect_uri' => $currentUrl, // possibly overwritten + 'state' => $this->state, + 'sdk' => 'php-sdk-'.self::VERSION + ), + $params + )); } /** @@ -614,24 +662,14 @@ abstract class BaseFacebook /** * Get a login status URL to fetch the status from Facebook. * - * The parameters: - * - ok_session: the URL to go to if a session is found - * - no_session: the URL to go to if the user is not connected - * - no_user: the URL to go to if the user is not signed into facebook - * * @param array $params Provide custom parameters * @return string The URL for the logout flow */ public function getLoginStatusUrl($params=array()) { - return $this->getUrl( - 'www', - 'extern/login_status.php', + return $this->getLoginUrl( array_merge(array( - 'api_key' => $this->getAppId(), - 'no_session' => $this->getCurrentUrl(), - 'no_user' => $this->getCurrentUrl(), - 'ok_session' => $this->getCurrentUrl(), - 'session_version' => 3, + 'response_type' => 'code', + 'display' => 'none', ), $params) ); } @@ -664,7 +702,7 @@ abstract class BaseFacebook } /** - * Constructs and returns the name of the coookie that potentially contain + * Constructs and returns the name of the cookie that potentially contain * metadata. The cookie is not set by the BaseFacebook class, but it may be * set by the JavaScript SDK. * @@ -683,20 +721,16 @@ abstract class BaseFacebook * code could not be determined. */ protected function getCode() { - if (isset($_REQUEST['code'])) { - if ($this->state !== null && - isset($_REQUEST['state']) && - $this->state === $_REQUEST['state']) { - + if (!isset($_REQUEST['code']) || !isset($_REQUEST['state'])) { + return false; + } + if ($this->state === $_REQUEST['state']) { // CSRF state has done its job, so clear it $this->state = null; $this->clearPersistentData('state'); return $_REQUEST['code']; - } else { - self::errorLog('CSRF state token does not match one provided.'); - return false; - } } + self::errorLog('CSRF state token does not match one provided.'); return false; } @@ -727,7 +761,7 @@ abstract class BaseFacebook * @return string The application access token, useful for gathering * public information about users and applications. */ - protected function getApplicationAccessToken() { + public function getApplicationAccessToken() { return $this->appId.'|'.$this->appSecret; } @@ -752,6 +786,8 @@ abstract class BaseFacebook * either logged in to Facebook or has granted an offline access permission. * * @param string $code An authorization code. + * @param string $redirect_uri Optional redirect URI. Default null + * * @return mixed An access token exchanged for the authorization code, or * false if an access token could not be generated. */ @@ -894,9 +930,13 @@ abstract class BaseFacebook $params['access_token'] = $this->getAccessToken(); } + if (isset($params['access_token']) && !isset($params['appsecret_proof'])) { + $params['appsecret_proof'] = $this->getAppSecretProof($params['access_token']); + } + // json_encode all params values that are not strings foreach ($params as $key => $value) { - if (!is_string($value)) { + if (!is_string($value) && !($value instanceof CURLFile)) { $params[$key] = json_encode($value); } } @@ -904,6 +944,19 @@ abstract class BaseFacebook return $this->makeRequest($url, $params); } + /** + * Generate a proof of App Secret + * This is required for all API calls originating from a server + * It is a sha256 hash of the access_token made using the app secret + * + * @param string $access_token The access_token to be hashed (required) + * + * @return string The sha256 hash of the access_token + */ + protected function getAppSecretProof($access_token) { + return hash_hmac('sha256', $access_token, $this->getAppSecret()); + } + /** * Makes an HTTP request. This method can be overridden by subclasses if * developers want to do fancier things or use something other than curl to @@ -941,11 +994,13 @@ abstract class BaseFacebook curl_setopt_array($ch, $opts); $result = curl_exec($ch); - if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT + $errno = curl_errno($ch); + // CURLE_SSL_CACERT || CURLE_SSL_CACERT_BADFILE + if ($errno == 60 || $errno == 77) { self::errorLog('Invalid or no certificate authority found, '. 'using bundled information'); curl_setopt($ch, CURLOPT_CAINFO, - dirname(__FILE__) . '/fb_ca_chain_bundle.crt'); + dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fb_ca_chain_bundle.crt'); $result = curl_exec($ch); } @@ -987,16 +1042,25 @@ abstract class BaseFacebook * Parses a signed_request and validates the signature. * * @param string $signed_request A signed token + * * @return array The payload inside it or null if the sig is wrong */ protected function parseSignedRequest($signed_request) { + + if (!$signed_request || strpos($signed_request, '.') === false) { + self::errorLog('Signed request was invalid!'); + return null; + } + list($encoded_sig, $payload) = explode('.', $signed_request, 2); // decode the data $sig = self::base64UrlDecode($encoded_sig); $data = json_decode(self::base64UrlDecode($payload), true); - if (strtoupper($data['algorithm']) !== self::SIGNED_REQUEST_ALGORITHM) { + if (!isset($data['algorithm']) + || strtoupper($data['algorithm']) !== self::SIGNED_REQUEST_ALGORITHM + ) { self::errorLog( 'Unknown algorithm. Expected ' . self::SIGNED_REQUEST_ALGORITHM); return null; @@ -1005,18 +1069,30 @@ abstract class BaseFacebook // check sig $expected_sig = hash_hmac('sha256', $payload, $this->getAppSecret(), $raw = true); - if ($sig !== $expected_sig) { + + if (strlen($expected_sig) !== strlen($sig)) { self::errorLog('Bad Signed JSON signature!'); return null; } - return $data; + $result = 0; + for ($i = 0; $i < strlen($expected_sig); $i++) { + $result |= ord($expected_sig[$i]) ^ ord($sig[$i]); + } + + if ($result == 0) { + return $data; + } else { + self::errorLog('Bad Signed JSON signature!'); + return null; + } } /** * Makes a signed_request blob using the given data. * - * @param array The data array. + * @param array $data The data array. + * * @return string The signed request. */ protected function makeSignedRequest($data) { @@ -1036,7 +1112,8 @@ abstract class BaseFacebook /** * Build the URL for api given parameters. * - * @param $method String the method name. + * @param string $method The method name. + * * @return string The URL for the given parameters */ protected function getApiUrl($method) { @@ -1113,9 +1190,9 @@ abstract class BaseFacebook /** * Build the URL for given domain alias, path and parameters. * - * @param $name string The name of the domain - * @param $path string Optional path (without a leading slash) - * @param $params array Optional query parameters + * @param string $name The name of the domain + * @param string $path Optional path (without a leading slash) + * @param array $params Optional query parameters * * @return string The URL for the given parameters */ @@ -1134,13 +1211,26 @@ abstract class BaseFacebook return $url; } + /** + * Returns the HTTP Host + * + * @return string The HTTP Host + */ protected function getHttpHost() { if ($this->trustForwarded && isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { - return $_SERVER['HTTP_X_FORWARDED_HOST']; + $forwardProxies = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']); + if (!empty($forwardProxies)) { + return $forwardProxies[0]; + } } return $_SERVER['HTTP_HOST']; } + /** + * Returns the HTTP Protocol + * + * @return string The HTTP Protocol + */ protected function getHttpProtocol() { if ($this->trustForwarded && isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { @@ -1162,7 +1252,9 @@ abstract class BaseFacebook } /** - * Get the base domain used for the cookie. + * Returns the base domain used for the cookie. + * + * @return string The base domain */ protected function getBaseDomain() { // The base domain is stored in the metadata cookie if not we fallback @@ -1175,8 +1267,6 @@ abstract class BaseFacebook return $this->getHttpHost(); } - /** - /** * Returns the Current URL, stripping it of known FB parameters that should * not persist. @@ -1223,13 +1313,14 @@ abstract class BaseFacebook * params that should be stripped out. * * @param string $param A key or key/value pair within a URL's query (e.g. - * 'foo=a', 'foo=', or 'foo'. + * 'foo=a', 'foo=', or 'foo'. * * @return boolean */ protected function shouldRetainParam($param) { foreach (self::$DROP_QUERY_PARAMS as $drop_query_param) { - if (strpos($param, $drop_query_param.'=') === 0) { + if ($param === $drop_query_param || + strpos($param, $drop_query_param.'=') === 0) { return false; } } @@ -1242,7 +1333,7 @@ abstract class BaseFacebook * because the access token is no longer valid. If that is * the case, then we destroy the session. * - * @param $result array A record storing the error message returned + * @param array $result A record storing the error message returned * by a failed API call. */ protected function throwAPIException($result) { @@ -1291,8 +1382,9 @@ abstract class BaseFacebook * _ instead of / * No padded = * - * @param string $input base64UrlEncoded string - * @return string + * @param string $input base64UrlEncoded input + * + * @return string The decoded string */ protected static function base64UrlDecode($input) { return base64_decode(strtr($input, '-_', '+/')); @@ -1304,8 +1396,8 @@ abstract class BaseFacebook * - instead of + * _ instead of / * - * @param string $input string - * @return string base64Url encoded string + * @param string $input The input to encode + * @return string The base64Url encoded input, as a string. */ protected static function base64UrlEncode($input) { $str = strtr(base64_encode($input), '+/', '-_'); @@ -1345,7 +1437,7 @@ abstract class BaseFacebook /** * Parses the metadata cookie that our Javascript API set * - * @return an array mapping key to value + * @return array an array mapping key to value */ protected function getMetadataCookie() { $cookie_name = $this->getMetadataCookieName(); @@ -1373,6 +1465,14 @@ abstract class BaseFacebook return $metadata; } + /** + * Finds whether the given domain is allowed or not + * + * @param string $big The value to be checked against $small + * @param string $small The input string + * + * @return boolean Returns TRUE if $big matches $small + */ protected static function isAllowedDomain($big, $small) { if ($big === $small) { return true; @@ -1380,6 +1480,14 @@ abstract class BaseFacebook return self::endsWith($big, '.'.$small); } + /** + * Checks if $big string ends with $small string + * + * @param string $big The value to be checked against $small + * @param string $small The input string + * + * @return boolean TRUE if $big ends with $small + */ protected static function endsWith($big, $small) { $len = strlen($small); if ($len === 0) { @@ -1423,6 +1531,7 @@ abstract class BaseFacebook * Clear the data with $key from the persistent storage * * @param string $key + * * @return void */ abstract protected function clearPersistentData($key); diff --git a/e107_handlers/hybridauth/Hybrid/thirdparty/Facebook/facebook.php b/e107_handlers/hybridauth/Hybrid/thirdparty/Facebook/facebook.php index a2238ef61..b6b827dc6 100644 --- a/e107_handlers/hybridauth/Hybrid/thirdparty/Facebook/facebook.php +++ b/e107_handlers/hybridauth/Hybrid/thirdparty/Facebook/facebook.php @@ -23,13 +23,22 @@ require_once "base_facebook.php"; */ class Facebook extends BaseFacebook { + /** + * Cookie prefix + */ const FBSS_COOKIE_NAME = 'fbss'; - // We can set this to a high number because the main session - // expiration will trump this. + /** + * We can set this to a high number because the main session + * expiration will trump this. + */ const FBSS_COOKIE_EXPIRE = 31556926; // 1 year - // Stores the shared session ID if one is set. + /** + * Stores the shared session ID if one is set. + * + * @var string + */ protected $sharedSessionID; /** @@ -38,25 +47,45 @@ class Facebook extends BaseFacebook * access token if during the course of execution * we discover them. * - * @param Array $config the application configuration. Additionally + * @param array $config the application configuration. Additionally * accepts "sharedSession" as a boolean to turn on a secondary * cookie for environments with a shared session (that is, your app * shares the domain with other apps). - * @see BaseFacebook::__construct in facebook.php + * + * @see BaseFacebook::__construct */ public function __construct($config) { - if (!session_id()) { + if ((function_exists('session_status') + && session_status() !== PHP_SESSION_ACTIVE) || !session_id()) { session_start(); } parent::__construct($config); if (!empty($config['sharedSession'])) { $this->initSharedSession(); + + // re-load the persisted state, since parent + // attempted to read out of non-shared cookie + $state = $this->getPersistentData('state'); + if (!empty($state)) { + $this->state = $state; + } else { + $this->state = null; + } + } } + /** + * Supported keys for persistent data + * + * @var array + */ protected static $kSupportedKeys = array('state', 'code', 'access_token', 'user_id'); + /** + * Initiates Shared Session + */ protected function initSharedSession() { $cookie_name = $this->getSharedSessionCookieName(); if (isset($_COOKIE[$cookie_name])) { @@ -95,10 +124,16 @@ class Facebook extends BaseFacebook /** * Provides the implementations of the inherited abstract - * methods. The implementation uses PHP sessions to maintain + * methods. The implementation uses PHP sessions to maintain * a store for authorization codes, user ids, CSRF states, and * access tokens. */ + + /** + * {@inheritdoc} + * + * @see BaseFacebook::setPersistentData() + */ protected function setPersistentData($key, $value) { if (!in_array($key, self::$kSupportedKeys)) { self::errorLog('Unsupported key passed to setPersistentData.'); @@ -109,6 +144,11 @@ class Facebook extends BaseFacebook $_SESSION[$session_var_name] = $value; } + /** + * {@inheritdoc} + * + * @see BaseFacebook::getPersistentData() + */ protected function getPersistentData($key, $default = false) { if (!in_array($key, self::$kSupportedKeys)) { self::errorLog('Unsupported key passed to getPersistentData.'); @@ -120,6 +160,11 @@ class Facebook extends BaseFacebook $_SESSION[$session_var_name] : $default; } + /** + * {@inheritdoc} + * + * @see BaseFacebook::clearPersistentData() + */ protected function clearPersistentData($key) { if (!in_array($key, self::$kSupportedKeys)) { self::errorLog('Unsupported key passed to clearPersistentData.'); @@ -127,9 +172,16 @@ class Facebook extends BaseFacebook } $session_var_name = $this->constructSessionVariableName($key); - unset($_SESSION[$session_var_name]); + if (isset($_SESSION[$session_var_name])) { + unset($_SESSION[$session_var_name]); + } } + /** + * {@inheritdoc} + * + * @see BaseFacebook::clearAllPersistentData() + */ protected function clearAllPersistentData() { foreach (self::$kSupportedKeys as $key) { $this->clearPersistentData($key); @@ -139,6 +191,9 @@ class Facebook extends BaseFacebook } } + /** + * Deletes Shared session cookie + */ protected function deleteSharedSessionCookie() { $cookie_name = $this->getSharedSessionCookieName(); unset($_COOKIE[$cookie_name]); @@ -146,10 +201,23 @@ class Facebook extends BaseFacebook setcookie($cookie_name, '', 1, '/', '.'.$base_domain); } + /** + * Returns the Shared session cookie name + * + * @return string The Shared session cookie name + */ protected function getSharedSessionCookieName() { return self::FBSS_COOKIE_NAME . '_' . $this->getAppId(); } + /** + * Constructs and returns the name of the session key. + * + * @see setPersistentData() + * @param string $key The key for which the session variable name to construct. + * + * @return string The name of the session key. + */ protected function constructSessionVariableName($key) { $parts = array('fb', $this->getAppId(), $key); if ($this->sharedSessionID) { diff --git a/e107_handlers/hybridauth/Hybrid/thirdparty/LinkedIn/LinkedIn.php b/e107_handlers/hybridauth/Hybrid/thirdparty/LinkedIn/LinkedIn.php index f67e731c4..2fdaf2df3 100644 --- a/e107_handlers/hybridauth/Hybrid/thirdparty/LinkedIn/LinkedIn.php +++ b/e107_handlers/hybridauth/Hybrid/thirdparty/LinkedIn/LinkedIn.php @@ -2,6 +2,8 @@ // http://code.google.com/p/simple-linkedinphp/ // 3.2.0 - November 29, 2011 // hacked into the code to handel new scope (r_basicprofile+r_emailaddress) - until Paul update linkedinphp library! +// Facyla note 20131219 : this in fact should not be hacked, as Linkedin lets developpers define the wanted scope +// in Linkedin application settings, when creating the (required) application and API access /** * This file defines the 'LinkedIn' class. This class is designed to be a @@ -122,8 +124,8 @@ class LinkedIn { const _URL_ACCESS = 'https://api.linkedin.com/uas/oauth/accessToken'; const _URL_API = 'https://api.linkedin.com'; const _URL_AUTH = 'https://www.linkedin.com/uas/oauth/authenticate?oauth_token='; - // const _URL_REQUEST = 'https://api.linkedin.com/uas/oauth/requestToken'; - const _URL_REQUEST = 'https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile+r_emailaddress+rw_nus'; + const _URL_REQUEST = 'https://api.linkedin.com/uas/oauth/requestToken'; + // const _URL_REQUEST = 'https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile+r_emailaddress+rw_nus+r_network'; const _URL_REVOKE = 'https://api.linkedin.com/uas/oauth/invalidateToken'; // Library version @@ -441,7 +443,7 @@ class LinkedIn { * http://developer.linkedin.com/docs/DOC-1327 * * @param str $cid - * Company ID you want the producte for. + * Company ID you want the product for. * @param str $options * [OPTIONAL] Data retrieval options. * @@ -670,6 +672,10 @@ class LinkedIn { curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_URL, $url); curl_setopt($handle, CURLOPT_VERBOSE, FALSE); + + if ( isset ( Hybrid_Auth::$config["proxy"] ) ) { + curl_setopt($handle, CURLOPT_PROXY, Hybrid_Auth::$config["proxy"]); + } // configure the header we are sending to LinkedIn - http://developer.linkedin.com/docs/DOC-1203 $header = array($oauth_req->to_header(self::_API_OAUTH_REALM)); @@ -696,6 +702,9 @@ class LinkedIn { // gather the response $return_data['linkedin'] = curl_exec($handle); + if( $return_data['linkedin'] === FALSE ) { + Hybrid_Logger::error( "LinkedIn::fetch(). curl_exec error: ", curl_error($ch) ); + } $return_data['info'] = curl_getinfo($handle); $return_data['oauth']['header'] = $oauth_req->to_header(self::_API_OAUTH_REALM); $return_data['oauth']['string'] = $oauth_req->base_string; @@ -2056,10 +2065,10 @@ class LinkedIn { * The group id. * @param str $xml * The group settings to set. The settings are: - * - + * - * - * - - * - + * - * - * - * @@ -2255,7 +2264,7 @@ class LinkedIn { // send request $response = $this->fetch('POST', $share_url, $data); } else { - // data contraints/rules not met, raise an exception + // data constraints/rules not met, raise an exception throw new LinkedInException('LinkedIn->share(): sharing data constraints not met; check that you have supplied valid content and combinations of content to share.'); } } else { @@ -2601,7 +2610,7 @@ class LinkedIn { public static function xmlToArray($xml) { // check passed data if(!is_string($xml)) { - // bad data possed + // bad data passed throw new LinkedInException('LinkedIn->xmlToArray(): bad data passed, $xml must be a non-zero length string.'); } diff --git a/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php b/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php index 976ced7b5..c97b61139 100644 --- a/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php +++ b/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php @@ -1,14 +1,15 @@ parameters as $k => $v) { if (substr($k, 0, 5) != "oauth") continue; if (is_array($v)) { - throw new OAuthExceptionPHP('Arrays not supported in headers'); + throw new OAuthException('Arrays not supported in headers'); } $out .= ($first) ? ' ' : ','; $out .= OAuthUtil::urlencode_rfc3986($k) . @@ -580,7 +584,7 @@ class OAuthServer { $version = '1.0'; } if ($version !== $this->version) { - throw new OAuthExceptionPHP("OAuth version '$version' not supported"); + throw new OAuthException("OAuth version '$version' not supported"); } return $version; } @@ -596,12 +600,12 @@ class OAuthServer { if (!$signature_method) { // According to chapter 7 ("Accessing Protected Ressources") the signature-method // parameter is required, and we can't just fallback to PLAINTEXT - throw new OAuthExceptionPHP('No signature method parameter. This parameter is required'); + throw new OAuthException('No signature method parameter. This parameter is required'); } if (!in_array($signature_method, array_keys($this->signature_methods))) { - throw new OAuthExceptionPHP( + throw new OAuthException( "Signature method '$signature_method' not supported " . "try one of the following: " . implode(", ", array_keys($this->signature_methods)) @@ -619,12 +623,12 @@ class OAuthServer { : NULL; if (!$consumer_key) { - throw new OAuthExceptionPHP("Invalid consumer key"); + throw new OAuthException("Invalid consumer key"); } $consumer = $this->data_store->lookup_consumer($consumer_key); if (!$consumer) { - throw new OAuthExceptionPHP("Invalid consumer"); + throw new OAuthException("Invalid consumer"); } return $consumer; @@ -642,7 +646,7 @@ class OAuthServer { $consumer, $token_type, $token_field ); if (!$token) { - throw new OAuthExceptionPHP("Invalid $token_type token: $token_field"); + throw new OAuthException("Invalid $token_type token: $token_field"); } return $token; } @@ -674,7 +678,7 @@ class OAuthServer { ); if (!$valid_sig) { - throw new OAuthExceptionPHP("Invalid signature"); + throw new OAuthException("Invalid signature"); } } @@ -683,14 +687,14 @@ class OAuthServer { */ private function check_timestamp($timestamp) { if( ! $timestamp ) - throw new OAuthExceptionPHP( + throw new OAuthException( 'Missing timestamp parameter. The parameter is required' ); // verify that timestamp is recentish $now = time(); if (abs($now - $timestamp) > $this->timestamp_threshold) { - throw new OAuthExceptionPHP( + throw new OAuthException( "Expired timestamp, yours $timestamp, ours $now" ); } @@ -701,7 +705,7 @@ class OAuthServer { */ private function check_nonce($consumer, $token, $nonce, $timestamp) { if( ! $nonce ) - throw new OAuthExceptionPHP( + throw new OAuthException( 'Missing nonce parameter. The parameter is required' ); @@ -713,7 +717,7 @@ class OAuthServer { $timestamp ); if ($found) { - throw new OAuthExceptionPHP("Nonce already used: $nonce"); + throw new OAuthException("Nonce already used: $nonce"); } } diff --git a/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth1Client.php b/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth1Client.php index 4c6dc52c5..bd9567d9f 100644 --- a/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth1Client.php +++ b/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth1Client.php @@ -1,8 +1,8 @@ api($url, 'GET', $parameters); + return $this->api($url, 'GET', $parameters, NULL, $content_type); } /** - * POST wreapper for provider apis request + * POST wrapper for provider apis request */ - function post($url, $parameters = array()) + function post($url, $parameters = array(), $body = NULL, $content_type = NULL, $multipart = false) { - return $this->api($url, 'POST', $parameters); + return $this->api($url, 'POST', $parameters, $body, $content_type, $multipart ); } /** * Format and sign an oauth for provider api */ - function api( $url, $method = 'GET', $parameters = array() ) + function api( $url, $method = 'GET', $parameters = array(), $body = NULL, $content_type = NULL, $multipart = false ) { if ( strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0 ) { $url = $this->api_base_url . $url; } - $response = $this->signedRequest( $url, $method, $parameters ); + $response = $this->signedRequest( $url, $method, $parameters, $body, $content_type, $multipart ); if( $this->decode_json ){ $response = json_decode( $response ); @@ -144,20 +144,34 @@ class OAuth1Client{ /** * Make signed request */ - function signedRequest( $url, $method, $parameters ) + function signedRequest( $url, $method, $parameters, $body = NULL, $content_type = NULL, $multipart = false ) { - $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters); + + $signature_parameters = array(); + + // when making a multipart request, use only oauth_* keys for signature + foreach( $parameters AS $key => $value ){ + if( !$multipart || strpos( $key, 'oauth_' ) === 0 ){ + $signature_parameters[$key] = $value; + } + } + + $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $signature_parameters); $request->sign_request($this->sha1_method, $this->consumer, $this->token); switch ($method) { - case 'GET': return $this->request( $request->to_url(), 'GET' ); - default : return $this->request( $request->get_normalized_http_url(), $method, $request->to_postdata(), $request->to_header() ) ; + case 'GET': return $this->request( $request->to_url(), 'GET', NULL, NULL, $content_type ); + default : + if ($body) + return $this->request( $request->to_url(), $method, $body, $request->to_header(), $content_type ); + else + return $this->request( $request->get_normalized_http_url(), $method, ($multipart ? $parameters : $request->to_postdata()), $request->to_header(), $content_type, $multipart ) ; } } /** * Make http request */ - function request( $url, $method, $postfields = NULL, $auth_header = null ) + function request( $url, $method, $postfields = NULL, $auth_header = NULL, $content_type = NULL, $multipart = false ) { Hybrid_Logger::info( "Enter OAuth1Client::request( $method, $url )" ); Hybrid_Logger::debug( "OAuth1Client::request(). dump post fields: ", serialize( $postfields ) ); @@ -174,6 +188,12 @@ class OAuth1Client{ curl_setopt( $ci, CURLOPT_SSL_VERIFYPEER, $this->curl_ssl_verifypeer ); curl_setopt( $ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader') ); curl_setopt( $ci, CURLOPT_HEADER , FALSE ); + + if( $multipart ){ + curl_setopt( $ci, CURLOPT_HTTPHEADER, array( 'Expect:', $auth_header ) ); + + }elseif ($content_type) + curl_setopt( $ci, CURLOPT_HTTPHEADER, array('Expect:', "Content-Type: $content_type") ); if($this->curl_proxy){ curl_setopt( $ci, CURLOPT_PROXY , $this->curl_proxy); @@ -187,7 +207,7 @@ class OAuth1Client{ curl_setopt( $ci, CURLOPT_POSTFIELDS, $postfields ); } - if ( !empty($auth_header) && $this->curl_auth_header ){ + if ( !empty($auth_header) && $this->curl_auth_header && !$multipart ){ curl_setopt( $ci, CURLOPT_HTTPHEADER, array( 'Content-Type: application/atom+xml', $auth_header ) ); } break; @@ -200,6 +220,10 @@ class OAuth1Client{ curl_setopt($ci, CURLOPT_URL, $url); $response = curl_exec($ci); + if( $response === FALSE ) { + Hybrid_Logger::error( "OAuth1Client::request(). curl_exec error: ", curl_error($ci) ); + } + Hybrid_Logger::debug( "OAuth1Client::request(). dump request info: ", serialize( curl_getinfo($ci) ) ); Hybrid_Logger::debug( "OAuth1Client::request(). dump request result: ", serialize( $response ) ); diff --git a/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth2Client.php b/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth2Client.php index 31bfac948..a321ae7da 100644 --- a/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth2Client.php +++ b/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth2Client.php @@ -1,8 +1,8 @@ $v ) $params[$k] = $v; - return $this->authorize_url . "?" . http_build_query( $params ); + return $this->authorize_url . "?" . http_build_query($params, '', '&'); } public function authenticate( $code ) @@ -146,7 +147,7 @@ class OAuth2Client } /** - * GET wrappwer for provider apis request + * GET wrapper for provider apis request */ function get( $url, $parameters = array() ) { @@ -154,7 +155,7 @@ class OAuth2Client } /** - * POST wreapper for provider apis request + * POST wrapper for provider apis request */ function post( $url, $parameters = array() ) { @@ -194,7 +195,7 @@ class OAuth2Client Hybrid_Logger::debug( "OAuth2Client::request(). dump request params: ", serialize( $params ) ); if( $type == "GET" ){ - $url = $url . ( strpos( $url, '?' ) ? '&' : '?' ) . http_build_query( $params ); + $url = $url . ( strpos( $url, '?' ) ? '&' : '?' ) . http_build_query($params, '', '&'); } $this->http_info = array(); @@ -206,6 +207,7 @@ class OAuth2Client curl_setopt($ch, CURLOPT_USERAGENT , $this->curl_useragent ); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT , $this->curl_connect_time_out ); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER , $this->curl_ssl_verifypeer ); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST , $this->curl_ssl_verifyhost ); curl_setopt($ch, CURLOPT_HTTPHEADER , $this->curl_header ); if($this->curl_proxy){ @@ -218,6 +220,9 @@ class OAuth2Client } $response = curl_exec($ch); + if( $response === FALSE ) { + Hybrid_Logger::error( "OAuth2Client::request(). curl_exec error: ", curl_error($ch) ); + } Hybrid_Logger::debug( "OAuth2Client::request(). dump request info: ", serialize( curl_getinfo($ch) ) ); Hybrid_Logger::debug( "OAuth2Client::request(). dump request result: ", serialize( $response ) ); @@ -233,11 +238,11 @@ class OAuth2Client { if( json_decode( $result ) ) return json_decode( $result ); - parse_str( $result, $ouput ); + parse_str( $result, $output ); $result = new StdClass(); - foreach( $ouput as $k => $v ) + foreach( $output as $k => $v ) $result->$k = $v; return $result; diff --git a/e107_handlers/hybridauth/Hybrid/thirdparty/OpenID/LightOpenID.php b/e107_handlers/hybridauth/Hybrid/thirdparty/OpenID/LightOpenID.php index 2da4b30e5..a43cb1cba 100644 --- a/e107_handlers/hybridauth/Hybrid/thirdparty/OpenID/LightOpenID.php +++ b/e107_handlers/hybridauth/Hybrid/thirdparty/OpenID/LightOpenID.php @@ -49,7 +49,7 @@ class LightOpenID $this->trustRoot = (strpos($host, '://') ? $host : 'https://' . $host); } - if(($host_end = strpos($this->trustRoot, '/', 8)) !== false) { + if(strlen($this->trustRoot >= 8) && ($host_end = strpos($this->trustRoot, '/', 8)) !== false) { $this->trustRoot = substr($this->trustRoot, 0, $host_end); } @@ -204,6 +204,9 @@ class LightOpenID curl_setopt($curl, CURLOPT_HTTPGET, true); } $response = curl_exec($curl); + if( $response === FALSE ) { + Hybrid_Logger::error( "LightOpenID::request_curl(). curl_exec error: ", curl_error($curl) ); + } if($method == 'HEAD' && curl_getinfo($curl, CURLINFO_HTTP_CODE) == 405) { curl_setopt($curl, CURLOPT_HTTPGET, true); @@ -626,7 +629,7 @@ class LightOpenID { $params = array(); # We always use SREG 1.1, even if the server is advertising only support for 1.0. - # That's because it's fully backwards compatibile with 1.0, and some providers + # That's because it's fully backwards compatible with 1.0, and some providers # advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1'; if ($this->required) { @@ -676,7 +679,7 @@ class LightOpenID $params['openid.ax.count.' . $alias] = $count; } - # Don't send empty ax.requied and ax.if_available. + # Don't send empty ax.required and ax.if_available. # Google and possibly other providers refuse to support ax when one of these is empty. if($required) { $params['openid.ax.required'] = implode(',', $required); @@ -809,7 +812,7 @@ class LightOpenID if ($this->data['openid_return_to'] != $this->returnUrl) { # The return_to url must match the url of current request. - # I'm assuing that noone will set the returnUrl to something that doesn't make sense. + # I'm assuming that no one will set the returnUrl to something that doesn't make sense. return false; } @@ -818,7 +821,7 @@ class LightOpenID foreach (explode(',', $this->data['openid_signed']) as $item) { # Checking whether magic_quotes_gpc is turned on, because # the function may fail if it is. For example, when fetching - # AX namePerson, it might containg an apostrophe, which will be escaped. + # AX namePerson, it might contain an apostrophe, which will be escaped. # In such case, validation would fail, since we'd send different data than OP # wants to verify. stripslashes() should solve that problem, but we can't # use it when magic_quotes is off. @@ -900,7 +903,7 @@ class LightOpenID } /** - * Gets AX/SREG attributes provided by OP. should be used only after successful validaton. + * Gets AX/SREG attributes provided by OP. should be used only after successful validation. * Note that it does not guarantee that any of the required/optional parameters will be present, * or that there will be no other attributes besides those specified. * In other words. OP may provide whatever information it wants to. diff --git a/e107_handlers/hybridauth/index.php b/e107_handlers/hybridauth/index.php index 5b60cea04..a27a01913 100644 --- a/e107_handlers/hybridauth/index.php +++ b/e107_handlers/hybridauth/index.php @@ -1,8 +1,8 @@