2Mar/1138

Google Apps as single authentication point for your corporate applications

This is an update to my post "Google Apps Premier federated login with PHP". Idea is simple, users do not like passwords, less passwords - less pain and more security.

Nowadays many companies have gone cloud, which covers most needs, but leaves space for homegrown small applications, ideas, prototypes, etc. It is convenient to organize user login into these applications using already existing Google Apps login infrastructure.

This is about using it with PHP.

Since previous post, I've updated PHP library used to the latest versions and tested them again. Also I rewrite bundled example to work in more transparent way and made it more clear.

Libraries version

php-openid-apps-discover-1.0.2.zip
openid-php-openid-2.2.2-0-ga287b2d.zip

Online demo

http://a32.me/other/ga-open-id/

Downloads

All-in-one-pack includes libraries and example

Installation

Unpack, make sure make TMP folder with sub-folders are writable.

It requires php_curl and php_openssl extension, make sure you have those.

Example code

<?php
/**
 * @date Created on Feb 22, 2011
 * @author		Constantin Bosneaga <ameoba32@gmail.com>
 * 
 */
 
// Include files
require_once "Auth/OpenID/Consumer.php";
require_once "Auth/OpenID/AX.php";
require_once "Auth/OpenID/google_discovery.php";
require_once "Auth/OpenID/FileStore.php";
require_once "Auth/OpenID/SReg.php";
require_once "Auth/OpenID/PAPE.php";
 
// Init login
$tmp = dirname(realpath(__FILE__)).DIRECTORY_SEPARATOR."tmp";
if (!file_exists($tmp)) die('Temp path '.$tmp.' does not exists'); 
if (!is_writable($tmp)) die('Temp path '.$tmp.' is not writable');
$config['tmp_path'] = $tmp;
 
// Return URL
$config['return_server'] = ($_SERVER["HTTPS"]?'https://':'http://').$_SERVER['SERVER_NAME'].":".$_SERVER['SERVER_PORT'];
$config['return_url'] = $config['return_server'].$_SERVER['REQUEST_URI']."?module=return";
 
// Cache for google discovery (much faster)
$config['cache'] = new FileCache($config['tmp_path']);
 
// Open id lib has many warnig and notices
error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING ^ E_USER_NOTICE);
 
$module = $_GET['module']?$_GET['module']:$_POST['module'];
switch ($module) {
 
	/**
	 * Login form
	 * 
	 * 
	 */	
	case '':
	?>
	<h1>Login with Google Apps</h1>
	<form method="POST">
	<input type="hidden" name="module" value="login">
	Your Google Apps domain:
	<input type="text" name="domain" value="">
	<input type="submit" name="submit" value="Login">
	</form>	
 
	<h1>Login with Google</h1>
	<form method="POST">
	<input type="hidden" name="module" value="login">
	<input type="hidden" name="domain" value="https://www.google.com/accounts/o8/id">
	<input type="submit" name="submit" value="Login">
	</form>
 
	<h1>Login with Yahoo</h1>
	<form method="POST">
	<input type="hidden" name="module" value="login">
	<input type="hidden" name="domain" value="http://me.yahoo.com">
	<input type="submit" name="submit" value="Login">
	</form>
		<?	
	break;	
 
 
	/**
	 * Process login 
	 */
	case 'login':
		$store = new Auth_OpenID_FileStore($config['tmp_path']);
		$consumer = new Auth_OpenID_Consumer($store);
		new GApps_OpenID_Discovery($consumer, null, $config['cache']);
 
		try {
			$auth_request = $consumer->begin($_POST['domain']);
			if (!is_object($auth_request)) die('Auth request object error. Try again');
		} catch (Exception $error) {
			die($error->getMessage());
		}
 
		/// Request additional parameters
		$ax = new Auth_OpenID_AX_FetchRequest;
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/contact/email',2,1,'email') );
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson/first',1,1, 'firstname') );
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson/last',1,1, 'lastname') );
 
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson/friendly',1,1,'friendly') );
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson',1,1,'fullname') );
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/birthDate',1,1,'dob') );
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/person/gender',1,1,'gender') );
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/contact/postalCode/home',1,1,'postcode') );
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/contact/country/home',1,1,'country') );
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/pref/language',1,1,'language') );
		$ax->add( Auth_OpenID_AX_AttrInfo::make('http://axschema.org/pref/timezone',1,1,'timezone') );
 
		$auth_request->addExtension($ax);
 
		// Request URL for auth dialog url 
		$redirect_url = $auth_request->redirectURL(
			$config['return_server'],
			$config['return_url']
		);
 
		if (Auth_OpenID::isFailure($redirect_url)) {
			die('Could not redirect to server: ' . $redirect_url->message);
		} else {
			header('Location: '.$redirect_url);
		}	
	break;
 
 
	/**
	 * Return URL, google redirects here after login
	 */
	case 'return':
		$store = new Auth_OpenID_FileStore($config['tmp_path']);
		$consumer = new Auth_OpenID_Consumer($store);
		new GApps_OpenID_Discovery($consumer, null, $config['cache']);
 
		$response = $consumer->complete($config['return_url']);
 
		// Check the response status.
		if ($response->status == Auth_OpenID_CANCEL) die('Verification cancelled.');
		if ($response->status == Auth_OpenID_FAILURE) die("OpenID authentication failed: " . $response->message);
		if ($response->status != Auth_OpenID_SUCCESS) die('Other error');
 
		// Successful login
 
		// Extract returned information
		$openid = $response->getDisplayIdentifier();
		$ax = new Auth_OpenID_AX_FetchResponse();
		if ($ax) $ax = $ax->fromSuccessResponse($response);
 
		$sreg = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
		if ($sreg ) $sreg = $sreg->contents();
 
		# print response
		?>
		<h1>OK</h1>
		You have successfully verified <a href="<?=$openid?>"><?=$openid?></a> as your identity.<br/><br/>
		<p>The following AX response received:</p>
		<pre><?=nl2br(print_r($ax->data,true))?></pre>
 
		<p>The following sreg response received:</p>
		<pre><?=nl2br(print_r($sreg,true))?></pre>
		<?
	break;	
 
}
 
 
class FileCache {
	var $cache_file;
 
	function __construct($tmp_path) {
		$this->cache_file = $tmp_path.DIRECTORY_SEPARATOR."google.tmp";
	}
 
	function get($name) {
		$cache = unserialize(file_get_contents($this->cache_file));
		return $cache[$name];
	}
 
	function set($name, $value) {
		$cache = unserialize(file_get_contents($this->cache_file));
		$cache[$name] = $value;
		file_put_contents($this->cache_file, serialize($cache));
	}
 
}
 
 
?>
 
Did you find this post useful? Support the the author ($10)
My Google Profile+
Comments (38) Trackbacks (2)
  1. This is awesome, just what I wanted.

    I didn’t want to understand the openID auth process, and I didn’t want my users registering.

    Cheers!

  2. Hi I tried your code but it gives me the following error. Can you please help in solving this ?

    Fatal error: Error while attempting OpenID discovery: Can not verify trust chain. in /home/neolearning/www/google/Auth/OpenID/google_discovery.php on line 101

    Thanks
    Anantha Prasad

  3. Hi, be sure that tmp folder and subfolders are writable.

  4. I’ve Given 777 mode to tmp folder and subfolders. still it gives the same error. then I tried commenting that
    /*if (!$trusted) {
    throw new GApps_Discovery_Exception(“Can not verify trust chain.”);
    }*/

    then it gives “OpenID authentication failed: Nonce already used or out of range” error
    Can you please help ?

    thanks
    Anantha Prasad

  5. Awesome. Thank you very much!

  6. Great solution – thanks a lot!

    Just a little bugfix – the url of the return server is wrong when using https – brackets are missing. Here is the correct line of code:
    $config['return_server'] = ($_SERVER["HTTPS"]?’https://':’http://’).$_SERVER['SERVER_NAME'].”:”.$_SERVER['SERVER_PORT'];

  7. Thanks! fixed

  8. Very usefull – thanks !

    We’ve created a MediaWiki extension out of it : http://www.mediawiki.org/wiki/Extension:GoogleAppsAuthentification – really shines !

  9. Cool! I am really happy that have done something useful.

  10. Great script. Does this do any housekeeping with it’s tmp directory?

  11. Help! Any idea how this code could be updated to request the user’s profile picture as well? Having problems working this in.

  12. Thanks for me to resolve mya google & yahoo api problems. It sis very helpfully to login by google & yahoo on our web site

  13. Can this work with Facebook or twitter? I saw that Facebook is signed up with OpenID

  14. As far as I know Facebook is not an OpenID provider, they use their own Connect technology. However, if you have more information about it I can add it also.

  15. it doesn’t work now, i have a php error
    “Parse error: syntax error, unexpected $end in C:\wamp\www\ga-open-id\index.php on line 175″
    do u know what is the problem? it’s look like easy.

  16. The error is often caused by the use of Short Open tags in PHP, replace

  17. Oh thank constantin! i have an other error now but i can read clearly. thank for your quick answer!

  18. An error in the GoogleAppsAuthentication.php code for MediaWiki 1.17.0. On line 98 $wgOut->redirect($url.”?action=purge”); //action=purge is used to purge the cache

    should read

    $wgOut->redirect($url.”&action=purge”); //action=purge is used to purge the cache

    Just the & instead of the ?. Not much of a coder so not sure if this is a problem for everyone.

    Thanks a lot for this solution. It worked brilliantly. Only took me 15 minutes to completely set up. And i am no computer guru.

  19. Also a question. Our company has a number of Google Apps domains. (e.g. company.com, company.co.uk, company.com.cn). Is there any way to allow the user to login under alternate domains?

    Thanks

  20. Also some tips about administration.

    Once you set this extension up you cant login as Admin (as far as I am aware) as it always wants you to login under a google apps account. This means you cant change the permissions for the users. Then if you disable the extension to change the permissions of some of the new google apps users (e.g. john@company.com) you hit the problem that MediaWiki doesnt like the @ symbol when using the Special:UserRights page. To overcome this you need to add $wgUserrightsInterwikiDelimiter = ‘#'; to the LocalSetting.php file to change it from using the @ to redirect to external wikis to using a # instead. Then you need to give some google apps users admin rights. Then enable the extension. Then it all works fine.

    Sorry for the poorly written comment. I am in a hurry.

  21. I have met error below. I don’t know why. Please help me about this.

    Fatal error: Call-time pass-by-reference has been removed in C:\xampp\htdocs\test\ga-open-id\Auth\OpenID\Consumer.php on line 1184

  22. It’s not working on php 5.4 :(

  23. That is probably related to OpenID library, it has some old depricated code. I will try to look at it!

    Btw 5.3 is good enough :)

  24. I found that pass-by-reference feature has been removed in 5.4 . But it seems to work without this.

    Just remove the “&” sign on line 1184. So it would become “$this->fetcher);” and try again!

  25. I am using trying to implement this plugin in localhost.

    But i am getting this error: “Auth request object error. Try again”

    Please help me..

  26. The error in these lines:

    Deprecated: Call-time pass-by-reference has been deprecated in C:\wamp\www\mediawiki-1.20.2\extensions\GoogleAppsAuthentication\Auth\OpenID\Consumer.php on line 1184

    Deprecated: Call-time pass-by-reference has been deprecated in C:\wamp\www\mediawiki-1.20.2\extensions\GoogleAppsAuthentication\Auth\Yadis\Manager.php on line 416

  27. Hi, see my comment above:

    Just remove the “&” sign on line 1184. So it would become “$this->fetcher);” and try again!

  28. Hi,
    Thank You for your reply.

    I got no error but still it is not working.

    it is showing “Auth request object error. Try again” error.

    Please help me with this also.

  29. Hi,
    I have problem with Wikimedia GoogleAppsAuthentifucation Extension, I use php-5.3.21 and apache 2.4.3
    I follow your guide step by step, I have fixed all “Call-time pass-by-reference” Errors , but I still have this Error :
    Fatal error: Failed to initialize OpenID file store in /var/www/opuntia/extensions/GoogleAppsAuthentication/tmp in /var/www/opuntia/extensions/GoogleAppsAuthentication/Auth/OpenID/FileStore.php on line 72

    Could any one help me please !

  30. just make sure TMP folder and subfolders are writable by webserver or 0777

  31. how would I go about redirecting the user to mail.domain.com which would bring them to their google app mail or any other service or directory once the login is successful. I noticed in the code that you’re calling up the results but what would I need to delete and input to direct to another directory instead?

  32. thanks Constantin for your answer
    I did chmod -R 0777 /tmp but i still have another error ” Auth request object error. Try again ”

    I can’t understand what is the problem,
    Note : I use Wikimedia GoogleAppsAuthentifucation Extension, php-5.3.21 and apache 2.4.3 .
    the Script test of OpenId give “success setup” that means that my php supports well the OpenID Library .
    Could you help me ?

  33. Hello , I have resolved the prb of “”Auth request object error. Try again ”””

    it was due to the lack of php extension requirements to be able to use OpenId API , I have used Curl with php but it was not enough and when I have used OpenSSl php extension the problem was resolved !
    best regards !

  34. Good to know that. I will add these requirements to blog-post.

  35. Hello

    In my case the error “Auth request object error. Try again”. solve it by installing the php-xml library

    Regards..

  36. Hey,

    Thanks for the work! I had troubles with Auth/Yadis/Manager.php not compiling, the solution for me was to change line &$fetcher to just $fetcher around line 416 in call_user_func()

  37. Heya i’m for the first time here. I came across this board and I find It really helpful & it helped me out much. I am hoping to offer one thing back and aid others such as you helped me.

  38. I have this error: “Fatal error: Error while attempting OpenID discovery: Can not verify trust chain.”

    I found that in row 441: $trusted = openssl_x509_checkpurpose($cert, X509_PURPOSE_ANY, $this->trust_roots, $untrusted_file);

    $this->trust_roots is array(1) { [0]=> string(73) “/Users/uuu/Sites/aaa/login/Auth/OpenID/ca-bundle.crt” }

    But there is not such file on my server!

    Can you help me?


Leave a comment

Google Apps Premier federated login service with PHP | a32.Blog
Google apps et applications tierces | Fabrice Laffont