2015-10-21 16:23:35 +00:00
< ? php
/*
* Copyright ( C ) 2015 Frederic France < frederic . france @ free . fr >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2019-09-23 19:55:30 +00:00
* along with this program . If not , see < https :// www . gnu . org / licenses />.
2015-10-21 16:23:35 +00:00
*/
2022-01-19 19:33:20 +00:00
// This page should make the process to login and get token as described here:
// https://developers.google.com/identity/protocols/oauth2/openid-connect#server-flow
2015-10-21 16:23:35 +00:00
/**
2017-01-06 18:58:38 +00:00
* \file htdocs / core / modules / oauth / google_oauthcallback . php
2015-10-21 16:23:35 +00:00
* \ingroup oauth
* \brief Page to get oauth callback
*/
require '../../../main.inc.php' ;
require_once DOL_DOCUMENT_ROOT . '/includes/OAuth/bootstrap.php' ;
use OAuth\Common\Storage\DoliStorage ;
use OAuth\Common\Consumer\Credentials ;
use OAuth\OAuth2\Service\Google ;
2015-11-06 00:33:49 +00:00
// Define $urlwithroot
2020-02-18 22:47:25 +00:00
$urlwithouturlroot = preg_replace ( '/' . preg_quote ( DOL_URL_ROOT , '/' ) . '$/i' , '' , trim ( $dolibarr_main_url_root ));
$urlwithroot = $urlwithouturlroot . DOL_URL_ROOT ; // This is to use external domain name found into config file
2015-11-06 00:33:49 +00:00
//$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
2020-09-16 17:39:50 +00:00
$action = GETPOST ( 'action' , 'aZ09' );
2015-11-06 00:33:49 +00:00
$backtourl = GETPOST ( 'backtourl' , 'alpha' );
2015-11-05 17:04:00 +00:00
2015-10-21 16:23:35 +00:00
/**
* Create a new instance of the URI class with the current URI , stripping the query string
*/
$uriFactory = new \OAuth\Common\Http\Uri\UriFactory ();
2015-11-06 00:33:49 +00:00
//$currentUri = $uriFactory->createFromSuperGlobalArray($_SERVER);
//$currentUri->setQuery('');
2016-02-09 13:05:05 +00:00
$currentUri = $uriFactory -> createFromAbsolute ( $urlwithroot . '/core/modules/oauth/google_oauthcallback.php' );
2015-11-06 00:33:49 +00:00
2015-10-21 16:23:35 +00:00
/**
* Load the credential for the service
*/
/** @var $serviceFactory \OAuth\ServiceFactory An OAuth service factory. */
$serviceFactory = new \OAuth\ServiceFactory ();
2015-11-06 00:33:49 +00:00
$httpClient = new \OAuth\Common\Http\Client\CurlClient ();
// TODO Set options for proxy and timeout
// $params=array('CURLXXX'=>value, ...)
//$httpClient->setCurlParameters($params);
$serviceFactory -> setHttpClient ( $httpClient );
2015-10-21 16:23:35 +00:00
// Dolibarr storage
$storage = new DoliStorage ( $db , $conf );
2015-11-06 00:33:49 +00:00
2015-10-21 16:23:35 +00:00
// Setup the credentials for the requests
$credentials = new Credentials (
2020-10-31 13:32:18 +00:00
$conf -> global -> OAUTH_GOOGLE_ID ,
$conf -> global -> OAUTH_GOOGLE_SECRET ,
$currentUri -> getAbsoluteUri ()
2015-10-21 16:23:35 +00:00
);
2022-01-19 19:33:20 +00:00
$state = GETPOST ( 'state' );
2020-02-18 22:47:25 +00:00
$requestedpermissionsarray = array ();
2022-01-19 19:33:20 +00:00
if ( $state ) {
// 'state' parameter is standard to store a hash value and can be used to retrieve some parameters back
$statewithscopeonly = preg_replace ( '/\-.*$/' , '' , $state );
$requestedpermissionsarray = explode ( ',' , $statewithscopeonly ); // Example: 'userinfo_email,userinfo_profile,openid,email,profile,cloud_print'.
2021-02-23 21:03:23 +00:00
}
if ( $action != 'delete' && empty ( $requestedpermissionsarray )) {
2020-10-31 13:32:18 +00:00
print 'Error, parameter state is not defined' ;
exit ;
2015-11-13 01:11:47 +00:00
}
//var_dump($requestedpermissionsarray);exit;
2015-11-06 00:33:49 +00:00
2022-01-19 19:33:20 +00:00
2015-10-21 16:23:35 +00:00
// Instantiate the Api service using the credentials, http client and storage mechanism for the token
2019-12-16 20:06:32 +00:00
// $requestedpermissionsarray contains list of scopes.
// Conversion into URL is done by Reflection on constant with name SCOPE_scope_in_uppercase
2015-11-13 01:11:47 +00:00
$apiService = $serviceFactory -> createService ( 'Google' , $credentials , $storage , $requestedpermissionsarray );
2015-10-21 16:23:35 +00:00
2017-01-06 18:58:38 +00:00
// access type needed to have oauth provider refreshing token
2019-12-16 20:06:32 +00:00
// also note that a refresh token is sent only after a prompt
2015-10-21 16:23:35 +00:00
$apiService -> setAccessType ( 'offline' );
2022-01-19 19:33:20 +00:00
2015-11-06 00:33:49 +00:00
$langs -> load ( " oauth " );
/*
* Actions
*/
2015-11-05 17:04:00 +00:00
2021-02-23 21:03:23 +00:00
if ( $action == 'delete' ) {
2020-10-31 13:32:18 +00:00
$storage -> clearToken ( 'Google' );
2017-11-27 12:45:59 +00:00
2020-10-31 13:32:18 +00:00
setEventMessages ( $langs -> trans ( 'TokenDeleted' ), null , 'mesgs' );
2017-11-27 12:45:59 +00:00
2020-10-31 13:32:18 +00:00
header ( 'Location: ' . $backtourl );
exit ();
2017-11-27 12:45:59 +00:00
}
2015-11-05 17:04:00 +00:00
2022-01-19 19:33:20 +00:00
if ( GETPOST ( 'code' )) { // We are coming from oauth provider page.
2018-03-08 18:50:41 +00:00
dol_syslog ( " We are coming from the oauth provider page " );
2015-11-05 17:04:00 +00:00
2022-01-19 22:01:50 +00:00
// We must validate that the $state is the same than the one into $_SESSION['oauthstateanticsrf'], return error if not.
if ( isset ( $_SESSION [ 'oauthstateanticsrf' ]) && $state != $_SESSION [ 'oauthstateanticsrf' ]) {
print 'Value for state = ' . dol_escape_htmltag ( $state ) . ' differs from value in $_SESSION["oauthstateanticsrf"]. Code is refused.' ;
unset ( $_SESSION [ 'oauthstateanticsrf' ]);
} else {
// This was a callback request from service, get the token
try {
//var_dump($_GET['code']);
//var_dump($state);
//var_dump($apiService); // OAuth\OAuth2\Service\Google
// This request the token
// Result is stored into object managed by class DoliStorage into includes/OAuth/Common/Storage/DoliStorage.php, so into table llx_oauth_token
$token = $apiService -> requestAccessToken ( GETPOST ( 'code' ), $state );
// Note: The extraparams has the 'id_token' than contains a lot of information about the user.
$extraparams = $token -> getExtraParams ();
$jwt = explode ( '.' , $extraparams [ 'id_token' ]);
// Extract the middle part, base64 decode, then json_decode it
if ( ! empty ( $jwt [ 1 ])) {
$userinfo = json_decode ( base64_decode ( $jwt [ 1 ]), true );
// TODO
// We should make the 5 steps of validation of id_token
// Verify that the ID token is properly signed by the issuer. Google-issued tokens are signed using one of the certificates found at the URI specified in the jwks_uri metadata value of the Discovery document.
// Verify that the value of the iss claim in the ID token is equal to https://accounts.google.com or accounts.google.com.
// Verify that the value of the aud claim in the ID token is equal to your app's client ID.
// Verify that the expiry time (exp claim) of the ID token has not passed.
// If you specified a hd parameter value in the request, verify that the ID token has a hd claim that matches an accepted G Suite hosted domain.
/*
$useremailuniq = $userinfo [ 'sub' ];
$useremail = $userinfo [ 'email' ];
$useremailverified = $userinfo [ 'email_verified' ];
$username = $userinfo [ 'name' ];
$userfamilyname = $userinfo [ 'family_name' ];
$usergivenname = $userinfo [ 'given_name' ];
$hd = $userinfo [ 'hd' ];
*/
}
setEventMessages ( $langs -> trans ( 'NewTokenStored' ), null , 'mesgs' );
$backtourl = $_SESSION [ " backtourlsavedbeforeoauthjump " ];
unset ( $_SESSION [ " backtourlsavedbeforeoauthjump " ]);
header ( 'Location: ' . $backtourl );
exit ();
} catch ( Exception $e ) {
print $e -> getMessage ();
2022-01-19 21:26:31 +00:00
}
2020-10-31 13:32:18 +00:00
}
2022-01-19 19:33:20 +00:00
} else {
// If we enter this page without 'code' parameter, we arrive here. this is the case when we want to get the redirect
// to the OAuth provider login page
2020-10-31 13:32:18 +00:00
$_SESSION [ " backtourlsavedbeforeoauthjump " ] = $backtourl ;
2022-01-19 21:49:53 +00:00
if ( ! preg_match ( '/^forlogin/' , $state )) {
$apiService -> setApprouvalPrompt ( 'force' );
}
2020-10-31 13:32:18 +00:00
// This may create record into oauth_state before the header redirect.
// Creation of record with state in this tables depend on the Provider used (see its constructor).
2022-01-19 21:49:53 +00:00
if ( $state ) {
$url = $apiService -> getAuthorizationUri ( array ( 'state' => $state ));
2020-10-31 13:32:18 +00:00
} else {
$url = $apiService -> getAuthorizationUri (); // Parameter state will be randomly generated
}
2022-01-19 21:49:53 +00:00
// Add more param
$url .= '&nonce=' . bin2hex ( random_bytes ( 64 / 8 ));
// TODO Add param hd and/or login_hint
2022-01-19 22:01:50 +00:00
if ( ! preg_match ( '/^forlogin/' , $state )) {
//$url .= 'hd=xxx';
}
2022-01-19 21:49:53 +00:00
2020-10-31 13:32:18 +00:00
// we go on oauth provider authorization page
header ( 'Location: ' . $url );
exit ();
2015-10-21 16:23:35 +00:00
}
2015-11-06 00:33:49 +00:00
/*
* View
*/
2022-01-19 22:01:50 +00:00
// No view at all, just actions, so we never reach this line.
2015-10-21 16:23:35 +00:00
$db -> close ();