SF Feature #2073323 - Using Single Sign On authentication

This commit is contained in:
Deon George 2009-07-12 12:01:59 +10:00
parent ed4784b1b6
commit 57d405fe3b
4 changed files with 167 additions and 21 deletions

View File

@ -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"

View File

@ -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
*/ */

View File

@ -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]);

View File

@ -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.