Work on openif authentication mode

This commit is contained in:
Laurent Destailleur 2013-09-18 21:22:24 +02:00
parent 04752dbfbe
commit 491bd76c1b
10 changed files with 266 additions and 130 deletions

View File

@ -1,6 +1,5 @@
<?php
/* Copyright (C) 2007-2008 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2007-2009 Regis Houssin <regis.houssin@capnetworks.com>
/* Copyright (C) 2013 Laurent Destailleur <eldy@users.sourceforge.net>
*
* 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
@ -17,102 +16,11 @@
*/
/**
* \file htdocs/core/login/functions_myopenid.php
* \file htdocs/core/class/openid.class.php
* \ingroup core
* \brief Authentication functions for OpenId mode
* \brief Class to manage authentication with OpenId
*/
/**
* Check validity of user/password/entity
* If test is ko, reason must be filled into $_SESSION["dol_loginmesg"]
*
* @param string $usertotest Login
* @param string $passwordtotest Password
* @param int $entitytotest Number of instance (always 1 if module multicompany not enabled)
* @return string Login if OK, '' if KO
*/
function check_user_password_myopenid($usertotest,$passwordtotest,$entitytotest)
{
global $_POST,$db,$conf,$langs;
dol_syslog("functions_dolibarr::check_user_password_myopenid usertotest=".$usertotest);
$login='';
// Get identity from user and redirect browser to OpenID Server
if (isset($_POST['username']))
{
$openid = new SimpleOpenID();
$openid->SetIdentity($_POST['username']);
$protocol = ($conf->file->main_force_https ? 'https://' : 'http://');
$openid->SetTrustRoot($protocol . $_SERVER["HTTP_HOST"]);
$openid->SetRequiredFields(array('email','fullname'));
$_SESSION['dol_entity'] = $_POST["entity"];
//$openid->SetOptionalFields(array('dob','gender','postcode','country','language','timezone'));
if ($openid->GetOpenIDServer())
{
$openid->SetApprovedURL($protocol . $_SERVER["HTTP_HOST"] . $_SERVER["SCRIPT_NAME"]); // Send Response from OpenID server to this script
$openid->Redirect(); // This will redirect user to OpenID Server
}
else
{
$error = $openid->GetError();
return false;
}
return false;
}
// Perform HTTP Request to OpenID server to validate key
elseif($_GET['openid_mode'] == 'id_res')
{
$openid = new SimpleOpenID();
$openid->SetIdentity($_GET['openid_identity']);
$openid_validation_result = $openid->ValidateWithServer();
if ($openid_validation_result == true)
{
// OK HERE KEY IS VALID
$sql ="SELECT login";
$sql.=" FROM ".MAIN_DB_PREFIX."user";
$sql.=" WHERE openid = '".$db->escape($_GET['openid_identity'])."'";
$sql.=" AND entity IN (0," . ($_SESSION["dol_entity"] ? $_SESSION["dol_entity"] : 1) . ")";
dol_syslog("functions_dolibarr::check_user_password_myopenid sql=".$sql);
$resql=$db->query($sql);
if ($resql)
{
$obj=$db->fetch_object($resql);
if ($obj)
{
$login=$obj->login;
}
}
}
else if($openid->IsError() == true)
{
// ON THE WAY, WE GOT SOME ERROR
$error = $openid->GetError();
return false;
}
else
{
// Signature Verification Failed
//echo "INVALID AUTHORIZATION";
return false;
}
}
else if ($_GET['openid_mode'] == 'cancel')
{
// User Canceled your Request
//echo "USER CANCELED REQUEST";
return false;
}
return $login;
}
/**
* Class to manage OpenID
*/
@ -416,9 +324,22 @@ class SimpleOpenID
return $ret;
}
function GetOpenIDServer()
/**
* Get openid server
*
* @param string $url Url to found endpoint
* @return string Endpoint
*/
function GetOpenIDServer($url='')
{
$response = $this->CURL_Request($this->openid_url_identity);
global $conf;
include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
if (empty($url)) $url=$conf->global->MAIN_AUTHENTICATION_OPENID_URL;
$response = getURLContent($url);
list($servers, $delegates) = $this->HTML2OpenIDServer($response);
if (count($servers) == 0){
$this->ErrorStore('OPENID_NOSERVERSFOUND');
@ -517,6 +438,61 @@ class SimpleOpenID
return false;
}
}
/**
* Get XRDS response and set possible servers.
*
* @param string $url Url of endpoint to request
* @return string First endpoint OpenID server found. False if it failed to found.
*/
function sendDiscoveryRequestToGetXRDS($url='')
{
global $conf;
include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
if (empty($url)) $url=$conf->global->MAIN_AUTHENTICATION_OPENID_URL;
dol_syslog(get_class($this).'::sendDiscoveryRequestToGetXRDS get XRDS');
$addheaders=array('Accept: application/xrds+xml');
$response = getURLContent($url, 'GET', '', 1, $addheaders);
/* response should like this:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
<XRD>
<Service priority="0">
<Type>http://specs.openid.net/auth/2.0/server</Type>
<Type>http://openid.net/srv/ax/1.0</Type>
...
<URI>https://www.google.com/accounts/o8/ud</URI>
</Service>
</XRD>
</xrds:XRDS>
*/
$content=$response['content'];
$server='';
if (preg_match('/'.preg_quote('<URI>','/').'(.*)'.preg_quote('</URI>','/').'/is', $content, $reg))
{
$server=$reg[1];
}
if (empty($server))
{
$this->ErrorStore('OPENID_NOSERVERSFOUND');
return false;
}
else
{
dol_syslog(get_class($this).'::sendDiscoveryRequestToGetXRDS found endpoint = '.$server);
$this->SetOpenIDServer($server);
return $server;
}
}
}
?>

View File

@ -25,12 +25,14 @@
/**
* Function get content from an URL (use proxy if proxy defined)
*
* @param string $url URL to call.
* @param string $postorget 'post' = POST, 'get='GET'
* @param string $param Paraemeters of URL (x=value1&y=value2)
* @return array returns an associtive array containing the response from the server.
* @param string $url URL to call.
* @param string $postorget 'POST', 'GET', 'HEAD'
* @param string $param Paraemeters of URL (x=value1&y=value2)
* @param string $followlocation 1=Follow location, 0=Do not follow
* @param array $addhearers Array of string to add into header. Example: ('Accept: application/xrds+xml', ....)
* @return array Returns an associative array containing the response from the server array('content'=>response,'curl_error_no'=>errno,'curl_error_msg'=>errmsg...)
*/
function getURLContent($url,$postorget='GET',$param='')
function getURLContent($url,$postorget='GET',$param='',$followlocation=1,$addheaders=array())
{
//declaring of global variables
global $conf, $langs;
@ -52,6 +54,11 @@ function getURLContent($url,$postorget='GET',$param='')
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_SSLVERSION, 3); // Force SSLv3
curl_setopt($ch, CURLOPT_USERAGENT, 'Dolibarr geturl function');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, ($followlocation?true:false));
if (count($addheaders)) curl_setopt($ch, CURLOPT_HTTPHEADER, $addheaders);
curl_setopt($ch, CURLINFO_HEADER_OUT, true); // To be able to retrieve request header and log it
//turning off the server and peer verification(TrustManager Concept).
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
@ -60,9 +67,21 @@ function getURLContent($url,$postorget='GET',$param='')
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, empty($conf->global->MAIN_USE_CONNECT_TIMEOUT)?5:$conf->global->MAIN_USE_CONNECT_TIMEOUT);
curl_setopt($ch, CURLOPT_TIMEOUT, empty($conf->global->MAIN_USE_RESPONSE_TIMEOUT)?30:$conf->global->MAIN_USE_RESPONSE_TIMEOUT);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
if ($postorget == 'POST') curl_setopt($ch, CURLOPT_POST, 1);
else curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // We want response
if ($postorget == 'POST')
{
curl_setopt($ch, CURLOPT_POST, 1); // POST
curl_setopt($ch, CURLOPT_POSTFIELDS, $param); // Setting param x=a&y=z as POST fields
}
else if ($postorget == 'HEAD')
{
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD'); // HTTP request is 'HEAD'
curl_setopt($ch, CURLOPT_NOBODY, true);
}
else
{
curl_setopt($ch, CURLOPT_POST, 0); // GET
}
//if USE_PROXY constant set to TRUE in Constants.php, then only proxy will be enabled.
if ($USE_PROXY)
@ -73,18 +92,18 @@ function getURLContent($url,$postorget='GET',$param='')
if ($PROXY_USER) curl_setopt($ch, CURLOPT_PROXYUSERPWD, $PROXY_USER. ":" . $PROXY_PASS);
}
//setting the nvpreq as POST FIELD to curl
curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
//getting response from server
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HEADER_OUT); // Reading of request must be done after sending request
dol_syslog("getURLContent request=".$status);
dol_syslog("getURLContent response=".$response);
$rep=array();
$rep['content']=$response;
$rep['curl_error_no']='';
$rep['curl_error_msg']='';
dol_syslog("getURLContent response=".$response);
if (curl_errno($ch))
{
@ -98,7 +117,7 @@ function getURLContent($url,$postorget='GET',$param='')
{
$info = curl_getinfo($ch);
$rep['header_size']=$info['header_size'];
//closing the curl
curl_close($ch);
}

View File

@ -0,0 +1,116 @@
<?php
/* Copyright (C) 2007-2013 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2007-2009 Regis Houssin <regis.houssin@capnetworks.com>
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \file htdocs/core/login/functions_openid.php
* \ingroup core
* \brief Authentication functions for OpenId mode
*/
include_once DOL_DOCUMENT_ROOT.'/core/class/openid.class.php';
/**
* Check validity of user/password/entity
* If test is ko, reason must be filled into $_SESSION["dol_loginmesg"]
*
* @param string $usertotest Login
* @param string $passwordtotest Password
* @param int $entitytotest Number of instance (always 1 if module multicompany not enabled)
* @return string Login if OK, '' if KO
*/
function check_user_password_openid($usertotest,$passwordtotest,$entitytotest)
{
global $_POST,$db,$conf,$langs;
dol_syslog("functions_openid::check_user_password_openid usertotest=".$usertotest);
$login='';
// Get identity from user and redirect browser to OpenID Server
if (isset($_POST['username']))
{
$openid = new SimpleOpenID();
$openid->SetIdentity($_POST['username']);
$protocol = ($conf->file->main_force_https ? 'https://' : 'http://');
$openid->SetTrustRoot($protocol . $_SERVER["HTTP_HOST"]);
$openid->SetRequiredFields(array('email','fullname'));
$_SESSION['dol_entity'] = $_POST["entity"];
//$openid->SetOptionalFields(array('dob','gender','postcode','country','language','timezone'));
if ($openid->sendDiscoveryRequestToGetXRDS())
{
$openid->SetApprovedURL($protocol . $_SERVER["HTTP_HOST"] . $_SERVER["SCRIPT_NAME"]); // Send Response from OpenID server to this script
$openid->Redirect(); // This will redirect user to OpenID Server
}
else
{
$error = $openid->GetError();
return false;
}
return false;
}
// Perform HTTP Request to OpenID server to validate key
elseif($_GET['openid_mode'] == 'id_res')
{
$openid = new SimpleOpenID();
$openid->SetIdentity($_GET['openid_identity']);
$openid_validation_result = $openid->ValidateWithServer();
if ($openid_validation_result == true)
{
// OK HERE KEY IS VALID
$sql ="SELECT login";
$sql.=" FROM ".MAIN_DB_PREFIX."user";
$sql.=" WHERE openid = '".$db->escape($_GET['openid_identity'])."'";
$sql.=" AND entity IN (0," . ($_SESSION["dol_entity"] ? $_SESSION["dol_entity"] : 1) . ")";
dol_syslog("functions_openid::check_user_password_openid sql=".$sql);
$resql=$db->query($sql);
if ($resql)
{
$obj=$db->fetch_object($resql);
if ($obj)
{
$login=$obj->login;
}
}
}
else if($openid->IsError() == true)
{
// ON THE WAY, WE GOT SOME ERROR
$error = $openid->GetError();
return false;
}
else
{
// Signature Verification Failed
//echo "INVALID AUTHORIZATION";
return false;
}
}
else if ($_GET['openid_mode'] == 'cancel')
{
// User Canceled your Request
//echo "USER CANCELED REQUEST";
return false;
}
return $login;
}
?>

View File

@ -152,6 +152,27 @@ if ($forgetpasslink || $helpcenterlink)
}
echo '</div>';
}
if (isset($conf->file->main_authentication) && preg_match('/openid/',$conf->file->main_authentication))
{
$langs->load("users");
//if (! empty($conf->global->MAIN_OPENIDURL_PERUSER)) $url=
echo '<br>';
echo '<div align="center" style="margin-top: 4px;">';
$url=$conf->global->MAIN_AUTHENTICATION_OPENID_URL;
if (! empty($url)) print '<a class="alogin" href="'.$url.'">'.$langs->trans("LoginUsingOpenID").'</a>';
else
{
$langs->load("errors");
print '<font class="warning">'.$langs->trans("ErrorOpenIDSetupNotComplete",'MAIN_AUTHENTICATION_OPENID_URL').'</font>';
}
echo '</div>';
}
?>
</div>

View File

@ -126,6 +126,7 @@ ErrorFailedToAddContact=Failed to add contact
ErrorDateMustBeBeforeToday=The date can not be greater than today
ErrorPaymentModeDefinedToWithoutSetup=A payment mode was set to type %s but setup of module Invoice was not completed to define information to show for this payment mode.
ErrorPHPNeedModule=Error, your PHP must have module <b>%s</b> installed to use this feature.
ErrorOpenIDSetupNotComplete=You setup Dolibarr config file to allow OpenID authentication, but URL of OpenID service is not defined into constant %s
# Warnings
WarningMandatorySetupNotComplete=Mandatory setup parameters are not yet defined

View File

@ -117,4 +117,5 @@ DontDowngradeSuperAdmin=Only a superadmin can downgrade a superadmin
HierarchicalResponsible=Hierarchical responsible
HierarchicView=Hierarchical view
UseTypeFieldToChange=Use field Type to change
OpenIDURL=OpenID URL
LoginUsingOpenID=Login using OpenID

View File

@ -126,6 +126,7 @@ ErrorFailedToAddContact=Echec à l'ajout du contact
ErrorDateMustBeBeforeToday=La date ne peut pas être supérieure à aujourd'hui
ErrorPaymentModeDefinedToWithoutSetup=Un mode de paiement a été défini de type %s mais la configuration du module Facture n'a pas été complété pour définir les informations afficher pour ce mode de paiment.
ErrorPHPNeedModule=Erreur, votre PHP doit avoir le module <b>%s</b> installé pour utiliser cette fonctionnalité.
ErrorOpenIDSetupNotComplete=Vous avez configuré Dolibarr pour accepter l'authentication OpenID, mais l'URL du service OpenID n'est pas défini dans la constante %s
# Warnings
WarningMandatorySetupNotComplete=Les informations de configuration obligatoire doivent être renseignées

View File

@ -117,3 +117,5 @@ DontDowngradeSuperAdmin=Seul un superadministrateur peut rétrograder un superad
HierarchicalResponsible=Responsable hiérarchique
HierarchicView=Vue hiérarchique
UseTypeFieldToChange=Modifier le champ Type pour changer
OpenIDURL=URL de connexion OpenID
LoginUsingOpenID=Se logguer via OpenID

View File

@ -435,7 +435,7 @@ if (! defined('NOLOGIN'))
$login = checkLoginPassEntity($usertotest,$passwordtotest,$entitytotest,$authmode);
if ($login)
{
$dol_authmode=$conf->authmode; // This properties is defined only when logged to say what mode was successfully used
$dol_authmode=$conf->authmode; // This properties is defined only when logged, to say what mode was successfully used
$dol_tz=$_POST["tz"];
$dol_tz_string=$_POST["tz_string"];
$dol_dst=0;

View File

@ -1049,7 +1049,7 @@ else
print '</td>';
print '</tr>'."\n";
if (isset($conf->authmode) && preg_match('/myopenid/',$conf->authmode)) $rowspan++;
if (isset($conf->file->main_authentication) && preg_match('/openid/',$conf->file->main_authentication) && ! empty($conf->global->MAIN_OPENIDURL_PERUSER)) $rowspan++;
if (! empty($conf->societe->enabled)) $rowspan++;
if (! empty($conf->adherent->enabled)) $rowspan++;
@ -1188,7 +1188,7 @@ else
}
print '</td>';
print "</tr>\n";
// Accountancy code
if (! empty($conf->global->USER_ENABLE_ACCOUNTANCY_CODE)) // For the moment field is not used so must not appeared.
{
@ -1196,7 +1196,7 @@ else
print '<tr><td valign="top">'.$langs->trans("AccountancyCode").'</td>';
print '<td>'.$object->accountancy_code.'</td>';
}
// Status
print '<tr><td valign="top">'.$langs->trans("Status").'</td>';
print '<td>';
@ -1212,10 +1212,9 @@ else
print '<td>'.dol_print_date($object->datepreviouslogin,"dayhour").'</td>';
print "</tr>\n";
if (isset($conf->authmode) && preg_match('/myopenid/',$conf->authmode))
if (isset($conf->file->main_authentication) && preg_match('/openid/',$conf->file->main_authentication) && ! empty($conf->global->MAIN_OPENIDURL_PERUSER))
{
print '<tr><td valign="top">'.$langs->trans("url_openid").'</td>';
print '<tr><td valign="top">'.$langs->trans("OpenIDURL").'</td>';
print '<td>'.$object->openid.'</td>';
print "</tr>\n";
}
@ -1512,7 +1511,10 @@ else
*/
if ($action == 'edit' && ($canedituser || $caneditfield || $caneditpassword || ($user->id == $object->id)))
{
$rowspan=14;
$rowspan=15;
if (isset($conf->file->main_authentication) && preg_match('/openid/',$conf->file->main_authentication) && ! empty($conf->global->MAIN_OPENIDURL_PERUSER)) $rowspan++;
if (! empty($conf->societe->enabled)) $rowspan++;
if (! empty($conf->adherent->enabled)) $rowspan++;
print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'" method="POST" name="updateuser" enctype="multipart/form-data">';
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
@ -1520,9 +1522,6 @@ else
print '<input type="hidden" name="entity" value="'.$object->entity.'">';
print '<table width="100%" class="border">';
if (! empty($conf->societe->enabled)) $rowspan++;
if (! empty($conf->adherent->enabled)) $rowspan++;
print '<tr><td width="25%" valign="top">'.$langs->trans("Ref").'</td>';
print '<td colspan="2">';
print $object->id;
@ -1791,17 +1790,17 @@ else
}
print '</td></tr>';
// openid
if (isset($conf->authmode) && preg_match('/myopenid/',$conf->authmode))
// OpenID url
if (isset($conf->file->main_authentication) && preg_match('/openid/',$conf->file->main_authentication) && ! empty($conf->global->MAIN_OPENIDURL_PERUSER))
{
print "<tr>".'<td valign="top">'.$langs->trans("url_openid").'</td>';
print "<tr>".'<td valign="top">'.$langs->trans("OpenIDURL").'</td>';
print '<td>';
if ($caneditfield && !$object->ldap_sid)
if ($caneditfield)
{
print '<input size="40" type="text" name="openid" class="flat" value="'.$object->openid.'">';
print '<input size="40" type="url" name="openid" class="flat" value="'.$object->openid.'">';
}
else
{
{
print '<input type="hidden" name="openid" value="'.$object->openid.'">';
print $object->openid;
}
@ -1824,7 +1823,7 @@ else
}
print '</td>';
print "</tr>\n";
// Accountancy code
print "<tr>";
print '<td valign="top">'.$langs->trans("AccountancyCode").'</td>';