721 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			721 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * The default Cache Lifetime (in seconds).
 | |
|  */
 | |
| define("OAUTH2_DEFAULT_EXPIRES_IN", 3600);
 | |
| 
 | |
| /**
 | |
|  * The default Base domain for the Cookie.
 | |
|  */
 | |
| define("OAUTH2_DEFAULT_BASE_DOMAIN", '');
 | |
| 
 | |
| /**
 | |
|  * OAuth2.0 draft v10 client-side implementation.
 | |
|  *
 | |
|  * @author Originally written by Naitik Shah <naitik@facebook.com>.
 | |
|  * @author Update to draft v10 by Edison Wong <hswong3i@pantarei-design.com>.
 | |
|  *
 | |
|  * @sa <a href="https://github.com/facebook/php-sdk">Facebook PHP SDK</a>.
 | |
|  */
 | |
| abstract class OAuth2Client {
 | |
| 
 | |
|   /**
 | |
|    * Array of persistent variables stored.
 | |
|    */
 | |
|   protected $conf = array();
 | |
| 
 | |
|   /**
 | |
|    * Returns a persistent variable.
 | |
|    *
 | |
|    * To avoid problems, always use lower case for persistent variable names.
 | |
|    *
 | |
|    * @param $name
 | |
|    *   The name of the variable to return.
 | |
|    * @param $default
 | |
|    *   The default value to use if this variable has never been set.
 | |
|    *
 | |
|    * @return
 | |
|    *   The value of the variable.
 | |
|    */
 | |
|   public function getVariable($name, $default = NULL) {
 | |
|     return isset($this->conf[$name]) ? $this->conf[$name] : $default;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets a persistent variable.
 | |
|    *
 | |
|    * To avoid problems, always use lower case for persistent variable names.
 | |
|    *
 | |
|    * @param $name
 | |
|    *   The name of the variable to set.
 | |
|    * @param $value
 | |
|    *   The value to set.
 | |
|    */
 | |
|   public function setVariable($name, $value) {
 | |
|     $this->conf[$name] = $value;
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   // Stuff that should get overridden by subclasses.
 | |
|   //
 | |
|   // I don't want to make these abstract, because then subclasses would have
 | |
|   // to implement all of them, which is too much work.
 | |
|   //
 | |
|   // So they're just stubs. Override the ones you need.
 | |
| 
 | |
|   /**
 | |
|    * Initialize a Drupal OAuth2.0 Application.
 | |
|    *
 | |
|    * @param $config
 | |
|    *   An associative array as below:
 | |
|    *   - base_uri: The base URI for the OAuth2.0 endpoints.
 | |
|    *   - code: (optional) The authorization code.
 | |
|    *   - username: (optional) The username.
 | |
|    *   - password: (optional) The password.
 | |
|    *   - client_id: (optional) The application ID.
 | |
|    *   - client_secret: (optional) The application secret.
 | |
|    *   - authorize_uri: (optional) The end-user authorization endpoint URI.
 | |
|    *   - access_token_uri: (optional) The token endpoint URI.
 | |
|    *   - services_uri: (optional) The services endpoint URI.
 | |
|    *   - cookie_support: (optional) TRUE to enable cookie support.
 | |
|    *   - base_domain: (optional) The domain for the cookie.
 | |
|    *   - file_upload_support: (optional) TRUE if file uploads are enabled.
 | |
|    */
 | |
|   public function __construct($config = array()) {
 | |
|     // We must set base_uri first.
 | |
|     $this->setVariable('base_uri', $config['base_uri']);
 | |
|     unset($config['base_uri']);
 | |
| 
 | |
|     // Use predefined OAuth2.0 params, or get it from $_REQUEST.
 | |
|     foreach (array('code', 'username', 'password') as $name) {
 | |
|       if (isset($config[$name]))
 | |
|         $this->setVariable($name, $config[$name]);
 | |
|       else if (isset($_REQUEST[$name]) && !empty($_REQUEST[$name]))
 | |
|         $this->setVariable($name, $_REQUEST[$name]);
 | |
|       unset($config[$name]);
 | |
|     }
 | |
| 
 | |
|     // Endpoint URIs.
 | |
|     foreach (array('authorize_uri', 'access_token_uri', 'services_uri') as $name) {
 | |
|       if (isset($config[$name]))
 | |
|         if (substr($config[$name], 0, 4) == "http")
 | |
|           $this->setVariable($name, $config[$name]);
 | |
|         else
 | |
|           $this->setVariable($name, $this->getVariable('base_uri') . $config[$name]);
 | |
|       unset($config[$name]);
 | |
|     }
 | |
| 
 | |
|     // Other else configurations.
 | |
|     foreach ($config as $name => $value) {
 | |
|       $this->setVariable($name, $value);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Try to get session object from custom method.
 | |
|    *
 | |
|    * By default we generate session object based on access_token response, or
 | |
|    * if it is provided from server with $_REQUEST. For sure, if it is provided
 | |
|    * by server it should follow our session object format.
 | |
|    *
 | |
|    * Session object provided by server can ensure the correct expirse and
 | |
|    * base_domain setup as predefined in server, also you may get more useful
 | |
|    * information for custom functionality, too. BTW, this may require for
 | |
|    * additional remote call overhead.
 | |
|    *
 | |
|    * You may wish to override this function with your custom version due to
 | |
|    * your own server-side implementation.
 | |
|    *
 | |
|    * @param $access_token
 | |
|    *   (optional) A valid access token in associative array as below:
 | |
|    *   - access_token: A valid access_token generated by OAuth2.0
 | |
|    *     authorization endpoint.
 | |
|    *   - expires_in: (optional) A valid expires_in generated by OAuth2.0
 | |
|    *     authorization endpoint.
 | |
|    *   - refresh_token: (optional) A valid refresh_token generated by OAuth2.0
 | |
|    *     authorization endpoint.
 | |
|    *   - scope: (optional) A valid scope generated by OAuth2.0
 | |
|    *     authorization endpoint.
 | |
|    *
 | |
|    *  @return
 | |
|    *    A valid session object in associative array for setup cookie, and
 | |
|    *    NULL if not able to generate it with custom method.
 | |
|    */
 | |
|   protected function getSessionObject($access_token = NULL) {
 | |
|     $session = NULL;
 | |
| 
 | |
|     // Try generate local version of session cookie.
 | |
|     if (!empty($access_token) && isset($access_token['access_token'])) {
 | |
|       $session['access_token'] = $access_token['access_token'];
 | |
|       $session['base_domain'] = $this->getVariable('base_domain', OAUTH2_DEFAULT_BASE_DOMAIN);
 | |
|       $session['expirse'] = isset($access_token['expires_in']) ? time() + $access_token['expires_in'] : time() + $this->getVariable('expires_in', OAUTH2_DEFAULT_EXPIRES_IN);
 | |
|       $session['refresh_token'] = isset($access_token['refresh_token']) ? $access_token['refresh_token'] : '';
 | |
|       $session['scope'] = isset($access_token['scope']) ? $access_token['scope'] : '';
 | |
|       $session['secret'] = md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid())));
 | |
| 
 | |
|       // Provide our own signature.
 | |
|       $sig = self::generateSignature(
 | |
|         $session,
 | |
|         $this->getVariable('client_secret')
 | |
|       );
 | |
|       $session['sig'] = $sig;
 | |
|     }
 | |
| 
 | |
|     // Try loading session from $_REQUEST.
 | |
|     if (!$session && isset($_REQUEST['session'])) {
 | |
|       $session = json_decode(
 | |
|         get_magic_quotes_gpc()
 | |
|           ? stripslashes($_REQUEST['session'])
 | |
|           : $_REQUEST['session'],
 | |
|         TRUE
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     return $session;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Make an API call.
 | |
|    *
 | |
|    * Support both OAuth2.0 or normal GET/POST API call, with relative
 | |
|    * or absolute URI.
 | |
|    *
 | |
|    * If no valid OAuth2.0 access token found in session object, this function
 | |
|    * will automatically switch as normal remote API call without "oauth_token"
 | |
|    * parameter.
 | |
|    *
 | |
|    * Assume server reply in JSON object and always decode during return. If
 | |
|    * you hope to issue a raw query, please use makeRequest().
 | |
|    *
 | |
|    * @param $path
 | |
|    *   The target path, relative to base_path/service_uri or an absolute URI.
 | |
|    * @param $method
 | |
|    *   (optional) The HTTP method (default 'GET').
 | |
|    * @param $params
 | |
|    *   (optional The GET/POST parameters.
 | |
|    *
 | |
|    * @return
 | |
|    *   The JSON decoded response object.
 | |
|    *
 | |
|    * @throws OAuth2Exception
 | |
|    */
 | |
|   public function api($path, $method = 'GET', $params = array()) {
 | |
|     if (is_array($method) && empty($params)) {
 | |
|       $params = $method;
 | |
|       $method = 'GET';
 | |
|     }
 | |
| 
 | |
|     // json_encode all params values that are not strings.
 | |
|     foreach ($params as $key => $value) {
 | |
|       if (!is_string($value)) {
 | |
|         $params[$key] = json_encode($value);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     $result = json_decode($this->makeOAuth2Request(
 | |
|       $this->getUri($path),
 | |
|       $method,
 | |
|       $params
 | |
|     ), TRUE);
 | |
| 
 | |
|     // Results are returned, errors are thrown.
 | |
|     if (is_array($result) && isset($result['error'])) {
 | |
|       $e = new OAuth2Exception($result);
 | |
|       switch ($e->getType()) {
 | |
|         // OAuth 2.0 Draft 10 style.
 | |
|         case 'invalid_token':
 | |
|           $this->setSession(NULL);
 | |
|         default:
 | |
|           $this->setSession(NULL);
 | |
|       }
 | |
|       throw $e;
 | |
|     }
 | |
|     return $result;
 | |
|   }
 | |
| 
 | |
|   // End stuff that should get overridden.
 | |
| 
 | |
|   /**
 | |
|    * Default options for cURL.
 | |
|    */
 | |
|   public static $CURL_OPTS = array(
 | |
|     CURLOPT_CONNECTTIMEOUT => 10,
 | |
|     CURLOPT_RETURNTRANSFER => TRUE,
 | |
|     CURLOPT_HEADER         => TRUE,
 | |
|     CURLOPT_TIMEOUT        => 60,
 | |
|     CURLOPT_USERAGENT      => 'oauth2-draft-v10',
 | |
|     CURLOPT_HTTPHEADER     => array("Accept: application/json"),
 | |
|   );
 | |
| 
 | |
|   /**
 | |
|    * Set the Session.
 | |
|    *
 | |
|    * @param $session
 | |
|    *   (optional) The session object to be set. NULL if hope to frush existing
 | |
|    *   session object.
 | |
|    * @param $write_cookie
 | |
|    *   (optional) TRUE if a cookie should be written. This value is ignored
 | |
|    *   if cookie support has been disabled.
 | |
|    *
 | |
|    * @return
 | |
|    *   The current OAuth2.0 client-side instance.
 | |
|    */
 | |
|   public function setSession($session = NULL, $write_cookie = TRUE) {
 | |
|     $this->setVariable('_session', $this->validateSessionObject($session));
 | |
|     $this->setVariable('_session_loaded', TRUE);
 | |
|     if ($write_cookie) {
 | |
|       $this->setCookieFromSession($this->getVariable('_session'));
 | |
|     }
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get the session object.
 | |
|    *
 | |
|    * This will automatically look for a signed session via custom method,
 | |
|    * OAuth2.0 grant type with authorization_code, OAuth2.0 grant type with
 | |
|    * password, or cookie that we had already setup.
 | |
|    *
 | |
|    * @return
 | |
|    *   The valid session object with OAuth2.0 infomration, and NULL if not
 | |
|    *   able to discover any cases.
 | |
|    */
 | |
|   public function getSession() {
 | |
|     if (!$this->getVariable('_session_loaded')) {
 | |
|       $session = NULL;
 | |
|       $write_cookie = TRUE;
 | |
| 
 | |
|       // Try obtain login session by custom method.
 | |
|       $session = $this->getSessionObject(NULL);
 | |
|       $session = $this->validateSessionObject($session);
 | |
| 
 | |
|       // grant_type == authorization_code.
 | |
|       if (!$session && $this->getVariable('code')) {
 | |
|         $access_token = $this->getAccessTokenFromAuthorizationCode($this->getVariable('code'));
 | |
|         $session = $this->getSessionObject($access_token);
 | |
|         $session = $this->validateSessionObject($session);
 | |
|       }
 | |
| 
 | |
|       // grant_type == password.
 | |
|       if (!$session && $this->getVariable('username') && $this->getVariable('password')) {
 | |
|         $access_token = $this->getAccessTokenFromPassword($this->getVariable('username'), $this->getVariable('password'));
 | |
|         $session = $this->getSessionObject($access_token);
 | |
|         $session = $this->validateSessionObject($session);
 | |
|       }
 | |
| 
 | |
|       // Try loading session from cookie if necessary.
 | |
|       if (!$session && $this->getVariable('cookie_support')) {
 | |
|         $cookie_name = $this->getSessionCookieName();
 | |
|         if (isset($_COOKIE[$cookie_name])) {
 | |
|           $session = array();
 | |
|           parse_str(trim(
 | |
|             get_magic_quotes_gpc()
 | |
|               ? stripslashes($_COOKIE[$cookie_name])
 | |
|               : $_COOKIE[$cookie_name],
 | |
|             '"'
 | |
|           ), $session);
 | |
|           $session = $this->validateSessionObject($session);
 | |
|           // Write only if we need to delete a invalid session cookie.
 | |
|           $write_cookie = empty($session);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       $this->setSession($session, $write_cookie);
 | |
|     }
 | |
| 
 | |
|     return $this->getVariable('_session');
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets an OAuth2.0 access token from session.
 | |
|    *
 | |
|    * This will trigger getSession() and so we MUST initialize with required
 | |
|    * configuration.
 | |
|    *
 | |
|    * @return
 | |
|    *   The valid OAuth2.0 access token, and NULL if not exists in session.
 | |
|    */
 | |
|   public function getAccessToken() {
 | |
|     $session = $this->getSession();
 | |
|     return isset($session['access_token']) ? $session['access_token'] : NULL;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get access token from OAuth2.0 token endpoint with authorization code.
 | |
|    *
 | |
|    * This function will only be activated if both access token URI, client
 | |
|    * identifier and client secret are setup correctly.
 | |
|    *
 | |
|    * @param $code
 | |
|    *   Authorization code issued by authorization server's authorization
 | |
|    *   endpoint.
 | |
|    *
 | |
|    * @return
 | |
|    *   A valid OAuth2.0 JSON decoded access token in associative array, and
 | |
|    *   NULL if not enough parameters or JSON decode failed.
 | |
|    */
 | |
|   private function getAccessTokenFromAuthorizationCode($code) {
 | |
|     if ($this->getVariable('access_token_uri') && $this->getVariable('client_id') && $this->getVariable('client_secret')) {
 | |
|       return json_decode($this->makeRequest(
 | |
|         $this->getVariable('access_token_uri'),
 | |
|         'POST',
 | |
|         array(
 | |
|           'grant_type' => 'authorization_code',
 | |
|           'client_id' => $this->getVariable('client_id'),
 | |
|           'client_secret' => $this->getVariable('client_secret'),
 | |
|           'code' => $code,
 | |
|           'redirect_uri' => $this->getCurrentUri(),
 | |
|         )
 | |
|       ), TRUE);
 | |
|     }
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get access token from OAuth2.0 token endpoint with basic user
 | |
|    * credentials.
 | |
|    *
 | |
|    * This function will only be activated if both username and password
 | |
|    * are setup correctly.
 | |
|    *
 | |
|    * @param $username
 | |
|    *   Username to be check with.
 | |
|    * @param $password
 | |
|    *   Password to be check with.
 | |
|    *
 | |
|    * @return
 | |
|    *   A valid OAuth2.0 JSON decoded access token in associative array, and
 | |
|    *   NULL if not enough parameters or JSON decode failed.
 | |
|    */
 | |
|   private function getAccessTokenFromPassword($username, $password) {
 | |
|     if ($this->getVariable('access_token_uri') && $this->getVariable('client_id') && $this->getVariable('client_secret')) {
 | |
|       return json_decode($this->makeRequest(
 | |
|         $this->getVariable('access_token_uri'),
 | |
|         'POST',
 | |
|         array(
 | |
|           'grant_type' => 'password',
 | |
|           'client_id' => $this->getVariable('client_id'),
 | |
|           'client_secret' => $this->getVariable('client_secret'),
 | |
|           'username' => $username,
 | |
|           'password' => $password,
 | |
|         )
 | |
|       ), TRUE);
 | |
|     }
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Make an OAuth2.0 Request.
 | |
|    *
 | |
|    * Automatically append "oauth_token" in query parameters if not yet
 | |
|    * exists and able to discover a valid access token from session. Otherwise
 | |
|    * just ignore setup with "oauth_token" and handle the API call AS-IS, and
 | |
|    * so may issue a plain API call without OAuth2.0 protection.
 | |
|    *
 | |
|    * @param $path
 | |
|    *   The target path, relative to base_path/service_uri or an absolute URI.
 | |
|    * @param $method
 | |
|    *   (optional) The HTTP method (default 'GET').
 | |
|    * @param $params
 | |
|    *   (optional The GET/POST parameters.
 | |
|    *
 | |
|    * @return
 | |
|    *   The JSON decoded response object.
 | |
|    *
 | |
|    * @throws OAuth2Exception
 | |
|    */
 | |
|   protected function makeOAuth2Request($path, $method = 'GET', $params = array()) {
 | |
|     if ((!isset($params['oauth_token']) || empty($params['oauth_token'])) && $oauth_token = $this->getAccessToken()) {
 | |
|       $params['oauth_token'] = $oauth_token;
 | |
|     }
 | |
|     return $this->makeRequest($path, $method, $params);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Makes an HTTP request.
 | |
|    *
 | |
|    * This method can be overriden by subclasses if developers want to do
 | |
|    * fancier things or use something other than cURL to make the request.
 | |
|    *
 | |
|    * @param $path
 | |
|    *   The target path, relative to base_path/service_uri or an absolute URI.
 | |
|    * @param $method
 | |
|    *   (optional) The HTTP method (default 'GET').
 | |
|    * @param $params
 | |
|    *   (optional The GET/POST parameters.
 | |
|    * @param $ch
 | |
|    *   (optional) An initialized curl handle
 | |
|    *
 | |
|    * @return
 | |
|    *   The JSON decoded response object.
 | |
|    */
 | |
|   protected function makeRequest($path, $method = 'GET', $params = array(), $ch = NULL) {
 | |
|     if (!$ch)
 | |
|       $ch = curl_init();
 | |
| 
 | |
|     $opts = self::$CURL_OPTS;
 | |
|     if ($params) {
 | |
|       switch ($method) {
 | |
|         case 'GET':
 | |
|           $path .= '?' . http_build_query($params, NULL, '&');
 | |
|           break;
 | |
|         // Method override as we always do a POST.
 | |
|         default:
 | |
|           if ($this->getVariable('file_upload_support')) {
 | |
|             $opts[CURLOPT_POSTFIELDS] = $params;
 | |
|           }
 | |
|           else {
 | |
|             $opts[CURLOPT_POSTFIELDS] = http_build_query($params, NULL, '&');
 | |
|           }
 | |
|       }
 | |
|     }
 | |
|     $opts[CURLOPT_URL] = $path;
 | |
| 
 | |
|     // Disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
 | |
|     // for 2 seconds if the server does not support this header.
 | |
|     if (isset($opts[CURLOPT_HTTPHEADER])) {
 | |
|       $existing_headers = $opts[CURLOPT_HTTPHEADER];
 | |
|       $existing_headers[] = 'Expect:';
 | |
|       $opts[CURLOPT_HTTPHEADER] = $existing_headers;
 | |
|     }
 | |
|     else {
 | |
|       $opts[CURLOPT_HTTPHEADER] = array('Expect:');
 | |
|     }
 | |
| 
 | |
|     curl_setopt_array($ch, $opts);
 | |
|     $result = curl_exec($ch);
 | |
| 
 | |
|     if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT
 | |
|       error_log('Invalid or no certificate authority found, using bundled information');
 | |
|       curl_setopt($ch, CURLOPT_CAINFO,
 | |
|                   dirname(__FILE__) . '/fb_ca_chain_bundle.crt');
 | |
|       $result = curl_exec($ch);
 | |
|     }
 | |
| 
 | |
|     if ($result === FALSE) {
 | |
|       $e = new OAuth2Exception(array(
 | |
|         'code' => curl_errno($ch),
 | |
|         'message' => curl_error($ch),
 | |
|       ));
 | |
|       curl_close($ch);
 | |
|       throw $e;
 | |
|     }
 | |
|     curl_close($ch);
 | |
| 
 | |
|     // Split the HTTP response into header and body.
 | |
|     list($headers, $body) = explode("\r\n\r\n", $result);
 | |
|     $headers = explode("\r\n", $headers);
 | |
| 
 | |
|     // We catch HTTP/1.1 4xx or HTTP/1.1 5xx error response.
 | |
|     if (strpos($headers[0], 'HTTP/1.1 4') !== FALSE || strpos($headers[0], 'HTTP/1.1 5') !== FALSE) {
 | |
|       $result = array(
 | |
|         'code' => 0,
 | |
|         'message' => '',
 | |
|       );
 | |
| 
 | |
|       if (preg_match('/^HTTP\/1.1 ([0-9]{3,3}) (.*)$/', $headers[0], $matches)) {
 | |
|         $result['code'] = $matches[1];
 | |
|         $result['message'] = $matches[2];
 | |
|       }
 | |
| 
 | |
|       // In case retrun with WWW-Authenticate replace the description.
 | |
|       foreach ($headers as $header) {
 | |
|         if (preg_match("/^WWW-Authenticate:.*error='(.*)'/", $header, $matches)) {
 | |
|           $result['error'] = $matches[1];
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       return json_encode($result);
 | |
|     }
 | |
| 
 | |
|     return $body;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * The name of the cookie that contains the session object.
 | |
|    *
 | |
|    * @return
 | |
|    *   The cookie name.
 | |
|    */
 | |
|   private function getSessionCookieName() {
 | |
|     return 'oauth2_' . $this->getVariable('client_id');
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Set a JS Cookie based on the _passed in_ session.
 | |
|    *
 | |
|    * It does not use the currently stored session - you need to explicitly
 | |
|    * pass it in.
 | |
|    *
 | |
|    * @param $session
 | |
|    *   The session to use for setting the cookie.
 | |
|    */
 | |
|   protected function setCookieFromSession($session = NULL) {
 | |
|     if (!$this->getVariable('cookie_support'))
 | |
|       return;
 | |
| 
 | |
|     $cookie_name = $this->getSessionCookieName();
 | |
|     $value = 'deleted';
 | |
|     $expires = time() - 3600;
 | |
|     $base_domain = $this->getVariable('base_domain', OAUTH2_DEFAULT_BASE_DOMAIN);
 | |
|     if ($session) {
 | |
|       $value = '"' . http_build_query($session, NULL, '&') . '"';
 | |
|       $base_domain = isset($session['base_domain']) ? $session['base_domain'] : $base_domain;
 | |
|       $expires = isset($session['expires']) ? $session['expires'] : time() + $this->getVariable('expires_in', OAUTH2_DEFAULT_EXPIRES_IN);
 | |
|     }
 | |
| 
 | |
|     // Prepend dot if a domain is found.
 | |
|     if ($base_domain)
 | |
|       $base_domain = '.' . $base_domain;
 | |
| 
 | |
|     // If an existing cookie is not set, we dont need to delete it.
 | |
|     if ($value == 'deleted' && empty($_COOKIE[$cookie_name]))
 | |
|       return;
 | |
| 
 | |
|     if (headers_sent())
 | |
|       error_log('Could not set cookie. Headers already sent.');
 | |
|     else
 | |
|       setcookie($cookie_name, $value, $expires, '/', $base_domain);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Validates a session_version = 3 style session object.
 | |
|    *
 | |
|    * @param $session
 | |
|    *   The session object.
 | |
|    *
 | |
|    * @return
 | |
|    *   The session object if it validates, NULL otherwise.
 | |
|    */
 | |
|   protected function validateSessionObject($session) {
 | |
|     // Make sure some essential fields exist.
 | |
|     if (is_array($session) && isset($session['access_token']) && isset($session['sig'])) {
 | |
|       // Validate the signature.
 | |
|       $session_without_sig = $session;
 | |
|       unset($session_without_sig['sig']);
 | |
| 
 | |
|       $expected_sig = self::generateSignature(
 | |
|         $session_without_sig,
 | |
|         $this->getVariable('client_secret')
 | |
|       );
 | |
| 
 | |
|       if ($session['sig'] != $expected_sig) {
 | |
|         error_log('Got invalid session signature in cookie.');
 | |
|         $session = NULL;
 | |
|       }
 | |
|     }
 | |
|     else {
 | |
|       $session = NULL;
 | |
|     }
 | |
|     return $session;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Since $_SERVER['REQUEST_URI'] is only available on Apache, we
 | |
|    * generate an equivalent using other environment variables.
 | |
|    */
 | |
|   function getRequestUri() {
 | |
|     if (isset($_SERVER['REQUEST_URI'])) {
 | |
|       $uri = $_SERVER['REQUEST_URI'];
 | |
|     }
 | |
|     else {
 | |
|       if (isset($_SERVER['argv'])) {
 | |
|         $uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['argv'][0];
 | |
|       }
 | |
|       elseif (isset($_SERVER['QUERY_STRING'])) {
 | |
|         $uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
 | |
|       }
 | |
|       else {
 | |
|         $uri = $_SERVER['SCRIPT_NAME'];
 | |
|       }
 | |
|     }
 | |
|     // Prevent multiple slashes to avoid cross site requests via the Form API.
 | |
|     $uri = '/' . ltrim($uri, '/');
 | |
| 
 | |
|     return $uri;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the Current URL.
 | |
|    *
 | |
|    * @return
 | |
|    *   The current URL.
 | |
|    */
 | |
|   protected function getCurrentUri() {
 | |
|     $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'
 | |
|       ? 'https://'
 | |
|       : 'http://';
 | |
|     $current_uri = $protocol . $_SERVER['HTTP_HOST'] . $this->getRequestUri();
 | |
|     $parts = parse_url($current_uri);
 | |
| 
 | |
|     $query = '';
 | |
|     if (!empty($parts['query'])) {
 | |
|       $params = array();
 | |
|       parse_str($parts['query'], $params);
 | |
|       $params = array_filter($params);
 | |
|       if (!empty($params)) {
 | |
|         $query = '?' . http_build_query($params, NULL, '&');
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // Use port if non default.
 | |
|     $port = isset($parts['port']) &&
 | |
|       (($protocol === 'http://' && $parts['port'] !== 80) || ($protocol === 'https://' && $parts['port'] !== 443))
 | |
|       ? ':' . $parts['port'] : '';
 | |
| 
 | |
|     // Rebuild.
 | |
|     return $protocol . $parts['host'] . $port . $parts['path'] . $query;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Build the URL for given path and parameters.
 | |
|    *
 | |
|    * @param $path
 | |
|    *   (optional) The path.
 | |
|    * @param $params
 | |
|    *   (optional) The query parameters in associative array.
 | |
|    *
 | |
|    * @return
 | |
|    *   The URL for the given parameters.
 | |
|    */
 | |
|   protected function getUri($path = '', $params = array()) {
 | |
|     $url = $this->getVariable('services_uri') ? $this->getVariable('services_uri') : $this->getVariable('base_uri');
 | |
| 
 | |
|     if (!empty($path))
 | |
|       if (substr($path, 0, 4) == "http")
 | |
|         $url = $path;
 | |
|       else
 | |
|         $url = rtrim($url, '/') . '/' . ltrim($path, '/');
 | |
| 
 | |
|     if (!empty($params))
 | |
|       $url .= '?' . http_build_query($params, NULL, '&');
 | |
| 
 | |
|     return $url;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Generate a signature for the given params and secret.
 | |
|    *
 | |
|    * @param $params
 | |
|    *   The parameters to sign.
 | |
|    * @param $secret
 | |
|    *   The secret to sign with.
 | |
|    *
 | |
|    * @return
 | |
|    *   The generated signature
 | |
|    */
 | |
|   protected function generateSignature($params, $secret) {
 | |
|     // Work with sorted data.
 | |
|     ksort($params);
 | |
| 
 | |
|     // Generate the base string.
 | |
|     $base_string = '';
 | |
|     foreach ($params as $key => $value) {
 | |
|       $base_string .= $key . '=' . $value;
 | |
|     }
 | |
|     $base_string .= $secret;
 | |
| 
 | |
|     return md5($base_string);
 | |
|   }
 | |
| }
 |