Index: /extensions/oAuth/admin/template/providers.tpl
===================================================================
--- /extensions/oAuth/admin/template/providers.tpl	(revision 26554)
+++ /extensions/oAuth/admin/template/providers.tpl	(revision 26555)
@@ -69,5 +69,5 @@
       <td class="keys" {if not $CONFIG[$p].enabled}style="display:none;"{/if}>
         {if $provider.require_client_id}
-          <label for="{$p}_app_id">Application ID</label>
+          <label for="{$p}_app_id">Application/Client ID</label>
           <input type="text" id="{$p}_app_id" name="providers[{$p}][keys][id]" value="{$CONFIG[$p].keys.id}">
         {else}
@@ -88,7 +88,5 @@
         
       {if $p=='Google'}
-        <li>{'On the <b>API Access</b> tab, <b>create an OAuth 2.0 Client ID</b>'|@translate}</li>
-        <li>{'Fill out any required fields such as the application name and description'|@translate}</li>
-        <li>{'On the <b>Create Client ID</b> popup, switch to advanced settings by clicking on <b>(more options)</b>'|@translate}</li>
+        <li>{'On the <b>APIs & auth -> Credentials</b> tab, <b>Create new client ID</b>'|@translate}</li>
       {else}
         <li>{'Fill out any required fields such as the application name and description'|@translate}</li>
@@ -105,21 +103,24 @@
         <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Redirect Domain</b>':$SERVERNAME}</li>
       {elseif $p=='Facebook'}
-        <li>{'Set the <b>%s</b> to <em>%s</em>'|@translate|sprintf:'application type':'Website with facebook authentication'}</li>
-        <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Site Url</b>, <b>App Domains</b>':$SERVERNAME}</li>
+        <li>{'Go to <b>Settings->Advanced</b> and activate <em>Client OAuth Login</em>.'|translate}</li>
+        <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Valid OAuth redirect URIs</b>':$SERVERNAME}</li>
       {elseif $p=='LinkedIn'}
         <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Website URL</b>':$SERVERNAME}</li>
-        <li>{'Set the <b>%s</b> to <em>%s</em>'|@translate|sprintf:'Application Type':'Web Application'}</li>
+        <li>{'Set <b>%s</b> to <em>%s</em>'|@translate|sprintf:'Application Type':'Web Application'}</li>
+        <li>{'Set <b>%s</b> to <em>%s</em>'|@translate|sprintf:'Default Scope':'r_basicprofile & r_emailaddress'}</li>
       {elseif $p=='Yahoo'}
         <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Application URL</b>, <b>Application Domain</b>':$SERVERNAME}</li>
-        <li>{'Set the <b>%s</b> to <em>%s</em>'|@translate|sprintf:'Kind of Application':'Web-based'}</li>
-        <li>{'Set the <b>%s</b> to <em>%s</em>'|@translate|sprintf:'Access Scopes':'This app will only access public...'}</li>
+        <li>{'Set <b>%s</b> to <em>%s</em>'|@translate|sprintf:'Kind of Application':'Web-based'}</li>
+        <li>{'Set <b>%s</b> to <em>%s</em>'|@translate|sprintf:'Access Scopes':'This app will only access public...'}</li>
         <li>{'Once the application is registered update the permissions : set <b>Contacts</b> as <em>Read</em> and <b>Social Directory</b> as <em>Read Public</em>'|@translate}</li>
       {elseif $p=='Twitter'}
-        <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Application Website</b>, <b>Application Callback URL</b>':$SERVERNAME}</li>
-        <li>{'Set the <b>%s</b> to <em>%s</em>'|@translate|sprintf:'Default Access Type':'Read only'}</li>
+        <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Website</b>, <b>Callback URL</b>':$SERVERNAME}</li>
       {elseif $p=='Tumblr'}
         <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Application Website</b>, <b>Default Callback URL</b>':$SERVERNAME}</li>
       {elseif $p=='Instagram'}
         <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Website</b>':$SERVERNAME}</li>
+      {elseif $p=='Google'}
+        <li>{'Set <b>%s</b> to <em>%s</em>'|@translate|sprintf:'Application Type':'Web Application'}</li>
+        <li>{'Put your website domain in the %s fields. It should match with the current hostname: <em>%s</em>'|@translate|sprintf:'<b>Authorized Javascript origins </b>':$SERVERNAME}</li>
       {/if}
       
Index: /extensions/oAuth/include/hybridauth/Hybrid/Auth.php
===================================================================
--- /extensions/oAuth/include/hybridauth/Hybrid/Auth.php	(revision 26554)
+++ /extensions/oAuth/include/hybridauth/Hybrid/Auth.php	(revision 26555)
@@ -15,5 +15,5 @@
 class Hybrid_Auth 
 {
-	public static $version = "2.1.1-dev";
+	public static $version = "2.1.2";
 
 	public static $config  = array();
@@ -250,5 +250,5 @@
 			$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 stored for this provider.", $params );
+			Hybrid_Logger::debug( "Hybrid_Auth::setup( $providerId ), no params given. Trying to get the sotred for this provider.", $params );
 		}
 
@@ -387,9 +387,10 @@
 
 		// use port if non default
-		$url .= 
-			isset( $_SERVER['SERVER_PORT'] ) 
-			&&( ($protocol === 'http://' && $_SERVER['SERVER_PORT'] != 80) || ($protocol === 'https://' && $_SERVER['SERVER_PORT'] != 443) )
-			? ':' . $_SERVER['SERVER_PORT'] 
-			: '';
+		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 ){
Index: /extensions/oAuth/include/hybridauth/Hybrid/Endpoint.php
===================================================================
--- /extensions/oAuth/include/hybridauth/Hybrid/Endpoint.php	(revision 26554)
+++ /extensions/oAuth/include/hybridauth/Hybrid/Endpoint.php	(revision 26555)
@@ -198,9 +198,9 @@
 				
 				$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.2" );
+					die( "You cannot access this page directly." );
 				}
 
Index: /extensions/oAuth/include/hybridauth/Hybrid/Provider_Adapter.php
===================================================================
--- /extensions/oAuth/include/hybridauth/Hybrid/Provider_Adapter.php	(revision 26554)
+++ /extensions/oAuth/include/hybridauth/Hybrid/Provider_Adapter.php	(revision 26555)
@@ -140,5 +140,5 @@
 		// move on
 		Hybrid_Logger::debug( "Hybrid_Provider_Adapter::login( {$this->id} ), redirect the user to login_start URL." );
-    
+
 		Hybrid_Auth::redirect( $this->params["login_start"] );
 	}
Index: /extensions/oAuth/include/hybridauth/Hybrid/Providers/Facebook.php
===================================================================
--- /extensions/oAuth/include/hybridauth/Hybrid/Providers/Facebook.php	(revision 26554)
+++ /extensions/oAuth/include/hybridauth/Hybrid/Providers/Facebook.php	(revision 26555)
@@ -31,4 +31,8 @@
 			require_once Hybrid_Auth::$config["path_libraries"] . "Facebook/facebook.php";
 		}
+		
+		if ( isset ( Hybrid_Auth::$config["proxy"] ) ) {
+			BaseFacebook::$CURL_OPTS[CURLOPT_PROXY] = Hybrid_Auth::$config["proxy"];
+		}
 
 		$this->api = new Facebook( ARRAY( 'appId' => $this->config["keys"]["id"], 'secret' => $this->config["keys"]["secret"] ) ); 
@@ -128,5 +132,5 @@
 		$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?type=square";
+		$this->user->profile->photoURL      = "https://graph.facebook.com/" . $this->user->profile->identifier . "/picture?width=150&height=150";
 		$this->user->profile->profileURL    = (array_key_exists('link',$data))?$data['link']:""; 
 		$this->user->profile->webSiteURL    = (array_key_exists('website',$data))?$data['website']:""; 
@@ -172,5 +176,5 @@
 			$uc->displayName = (array_key_exists("name",$item))?$item["name"]:"";
 			$uc->profileURL  = "https://www.facebook.com/profile.php?id=" . $uc->identifier;
-			$uc->photoURL    = "https://graph.facebook.com/" . $uc->identifier . "/picture?type=square"; 
+			$uc->photoURL    = "https://graph.facebook.com/" . $uc->identifier . "/picture?width=150&height=150";
 
 			$contacts[] = $uc;
Index: /extensions/oAuth/include/hybridauth/Hybrid/Providers/Instagram.php
===================================================================
--- /extensions/oAuth/include/hybridauth/Hybrid/Providers/Instagram.php	(revision 26554)
+++ /extensions/oAuth/include/hybridauth/Hybrid/Providers/Instagram.php	(revision 26555)
@@ -34,5 +34,5 @@
 
 		if ( $data->meta->code != 200 ){
-			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 );
 		}
 
Index: /extensions/oAuth/include/hybridauth/Hybrid/Providers/Twitter.php
===================================================================
--- /extensions/oAuth/include/hybridauth/Hybrid/Providers/Twitter.php	(revision 26554)
+++ /extensions/oAuth/include/hybridauth/Hybrid/Providers/Twitter.php	(revision 26555)
@@ -18,12 +18,51 @@
 		parent::initialize();
 
-		// Provider api end-points
-		$this->api->api_base_url      = "https://api.twitter.com/1/";
+		// Provider api end-points 
+		$this->api->api_base_url      = "https://api.twitter.com/1.1/";
 		$this->api->authorize_url     = "https://api.twitter.com/oauth/authenticate";
 		$this->api->request_token_url = "https://api.twitter.com/oauth/request_token";
 		$this->api->access_token_url  = "https://api.twitter.com/oauth/access_token";
 
+		if ( isset( $this->config['api_version'] ) && $this->config['api_version'] ){
+			$this->api->api_base_url  = "https://api.twitter.com/{$this->config['api_version']}/";
+		}
+ 
+		if ( isset( $this->config['authorize'] ) && $this->config['authorize'] ){
+			$this->api->authorize_url = "https://api.twitter.com/oauth/authorize";
+		}
+
 		$this->api->curl_auth_header  = false;
 	}
+
+ 	/**
+ 	 * begin login step
+ 	 */
+ 	function loginBegin()
+ 	{
+ 		$tokens = $this->api->requestToken( $this->endpoint );
+ 	
+ 		// request tokens as recived 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 );
+ 		}
+ 	
+ 		if ( ! isset( $tokens["oauth_token"] ) ){
+ 			throw new Exception( "Authentification 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'] ){
+ 			Hybrid_Auth::redirect( $this->api->authorizeUrl( $tokens, array( 'force_login' => true ) ) );
+ 		}
+
+		// else, redirect the user to the provider authentication url
+ 		Hybrid_Auth::redirect( $this->api->authorizeUrl( $tokens ) );
+ 	}
 
 	/**
Index: /extensions/oAuth/include/hybridauth/Hybrid/Storage.php
===================================================================
--- /extensions/oAuth/include/hybridauth/Hybrid/Storage.php	(revision 26554)
+++ /extensions/oAuth/include/hybridauth/Hybrid/Storage.php	(revision 26555)
@@ -28,8 +28,8 @@
 
 		if( $value ){
-			$_SESSION["HA::CONFIG"][$key] = serialize($value); 
+			$_SESSION["HA::CONFIG"][$key] = serialize( $value ); 
 		}
 		elseif( isset( $_SESSION["HA::CONFIG"][$key] ) ){ 
-			return unserialize($_SESSION["HA::CONFIG"][$key]);  
+			return unserialize( $_SESSION["HA::CONFIG"][$key] );  
 		}
 
@@ -42,5 +42,5 @@
 
 		if( isset( $_SESSION["HA::STORE"], $_SESSION["HA::STORE"][$key] ) ){ 
-			return unserialize($_SESSION["HA::STORE"][$key]);  
+			return unserialize( $_SESSION["HA::STORE"][$key] );  
 		}
 
@@ -52,5 +52,5 @@
 		$key = strtolower( $key ); 
 
-		$_SESSION["HA::STORE"][$key] = serialize($value); 
+		$_SESSION["HA::STORE"][$key] = serialize( $value ); 
 	}
 
@@ -65,5 +65,7 @@
 
 		if( isset( $_SESSION["HA::STORE"], $_SESSION["HA::STORE"][$key] ) ){
-			unset( $_SESSION["HA::STORE"][$key] );
+		    $f = $_SESSION['HA::STORE'];
+		    unset($f[$key]);
+		    $_SESSION["HA::STORE"] = $f;
 		} 
 	}
@@ -74,9 +76,12 @@
 
 		if( isset( $_SESSION["HA::STORE"] ) && count( $_SESSION["HA::STORE"] ) ) {
-			foreach( $_SESSION["HA::STORE"] as $k => $v ){ 
+		    $f = $_SESSION['HA::STORE'];
+		    foreach( $f as $k => $v ){ 
 				if( strstr( $k, $key ) ){
-					unset( $_SESSION["HA::STORE"][ $k ] ); 
+					unset( $f[ $k ] ); 
 				}
 			}
+			$_SESSION["HA::STORE"] = $f;
+			
 		}
 	}
@@ -85,5 +90,5 @@
 	{
 		if( isset( $_SESSION["HA::STORE"] ) ){ 
-			return $_SESSION["HA::STORE"]; 
+			return serialize( $_SESSION["HA::STORE"] ); 
 		}
 
@@ -93,5 +98,5 @@
 	function restoreSessionData( $sessiondata = NULL )
 	{ 
-		$_SESSION["HA::STORE"] = $sessiondata;
+		$_SESSION["HA::STORE"] = unserialize( $sessiondata );
 	} 
 }
Index: /extensions/oAuth/include/hybridauth/Hybrid/thirdparty/LinkedIn/LinkedIn.php
===================================================================
--- /extensions/oAuth/include/hybridauth/Hybrid/thirdparty/LinkedIn/LinkedIn.php	(revision 26554)
+++ /extensions/oAuth/include/hybridauth/Hybrid/thirdparty/LinkedIn/LinkedIn.php	(revision 26555)
@@ -124,5 +124,5 @@
 	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'; 
+	const _URL_REQUEST                 = 'https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile+r_emailaddress+rw_nus'; 
 	const _URL_REVOKE                  = 'https://api.linkedin.com/uas/oauth/invalidateToken';
 	
Index: /extensions/oAuth/include/hybridauth/Hybrid/thirdparty/OpenID/LightOpenID.php
===================================================================
--- /extensions/oAuth/include/hybridauth/Hybrid/thirdparty/OpenID/LightOpenID.php	(revision 26554)
+++ /extensions/oAuth/include/hybridauth/Hybrid/thirdparty/OpenID/LightOpenID.php	(revision 26555)
@@ -1,53 +1,16 @@
 <?php
-// http://gitorious.org/lightopenid
-// updated 29/12/2012
+// https://github.com/iignatov/LightOpenID
 
 /**
- * This class provides a simple interface for OpenID (1.1 and 2.0) authentication.
- * Supports Yadis discovery.
- * The authentication process is stateless/dumb.
+ * This class provides a simple interface for OpenID 1.1/2.0 authentication.
+ * 
+ * It requires PHP >= 5.1.2 with cURL or HTTP/HTTPS stream wrappers enabled.
  *
- * Usage:
- * Sign-on with OpenID is a two step process:
- * Step one is authentication with the provider:
- * <code>
- * $openid = new LightOpenID('my-host.example.org');
- * $openid->identity = 'ID supplied by user';
- * header('Location: ' . $openid->authUrl());
- * </code>
- * The provider then sends various parameters via GET, one of them is openid_mode.
- * Step two is verification:
- * <code>
- * $openid = new LightOpenID('my-host.example.org');
- * if ($openid->mode) {
- *     echo $openid->validate() ? 'Logged in.' : 'Failed';
- * }
- * </code>
- *
- * Change the 'my-host.example.org' to your domain name. Do NOT use $_SERVER['HTTP_HOST']
- * for that, unless you know what you are doing.
- *
- * Optionally, you can set $returnUrl and $realm (or $trustRoot, which is an alias).
- * The default values for those are:
- * $openid->realm     = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'];
- * $openid->returnUrl = $openid->realm . $_SERVER['REQUEST_URI'];
- * If you don't know their meaning, refer to any openid tutorial, or specification. Or just guess.
- *
- * AX and SREG extensions are supported.
- * To use them, specify $openid->required and/or $openid->optional before calling $openid->authUrl().
- * These are arrays, with values being AX schema paths (the 'path' part of the URL).
- * For example:
- *   $openid->required = array('namePerson/friendly', 'contact/email');
- *   $openid->optional = array('namePerson/first');
- * If the server supports only SREG or OpenID 1.1, these are automaticaly
- * mapped to SREG names, so that user doesn't have to know anything about the server.
- *
- * To get the values, use $openid->getAttributes().
- *
- *
- * The library requires PHP >= 5.1.2 with curl or http/https stream wrappers enabled.
+ * @version v1.1.2 2013-01-15
+ * @link http://gitorious.org/lightopenid Official Repo
+ * @link http://github.com/iignatov/LightOpenID GitHub Clone
  * @author Mewp
  * @copyright Copyright (c) 2010, Mewp
- * @license http://www.opensource.org/licenses/mit-license.php MIT
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
  */
 class LightOpenID
@@ -59,8 +22,10 @@
          , $capath = null
          , $cainfo = null
-         , $data;
+         , $data
+         , $oauth = array();
     private $identity, $claimed_id;
     protected $server, $version, $trustRoot, $aliases, $identifier_select = false
-            , $ax = false, $sreg = false, $setup_url = null, $headers = array();
+            , $ax = false, $sreg = false, $setup_url = null, $headers = array(), $proxy = null
+            , $xrds_override_pattern = null, $xrds_override_replacement = null;
     static protected $ax_to_sreg = array(
         'namePerson/friendly'     => 'nickname',
@@ -75,5 +40,5 @@
         );
 
-    function __construct($host)
+    function __construct($host, $proxy = null)
     {
         $this->trustRoot = (strpos($host, '://') ? $host : 'http://' . $host);
@@ -88,4 +53,6 @@
             $this->trustRoot = substr($this->trustRoot, 0, $host_end);
         }
+        
+        $this->set_proxy($proxy);
 
         $uri = rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#', '', $_SERVER['REQUEST_URI']), '?');
@@ -118,4 +85,14 @@
         case 'realm':
             $this->trustRoot = trim($value);
+            break;
+        case 'xrdsOverride':
+            if (is_array($value)) {
+                list($pattern, $replacement) = $value;
+                $this->xrds_override_pattern = $pattern;
+                $this->xrds_override_replacement = $replacement;
+            } else {
+                trigger_error('Invalid value specified for "xrdsOverride".', E_USER_ERROR);
+            }
+            break;
         }
     }
@@ -136,4 +113,30 @@
         }
     }
+    
+    function set_proxy($proxy)
+    {
+        if (!empty($proxy)) {
+            // When the proxy is a string - try to parse it.
+            if (!is_array($proxy)) {
+                $proxy = parse_url($proxy);
+            }
+            
+            // Check if $proxy is valid after the parsing.
+            if ($proxy && !empty($proxy['host'])) {
+                // Make sure that a valid port number is specified.
+                if (array_key_exists('port', $proxy)) {
+                    if (!is_int($proxy['port'])) {
+                        $proxy['port'] = is_numeric($proxy['port']) ? intval($proxy['port']) : 0;
+                    }
+                    
+                    if ($proxy['port'] <= 0) {
+                        throw new ErrorException('The specified proxy port number is invalid.');
+                    }
+                }
+                
+                $this->proxy = $proxy;
+            }
+        }
+    }
 
     /**
@@ -167,4 +170,16 @@
         curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
         curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*'));
+        
+        if (!empty($this->proxy)) {
+            curl_setopt($curl, CURLOPT_PROXY, $this->proxy['host']);
+            
+            if (!empty($this->proxy['port'])) {
+                curl_setopt($curl, CURLOPT_PROXYPORT, $this->proxy['port']);
+            }
+            
+            if (!empty($this->proxy['user'])) {
+                curl_setopt($curl, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']);            
+            }
+        }
 
         if($this->verify_peer !== null) {
@@ -285,4 +300,7 @@
             );
             $url = $url . ($params ? '?' . $params : '');
+            if (!empty($this->proxy)) {
+                $opts['http']['proxy'] = $this->proxy_url();
+            }
             break;
         case 'POST':
@@ -297,49 +315,83 @@
                 ),
             );
+            if (!empty($this->proxy)) {
+                $opts['http']['proxy'] = $this->proxy_url();
+            }
             break;
         case 'HEAD':
-            # We want to send a HEAD request,
-            # but since get_headers doesn't accept $context parameter,
-            # we have to change the defaults.
+            // We want to send a HEAD request, but since get_headers() doesn't 
+            // accept $context parameter, we have to change the defaults.
             $default = stream_context_get_options(stream_context_get_default());
-            stream_context_get_default(
-                array(
-                    'http' => array(
-                        'method' => 'HEAD',
-                        'header' => 'Accept: application/xrds+xml, */*',
-                        'ignore_errors' => true,
-                    ), 'ssl' => array(
-                        'CN_match' => parse_url($url, PHP_URL_HOST),
-                    ),
+            
+            // PHP does not reset all options. Instead, it just sets the options
+            // available in the passed array, therefore set the defaults manually.
+            $default += array(
+                'http' => array(),
+                'ssl' => array()
+            );
+            $default['http'] += array(
+                'method' => 'GET',
+                'header' => '',
+                'ignore_errors' => false
+            );
+            $default['ssl'] += array(
+                'CN_match' => ''
+            );
+            
+            $opts = array(
+                'http' => array(
+                    'method' => 'HEAD',
+                    'header' => 'Accept: application/xrds+xml, */*',
+                    'ignore_errors' => true,
+                ),
+                'ssl' => array(
+                    'CN_match' => parse_url($url, PHP_URL_HOST)
                 )
             );
-
-            $url = $url . ($params ? '?' . $params : '');
-            $headers = get_headers ($url);
-            if(!$headers) {
-                return array();
-            }
-
-            if(intval(substr($headers[0], strlen('HTTP/1.1 '))) == 405) {
-                # The server doesn't support HEAD, so let's emulate it with
-                # a GET.
-                $args = func_get_args();
-                $args[1] = 'GET';
-                call_user_func_array(array($this, 'request_streams'), $args);
-                return $this->headers;
-            }
-
-            $headers = $this->parse_header_array($headers, $update_claimed_id);
-
-            # And restore them.
+            
+            // Enable validation of the SSL certificates.
+            if ($this->verify_peer) {
+                $default['ssl'] += array(
+                    'verify_peer' => false,
+                    'capath' => '',
+                    'cafile' => ''
+                );
+                $opts['ssl'] += array(
+                    'verify_peer' => true,
+                    'capath' => $this->capath,
+                    'cafile' => $this->cainfo
+                );
+            }
+            
+            // Change the stream context options.
+            stream_context_get_default($opts);
+            
+            $headers = get_headers($url . ($params ? '?' . $params : ''));
+            
+            // Restore the stream context options.
             stream_context_get_default($default);
+            
+            if (!empty($headers)) {
+                if (intval(substr($headers[0], strlen('HTTP/1.1 '))) == 405) {
+                    // The server doesn't support HEAD - emulate it with a GET.
+                    $args = func_get_args();
+                    $args[1] = 'GET';
+                    call_user_func_array(array($this, 'request_streams'), $args);
+                    $headers = $this->headers;
+                } else {
+                    $headers = $this->parse_header_array($headers, $update_claimed_id);
+                }
+            } else {
+                $headers = array();
+            }
+            
             return $headers;
         }
 
-        if($this->verify_peer) {
+        if ($this->verify_peer) {
             $opts['ssl'] += array(
                 'verify_peer' => true,
                 'capath'      => $this->capath,
-                'cafile'      => $this->cainfo,
+                'cafile'      => $this->cainfo
             );
         }
@@ -364,4 +416,25 @@
         }
         return $this->request_streams($url, $method, $params, $update_claimed_id);
+    }
+    
+    protected function proxy_url()
+    {
+        $result = '';
+        
+        if (!empty($this->proxy)) {
+            $result = $this->proxy['host'];
+            
+            if (!empty($this->proxy['port'])) {
+                $result = $result . ':' . $this->proxy['port'];
+            }
+            
+            if (!empty($this->proxy['user'])) {
+                $result = $this->proxy['user'] . ':' . $this->proxy['pass'] . '@' . $result;
+            }
+            
+            $result = 'http://' . $result;
+        }
+        
+        return $result;
     }
 
@@ -419,4 +492,10 @@
         # A flag to disable yadis discovery in case of failure in headers.
         $yadis = true;
+        
+        # Allows optional regex replacement of the URL, e.g. to use Google Apps
+        # as an OpenID provider without setting up XRDS on the domain hosting.
+        if (!is_null($this->xrds_override_pattern) && !is_null($this->xrds_override_replacement)) {
+            $url = preg_replace($this->xrds_override_pattern, $this->xrds_override_replacement, $url);
+        }
 
         # We'll jump a maximum of 5 times, to avoid endless redirections.
@@ -639,14 +718,23 @@
             'openid.realm'       => $this->trustRoot,
         );
+        
         if ($this->ax) {
             $params += $this->axParams();
         }
+        
         if ($this->sreg) {
             $params += $this->sregParams();
         }
+        
         if (!$this->ax && !$this->sreg) {
             # If OP doesn't advertise either SREG, nor AX, let's send them both
             # in worst case we don't get anything in return.
             $params += $this->axParams() + $this->sregParams();
+        }
+
+        if (!empty($this->oauth) && is_array($this->oauth)) {
+            $params['openid.ns.oauth'] = 'http://specs.openid.net/extensions/oauth/1.0';
+            $params['openid.oauth.consumer'] = str_replace(array('http://', 'https://'), '', $this->trustRoot);
+            $params['openid.oauth.scope'] = implode(' ', $this->oauth);
         }
 
@@ -749,47 +837,46 @@
     protected function getAxAttributes()
     {
-        $alias = null;
-        if (isset($this->data['openid_ns_ax'])
-            && $this->data['openid_ns_ax'] != 'http://openid.net/srv/ax/1.0'
-        ) { # It's the most likely case, so we'll check it before
-            $alias = 'ax';
+        $result = array();
+        
+        if ($alias = $this->getNamespaceAlias('http://openid.net/srv/ax/1.0', 'ax')) {
+            $prefix = 'openid_' . $alias;
+            $length = strlen('http://axschema.org/');
+            
+            foreach (explode(',', $this->data['openid_signed']) as $key) {
+                $keyMatch = $alias . '.type.';
+                
+                if (strncmp($key, $keyMatch, strlen($keyMatch)) !== 0) {
+                    continue;
+                }
+                
+                $key = substr($key, strlen($keyMatch));
+                $idv = $prefix . '_value_' . $key;
+                $idc = $prefix . '_count_' . $key;
+                $key = substr($this->getItem($prefix . '_type_' . $key), $length);
+                
+                if (!empty($key)) {
+                    if (($count = intval($this->getItem($idc))) > 0) {
+                        $value = array();
+                        
+                        for ($i = 1; $i <= $count; $i++) {
+                            $value[] = $this->getItem($idv . '_' . $i);
+                        }
+                        
+                        $value = ($count == 1) ? reset($value) : $value;
+                    } else {
+                        $value = $this->getItem($idv);
+                    }
+                    
+                    if (!is_null($value)) {
+                        $result[$key] = $value;
+                    }
+                }
+            }
         } else {
-            # 'ax' prefix is either undefined, or points to another extension,
-            # so we search for another prefix
-            foreach ($this->data as $key => $val) {
-                if (substr($key, 0, strlen('openid_ns_')) == 'openid_ns_'
-                    && $val == 'http://openid.net/srv/ax/1.0'
-                ) {
-                    $alias = substr($key, strlen('openid_ns_'));
-                    break;
-                }
-            }
-        }
-        if (!$alias) {
-            # An alias for AX schema has not been found,
-            # so there is no AX data in the OP's response
-            return array();
-        }
-
-        $attributes = array();
-        foreach (explode(',', $this->data['openid_signed']) as $key) {
-            $keyMatch = $alias . '.value.';
-            if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
-                continue;
-            }
-            $key = substr($key, strlen($keyMatch));
-            if (!isset($this->data['openid_' . $alias . '_type_' . $key])) {
-                # OP is breaking the spec by returning a field without
-                # associated ns. This shouldn't happen, but it's better
-                # to check, than cause an E_NOTICE.
-                continue;
-            }
-            $value = $this->data['openid_' . $alias . '_value_' . $key];
-            $key = substr($this->data['openid_' . $alias . '_type_' . $key],
-                          strlen('http://axschema.org/'));
-
-            $attributes[$key] = $value;
-        }
-        return $attributes;
+            // No alias for the AX schema has been found,
+            // so there is no AX data in the OP's response.
+        }
+        
+        return $result;
     }
 
@@ -800,5 +887,5 @@
         foreach (explode(',', $this->data['openid_signed']) as $key) {
             $keyMatch = 'sreg.';
-            if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
+            if (strncmp($key, $keyMatch, strlen($keyMatch)) !== 0) {
                 continue;
             }
@@ -832,3 +919,63 @@
         return $this->getSregAttributes();
     }
+
+    /**
+     * Gets an OAuth request token if the OpenID+OAuth hybrid protocol has been used.
+     *
+     * In order to use the OpenID+OAuth hybrid protocol, you need to add at least one
+     * scope to the $openid->oauth array before you get the call to getAuthUrl(), e.g.:
+     * $openid->oauth[] = 'https://www.googleapis.com/auth/plus.me';
+     * 
+     * Furthermore the registered consumer name must fit the OpenID realm. 
+     * To register an OpenID consumer at Google use: https://www.google.com/accounts/ManageDomains
+     * 
+     * @return string|bool OAuth request token on success, FALSE if no token was provided.
+     */
+    function getOAuthRequestToken()
+    {
+        $alias = $this->getNamespaceAlias('http://specs.openid.net/extensions/oauth/1.0');
+        
+        return !empty($alias) ? $this->data['openid_' . $alias . '_request_token'] : false;
+    }
+    
+    /**
+     * Gets the alias for the specified namespace, if it's present.
+     *
+     * @param string $namespace The namespace for which an alias is needed.
+     * @param string $hint Common alias of this namespace, used for optimization.
+     * @return string|null The namespace alias if found, otherwise - NULL.
+     */
+    private function getNamespaceAlias($namespace, $hint = null)
+    {
+        $result = null;
+        
+        if (empty($hint) || $this->getItem('openid_ns_' . $hint) != $namespace) {
+            // The common alias is either undefined or points to
+            // some other extension - search for another alias..
+            $prefix = 'openid_ns_';
+            $length = strlen($prefix);
+            
+            foreach ($this->data as $key => $val) {
+                if (strncmp($key, $prefix, $length) === 0 && $val === $namespace) {
+                    $result = trim(substr($key, $length));
+                    break;
+                }
+            }
+        } else {
+            $result = $hint;
+        }
+        
+        return $result;
+    }
+    
+    /**
+     * Gets an item from the $data array by the specified id.
+     *
+     * @param string $id The id of the desired item.
+     * @return string|null The item if found, otherwise - NULL.
+     */
+    private function getItem($id)
+    {
+        return isset($this->data[$id]) ? $this->data[$id] : null; 
+    }
 }
Index: /extensions/oAuth/include/providers_stats.inc.php
===================================================================
--- /extensions/oAuth/include/providers_stats.inc.php	(revision 26554)
+++ /extensions/oAuth/include/providers_stats.inc.php	(revision 26555)
@@ -15,5 +15,5 @@
     'callback'          => true,
     'require_client_id' => true,
-    'new_app_link'      => 'https://code.google.com/apis/console',
+    'new_app_link'      => 'https://cloud.google.com/console/project',
     'scope'             => 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
   ),
@@ -44,5 +44,5 @@
     'provider_name'     => 'Windows Live',
     'require_client_id' => true,
-    'new_app_link'      => 'https://manage.dev.live.com/ApplicationOverview.aspx',
+    'new_app_link'      => 'https://account.live.com/developers/applications/index',
   ),
   'Yahoo' => array( 
