📣 We're Hiring!

Let's implement OAuth2 logins with google - A how to :)

This post is designed to take people through this process so that they can implement Google logins for their SuiteCRM instance. I’m going to take people through the process that I used in order to get it working on an instance. There are obviously loads of ways of doing this, but I hope that following through this process will allow people to learn a bit about the SuiteCRM architecture and inspire people to get in and play with the code. Plus loads of people seem to want to be able to do this, and it covers loads of useful areas of the suiteCRM code which might make for interesting discussion.

Google OAuth2 can be implemented in your very own instance by editing just 4 files :grin:

References:

Process:

  1. Create an OAuth 2.0 Client ID:
    https://console.cloud.google.com/apis/credentials
    This needs to be for a web application. You need to configure some information that will be needed by your code:
    URIs - e.g. https://mydomain.com
    Authorized redirect URI - e.g. https://mydomain.com/index.php?entryPoint=GoogleSignIn
    (which is pointing to the entry point that we’re going to use.

Google will then kindly give you a ClientID and a Client Secret.

  1. Install the Google API code. This should have been simply:
    composer require google/apiclient:"^2.0"

in the web root, however on my system I got:
’ * PHP Fatal error: Allowed memory size of 1610612736 bytes exhausted’
and had to temporarily increase the setting in php.ini to 2G from 256M and then return it once complete. Whilst at it I did a:
composer update
composer self update

We managed to get men on the moon with less than 4k - See https://en.wikipedia.org/wiki/Apollo_Guidance_Computer

  1. Add an entry point which will match up with the entry point declared in your Google API configuration in point 1 above:
    edit httpdocs/custom/Extension/application/Ext/EntryPointRegistry/GoogleSignIn.php:
    <?php
    // httpdocs/custom/Extension/application/Ext/EntryPointRegistry/GoogleSignIn.php entry point

        $entry_point_registry['GoogleSignIn'] = array(
          'file' => 'modules/GoogleSignIn/GoogleSignIn.php',
          'auth' => false
        );
  1. Add the main code to carry out the authentication in httpdocs/modules/GoogleSignIn/GoogleSignIn.php:
    <?php
    // Google OAuth demo for SuiteCRM
    if (!defined('sugarEntry') || !sugarEntry) {
        die('Not A Valid Entry Point');
    }
    require_once 'vendor/autoload.php';
    global $record;
    global $current_user;
    global $sugar_config;

    // Code modified from https://github.com/googleapis/google-api-php-client
    $clientID = $sugar_config['GoogleSignIn']['clientID'];
    $clientSecret = $sugar_config['GoogleSignIn']['clientSecret'];
    $redirectUri = $sugar_config['GoogleSignIn']['redirectUri'];

    //LoggerManager::getLogger()->warn('ClientID:'.$clientID);
    //LoggerManager::getLogger()->warn('ClientSecret:'.$clientSecret);
    //LoggerManager::getLogger()->warn('redirectUri:'.$redirectUri);

    $client = new Google_Client();
    $client->setClientId($clientID);
    $client->setClientSecret($clientSecret);
    $client->setRedirectUri($redirectUri);

    // authenticate code from Google OAuth Flow
    if (isset($_GET['code'])) {

      $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
      try {
            $client->setAccessToken($token['access_token']);
            // get profile info
            $google_oauth = new Google_Service_Oauth2($client);
            $google_account_info = $google_oauth->userinfo->get();
            $email =  $google_account_info->email;
            $name =  $google_account_info->name;
      } catch (InvalidArgumentException $e) {
    	$_SESSION['login_error'] = "Login Error";
    	header('Location: '."index.php?module=Users&action=Login");
      }
      $user = new User();
      $user->retrieve_by_email_address($email);
      LoggerManager::getLogger()->warn('Starting Login process');
      LoggerManager::getLogger()->warn('User ID is '.$user->id);

      if(empty($user->id)) {
        $_SESSION['login_error'] = "Your email address is not registered - Please contact your support team if the problem persists";
        LoggerManager::getLogger()->warn("Empty $user->id");
        header('Location: '."index.php?module=Home&action=index");
        die();
      }

      $loginURL = "index.php?module={$GLOBALS['sugar_config']['default_module']}&action={$GLOBALS['sugar_config']['default_action']}";
      $loginVars = $GLOBALS['app']->getLoginVars(false);

      require_once('modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php');
      $userAuthenticate = new SugarAuthenticateUser();
      $userAuthenticate->loadUserOnSession($user->id);

      $_SESSION['login_error'] = "Login error - Please contact your support team if the problem persists";
      header('Location: '."index.php?module=Home&action=index");
    }

Plenty of additional Logger lines to help people see what’s actually happening in the suitecrm.log file. Just comment out or delete once you’re happy that it’s working.
The php gets the users email address, and finds the account associated with that email address, and logs them in. N.B. Potential for an error if multiple accounts have the same email address associated with them.

  1. We need the OAuth information stored somewhere, so add the required values to / config_override.php
    $sugar_config['GoogleSignIn']['enabled'] = true;
    $sugar_config['GoogleSignIn']['redirectUri'] = 'https://mydomain.com/index.php?entryPoint=GoogleSignIn';
    $sugar_config['GoogleSignIn']['clientID'] = 'xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com';
    $sugar_config['GoogleSignIn']['clientSecret'] = 'xxxxxxxxxxxxxxxxxxxxxxx';

Obviously inserting the values that you have been given by Google for this!
Also refer to https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_11.0/Architecture/Configurator/
for aditional information relating to this.

  1. Edit the login template page. I chose to edit custom/themes/SuiteP/login.tpl. (If you look in Login.php you’ll see that there is a list of alternative locations. OK - my approach here is messy, and I just inserted some php directly into the tpl file. I’m sure that there’s better ways to do this. I chose to do it this way as it’s as modular as I could make it. This code was inserted into the tpl file below the main login button and above the password recovery link:
    {php}
            global $sugar_config;
            require_once 'vendor/autoload.php';

            if($sugar_config['GoogleSignIn']['enabled']){
                $client = new Google_Client();
                $client->setClientId($sugar_config['GoogleSignIn']['clientID']);
                $client->setClientSecret($sugar_config['GoogleSignIn']['clientSecret']);
                $client->setRedirectUri($sugar_config['GoogleSignIn']['redirectUri']);
                $client->addScope("email");

                $GOOGLE_SIGNIN_URI = $client->createAuthUrl();
            }

            if($sugar_config['GoogleSignIn']['enabled']){
                echo '<div id="google_signin" style="clear: both; margin-top: 60px;">';
                echo '        <a style="background-color: rgb(0,51,102); color: white; display: block;padding: 10px;border-radius: 3px;margin: 20px 0;" href="'.$GOOGLE_SIGNIN_URI.'" title="Sign in with google">Google login with @my domain.com</a>';
                echo '</div>';
            }
    {/php}

All step 6 does is create a google oauth2 link and a button to press. I know that the styling is in line and I could have messed around with css etc, and don’t get me started on 2 forms with identical html ids on the login page (the main login and the password recovery?)

Usual disclaimer - obviously anyone who implements this will test the solution, and I accept no responsibility for anything, even if your server blows up!

Loads of stuff to discuss with people here, and I’ll try and answer Qs on the above if people want to have a go:)

4 Likes

Or of course, if you don’t want to do it yourself and understand how this works, you can always go for the free SSO package produced by one of our other community members here:

Just tried this and it appears to be broken atm :worried: