SF Feature #2073323 - Using Single Sign On authentication
This commit is contained in:
parent
ed4784b1b6
commit
57d405fe3b
@ -21,6 +21,8 @@ access to dn.regex="o=Simpsons$"
|
|||||||
access to *
|
access to *
|
||||||
by * read
|
by * read
|
||||||
|
|
||||||
|
authz-policy any
|
||||||
|
|
||||||
database bdb
|
database bdb
|
||||||
suffix "dc=example.com"
|
suffix "dc=example.com"
|
||||||
rootdn "cn=Manager,dc=example.com"
|
rootdn "cn=Manager,dc=example.com"
|
||||||
|
@ -128,6 +128,10 @@ class HTMLTree extends Tree {
|
|||||||
$this->draw_login_link();
|
$this->draw_login_link();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'config':
|
||||||
|
case 'proxy':
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
die(sprintf('Error: %s hasnt been configured for auth_type %s',__METHOD__,$server->getAuthType()));
|
die(sprintf('Error: %s hasnt been configured for auth_type %s',__METHOD__,$server->getAuthType()));
|
||||||
}
|
}
|
||||||
@ -294,7 +298,7 @@ class HTMLTree extends Tree {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'logout':
|
case 'logout':
|
||||||
if (in_array($server->getAuthType(),array('config','http')))
|
if (in_array($server->getAuthType(),array('config','http','proxy')))
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
$href = sprintf('cmd.php?cmd=logout&server_id=%s',$server->getIndex());
|
$href = sprintf('cmd.php?cmd=logout&server_id=%s',$server->getIndex());
|
||||||
@ -514,17 +518,6 @@ class HTMLTree extends Tree {
|
|||||||
$this->getDepth()+3-1,_('(Session timed out. Automatically logged out.)'));
|
$this->getDepth()+3-1,_('(Session timed out. Automatically logged out.)'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw out link
|
|
||||||
*/
|
|
||||||
protected function draw_logout_link() {
|
|
||||||
$server = $this->getServer();
|
|
||||||
|
|
||||||
if (! in_array($server->getAuthType(),array('config','http')))
|
|
||||||
printf('<tr><td class="spacer"></td><td colspan="%s"><small><a href="cmd.php?cmd=%s&server_id=%s">%s</a></small></td></tr>',
|
|
||||||
$this->getDepth()+3-1,get_custom_file($server->getIndex(),'logout',''),$server->getIndex(),_('logout'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there is javascript, draw it
|
* If there is javascript, draw it
|
||||||
*/
|
*/
|
||||||
|
38
lib/ds.php
38
lib/ds.php
@ -128,6 +128,7 @@ abstract class DS {
|
|||||||
switch ($this->getValue('login','auth_type')) {
|
switch ($this->getValue('login','auth_type')) {
|
||||||
case 'config':
|
case 'config':
|
||||||
case 'http':
|
case 'http':
|
||||||
|
case 'proxy':
|
||||||
case 'session':
|
case 'session':
|
||||||
return $this->getValue('login','auth_type');
|
return $this->getValue('login','auth_type');
|
||||||
|
|
||||||
@ -145,7 +146,7 @@ abstract class DS {
|
|||||||
public function getLogin($method=null) {
|
public function getLogin($method=null) {
|
||||||
$method = $this->getMethod($method);
|
$method = $this->getMethod($method);
|
||||||
|
|
||||||
if ($method == 'unauth')
|
if ($method == 'anon')
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
switch ($this->getAuthType()) {
|
switch ($this->getAuthType()) {
|
||||||
@ -155,6 +156,12 @@ abstract class DS {
|
|||||||
else
|
else
|
||||||
return blowfish_decrypt($_SESSION['USER'][$this->index][$method]['name']);
|
return blowfish_decrypt($_SESSION['USER'][$this->index][$method]['name']);
|
||||||
|
|
||||||
|
case 'proxy':
|
||||||
|
if (! isset($_SESSION['USER'][$this->index][$method]['proxy']))
|
||||||
|
return $this->getValue('login','bind_id');
|
||||||
|
else
|
||||||
|
return blowfish_decrypt($_SESSION['USER'][$this->index][$method]['proxy']);
|
||||||
|
|
||||||
case 'http':
|
case 'http':
|
||||||
case 'session':
|
case 'session':
|
||||||
if (! isset($_SESSION['USER'][$this->index][$method]['name']))
|
if (! isset($_SESSION['USER'][$this->index][$method]['name']))
|
||||||
@ -175,6 +182,12 @@ abstract class DS {
|
|||||||
|
|
||||||
switch ($this->getAuthType()) {
|
switch ($this->getAuthType()) {
|
||||||
case 'config':
|
case 'config':
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'proxy':
|
||||||
|
if (isset($_SESSION['USER'][$this->index][$method]['proxy']))
|
||||||
|
unset($_SESSION['USER'][$this->index][$method]['proxy']);
|
||||||
|
|
||||||
case 'http':
|
case 'http':
|
||||||
case 'session':
|
case 'session':
|
||||||
$_SESSION['USER'][$this->index][$method]['name'] = blowfish_encrypt($user);
|
$_SESSION['USER'][$this->index][$method]['name'] = blowfish_encrypt($user);
|
||||||
@ -193,11 +206,12 @@ abstract class DS {
|
|||||||
protected function getPassword($method=null) {
|
protected function getPassword($method=null) {
|
||||||
$method = $this->getMethod($method);
|
$method = $this->getMethod($method);
|
||||||
|
|
||||||
if ($method == 'unauth')
|
if ($method == 'anon')
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
switch ($this->getAuthType()) {
|
switch ($this->getAuthType()) {
|
||||||
case 'config':
|
case 'config':
|
||||||
|
case 'proxy':
|
||||||
if (! isset($_SESSION['USER'][$this->index][$method]['pass']))
|
if (! isset($_SESSION['USER'][$this->index][$method]['pass']))
|
||||||
return $this->getValue('login','bind_pass');
|
return $this->getValue('login','bind_pass');
|
||||||
else
|
else
|
||||||
@ -230,6 +244,15 @@ abstract class DS {
|
|||||||
|
|
||||||
# For some authentication types, we need to do the login here
|
# For some authentication types, we need to do the login here
|
||||||
switch ($this->getAuthType()) {
|
switch ($this->getAuthType()) {
|
||||||
|
case 'config':
|
||||||
|
if (! $CACHE[$this->index] = $this->login($this->getLogin($method),$this->getPassword($method),$method))
|
||||||
|
system_message(array(
|
||||||
|
'title'=>_('Unable to login.'),
|
||||||
|
'body'=>_('Your configuration file has authentication set to CONFIG based authentication, however, the userid/password failed to login'),
|
||||||
|
'type'=>'error'));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case 'http':
|
case 'http':
|
||||||
# If our auth vars are not set, throw up a login box.
|
# If our auth vars are not set, throw up a login box.
|
||||||
if (! isset($_SERVER['PHP_AUTH_USER'])) {
|
if (! isset($_SERVER['PHP_AUTH_USER'])) {
|
||||||
@ -272,6 +295,11 @@ abstract class DS {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'proxy':
|
||||||
|
$CACHE[$this->index] = $this->login($this->getValue('login','bind_id'),$this->getValue('login','bind_pass'),$method);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$CACHE[$this->index] = is_null($this->getLogin($method)) ? false : true;
|
$CACHE[$this->index] = is_null($this->getLogin($method)) ? false : true;
|
||||||
}
|
}
|
||||||
@ -287,14 +315,10 @@ abstract class DS {
|
|||||||
|
|
||||||
switch ($this->getAuthType()) {
|
switch ($this->getAuthType()) {
|
||||||
case 'config':
|
case 'config':
|
||||||
if (isset($_SESSION['USER'][$this->index][$method]))
|
|
||||||
unset($_SESSION['USER'][$this->index][$method]);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 'http':
|
case 'http':
|
||||||
return true;
|
case 'proxy':
|
||||||
|
|
||||||
case 'session':
|
case 'session':
|
||||||
if (isset($_SESSION['USER'][$this->index][$method]))
|
if (isset($_SESSION['USER'][$this->index][$method]))
|
||||||
unset($_SESSION['USER'][$this->index][$method]);
|
unset($_SESSION['USER'][$this->index][$method]);
|
||||||
|
131
lib/ds_ldap.php
131
lib/ds_ldap.php
@ -79,6 +79,10 @@ class ldap extends DS {
|
|||||||
'desc'=>'Limit logins to users who match any of the following LDAP filters',
|
'desc'=>'Limit logins to users who match any of the following LDAP filters',
|
||||||
'default'=>array());
|
'default'=>array());
|
||||||
|
|
||||||
|
$this->default->proxy['attr'] = array(
|
||||||
|
'desc'=>'Attribute to use to find the users DN for proxy based authentication',
|
||||||
|
'default'=>array());
|
||||||
|
|
||||||
# SASL configuration
|
# SASL configuration
|
||||||
$this->default->server['sasl'] = array(
|
$this->default->server['sasl'] = array(
|
||||||
'desc'=>'Use SASL authentication when binding LDAP server',
|
'desc'=>'Use SASL authentication when binding LDAP server',
|
||||||
@ -209,15 +213,24 @@ class ldap extends DS {
|
|||||||
debug_log('Leaving with FALSE, bind FAILed',16,__FILE__,__LINE__,__METHOD__);
|
debug_log('Leaving with FALSE, bind FAILed',16,__FILE__,__LINE__,__METHOD__);
|
||||||
|
|
||||||
$this->noconnect = true;
|
$this->noconnect = true;
|
||||||
|
$CACHE[$this->index][$method] = null;
|
||||||
|
|
||||||
system_message(array(
|
system_message(array(
|
||||||
'title'=>sprintf('%s %s',_('Unable to connect to LDAP server'),$this->getName()),
|
'title'=>sprintf('%s %s',_('Unable to connect to LDAP server'),$this->getName()),
|
||||||
'body'=>sprintf('<b>%s</b>: %s (%s) for <b>%s</b>',_('Error'),$this->getErrorMessage($method),$this->getErrorNum($method),$method),
|
'body'=>sprintf('<b>%s</b>: %s (%s) for <b>%s</b>',_('Error'),$this->getErrorMessage($method),$this->getErrorNum($method),$method),
|
||||||
'type'=>'error'));
|
'type'=>'error'));
|
||||||
|
|
||||||
} else
|
} else {
|
||||||
$this->noconnect = false;
|
$this->noconnect = false;
|
||||||
|
|
||||||
|
# If this is a proxy session, we need to switch to the proxy user
|
||||||
|
if ($this->isProxyEnabled() && $bind['id'] && $method != 'anon')
|
||||||
|
if (! $this->startProxy($resource,$method)) {
|
||||||
|
$this->noconnect = true;
|
||||||
|
$CACHE[$this->index][$method] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (function_exists('run_hook'))
|
if (function_exists('run_hook'))
|
||||||
run_hook('post_connect',array('server_id'=>$this->index,'method'=>$method,'id'=>$bind['id']));
|
run_hook('post_connect',array('server_id'=>$this->index,'method'=>$method,'id'=>$bind['id']));
|
||||||
|
|
||||||
@ -243,7 +256,7 @@ class ldap extends DS {
|
|||||||
if ($this->getValue('login','attr') == 'dn')
|
if ($this->getValue('login','attr') == 'dn')
|
||||||
$userDN = $user;
|
$userDN = $user;
|
||||||
else
|
else
|
||||||
$userDN = $this->getLoginID($user,'unauth');
|
$userDN = $this->getLoginID($user,'anon');
|
||||||
|
|
||||||
if (! $userDN)
|
if (! $userDN)
|
||||||
return false;
|
return false;
|
||||||
@ -596,6 +609,106 @@ class ldap extends DS {
|
|||||||
$this->getValue('sasl','props'));
|
$this->getValue('sasl','props'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches whether PROXY AUTH has been configured for use with a certain server.
|
||||||
|
*
|
||||||
|
* Users may configure phpLDAPadmin to use PROXY AUTH in config,php thus:
|
||||||
|
* <code>
|
||||||
|
* $servers->setValue('login','auth_type','proxy');
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
private function isProxyEnabled() {
|
||||||
|
return $this->getValue('login','auth_type') == 'proxy' ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If PROXY AUTH is configured, then start it
|
||||||
|
*/
|
||||||
|
private function startProxy($resource,$method) {
|
||||||
|
$rootdse = $this->getRootDSE();
|
||||||
|
|
||||||
|
if (! (isset($rootdse['supportedcontrol']) && in_array('2.16.840.1.113730.3.4.18',$rootdse['supportedcontrol']))) {
|
||||||
|
system_message(array(
|
||||||
|
'title'=>sprintf('%s %s',_('Unable to start proxy connection'),$this->getName()),
|
||||||
|
'body'=>sprintf('<b>%s</b>: %s',_('Error'),_('Your LDAP server doesnt seem to support this control')),
|
||||||
|
'type'=>'error'));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filter = '(&';
|
||||||
|
$dn = '';
|
||||||
|
|
||||||
|
$missing = false;
|
||||||
|
foreach ($this->getValue('proxy','attr') as $attr => $var) {
|
||||||
|
if (! isset($_SERVER[$var])) {
|
||||||
|
system_message(array(
|
||||||
|
'title'=>sprintf('%s %s',_('Unable to start proxy connection'),$this->getName()),
|
||||||
|
'body'=>sprintf('<b>%s</b>: %s (%s)',_('Error'),_('Attribute doesnt exist'),$var),
|
||||||
|
'type'=>'error'));
|
||||||
|
|
||||||
|
$missing = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if ($attr == 'dn') {
|
||||||
|
$dn = $var;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else
|
||||||
|
$filter .= sprintf('(%s=%s)',$attr,$_SERVER[$var]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($missing)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$filter .= ')';
|
||||||
|
|
||||||
|
if (! $dn) {
|
||||||
|
$query['filter'] = $filter;
|
||||||
|
|
||||||
|
foreach ($this->getBaseDN() as $base) {
|
||||||
|
$query['base'] = $base;
|
||||||
|
|
||||||
|
if ($search = $this->query($query,$method))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($search) != 1) {
|
||||||
|
system_message(array(
|
||||||
|
'title'=>sprintf('%s %s',_('Unable to start proxy connection'),$this->getName()),
|
||||||
|
'body'=>sprintf('<b>%s</b>: %s (%s)',_('Error'),_('Search for DN returned the incorrect number of results'),count($search)),
|
||||||
|
'type'=>'error'));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$search = array_pop($search);
|
||||||
|
$dn = $search['dn'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ctrl = array(
|
||||||
|
'oid'=>'2.16.840.1.113730.3.4.18',
|
||||||
|
'value'=>sprintf('dn:%s',$dn),
|
||||||
|
'iscritical' => true);
|
||||||
|
|
||||||
|
if (! ldap_set_option($resource,LDAP_OPT_SERVER_CONTROLS,array($ctrl))) {
|
||||||
|
system_message(array(
|
||||||
|
'title'=>sprintf('%s %s',_('Unable to start proxy connection'),$this->getName()),
|
||||||
|
'body'=>sprintf('<b>%s</b>: %s (%s) for <b>%s</b>',_('Error'),$this->getErrorMessage($method),$this->getErrorNum($method),$method),
|
||||||
|
'type'=>'error'));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION['USER'][$this->index][$method]['proxy'] = blowfish_encrypt($dn);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modify attributes of a DN
|
* Modify attributes of a DN
|
||||||
*/
|
*/
|
||||||
@ -946,6 +1059,20 @@ class ldap extends DS {
|
|||||||
return preg_replace('/\\\([0-9A-Fa-f]{2})/e',"''.chr(hexdec('\\1')).''",$dn);
|
return preg_replace('/\\\([0-9A-Fa-f]{2})/e',"''.chr(hexdec('\\1')).''",$dn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRootDSE($method=null) {
|
||||||
|
$query = array();
|
||||||
|
$query['base'] = '';
|
||||||
|
$query['scope'] = 'base';
|
||||||
|
$query['attrs'] = $this->getValue('server','root_dse_attributes');
|
||||||
|
$query['baseok'] = true;
|
||||||
|
$results = $this->query($query,$method);
|
||||||
|
|
||||||
|
if (is_array($results))
|
||||||
|
return array_change_key_case(array_pop($results));
|
||||||
|
else
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
/** Schema Methods **/
|
/** Schema Methods **/
|
||||||
/**
|
/**
|
||||||
* This function will query the ldap server and request the subSchemaSubEntry which should be the Schema DN.
|
* This function will query the ldap server and request the subSchemaSubEntry which should be the Schema DN.
|
||||||
|
Loading…
Reference in New Issue
Block a user