diff --git a/doc/phpldapadmin-demo.conf b/doc/phpldapadmin-demo.conf
index 3abc83a..91f8915 100644
--- a/doc/phpldapadmin-demo.conf
+++ b/doc/phpldapadmin-demo.conf
@@ -21,6 +21,8 @@ access to dn.regex="o=Simpsons$"
access to *
by * read
+authz-policy any
+
database bdb
suffix "dc=example.com"
rootdn "cn=Manager,dc=example.com"
diff --git a/lib/HTMLTree.php b/lib/HTMLTree.php
index 193c062..c3f65cc 100644
--- a/lib/HTMLTree.php
+++ b/lib/HTMLTree.php
@@ -128,6 +128,10 @@ class HTMLTree extends Tree {
$this->draw_login_link();
break;
+ case 'config':
+ case 'proxy':
+ break;
+
default:
die(sprintf('Error: %s hasnt been configured for auth_type %s',__METHOD__,$server->getAuthType()));
}
@@ -294,7 +298,7 @@ class HTMLTree extends Tree {
break;
case 'logout':
- if (in_array($server->getAuthType(),array('config','http')))
+ if (in_array($server->getAuthType(),array('config','http','proxy')))
return '';
$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.)'));
}
- /**
- * Draw out link
- */
- protected function draw_logout_link() {
- $server = $this->getServer();
-
- if (! in_array($server->getAuthType(),array('config','http')))
- printf('
| %s |
',
- $this->getDepth()+3-1,get_custom_file($server->getIndex(),'logout',''),$server->getIndex(),_('logout'));
- }
-
/**
* If there is javascript, draw it
*/
diff --git a/lib/ds.php b/lib/ds.php
index 3033eb8..706c4f2 100644
--- a/lib/ds.php
+++ b/lib/ds.php
@@ -128,6 +128,7 @@ abstract class DS {
switch ($this->getValue('login','auth_type')) {
case 'config':
case 'http':
+ case 'proxy':
case 'session':
return $this->getValue('login','auth_type');
@@ -145,7 +146,7 @@ abstract class DS {
public function getLogin($method=null) {
$method = $this->getMethod($method);
- if ($method == 'unauth')
+ if ($method == 'anon')
return '';
switch ($this->getAuthType()) {
@@ -155,6 +156,12 @@ abstract class DS {
else
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 'session':
if (! isset($_SESSION['USER'][$this->index][$method]['name']))
@@ -175,6 +182,12 @@ abstract class DS {
switch ($this->getAuthType()) {
case 'config':
+ return true;
+
+ case 'proxy':
+ if (isset($_SESSION['USER'][$this->index][$method]['proxy']))
+ unset($_SESSION['USER'][$this->index][$method]['proxy']);
+
case 'http':
case 'session':
$_SESSION['USER'][$this->index][$method]['name'] = blowfish_encrypt($user);
@@ -193,11 +206,12 @@ abstract class DS {
protected function getPassword($method=null) {
$method = $this->getMethod($method);
- if ($method == 'unauth')
+ if ($method == 'anon')
return '';
switch ($this->getAuthType()) {
case 'config':
+ case 'proxy':
if (! isset($_SESSION['USER'][$this->index][$method]['pass']))
return $this->getValue('login','bind_pass');
else
@@ -230,6 +244,15 @@ abstract class DS {
# For some authentication types, we need to do the login here
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':
# If our auth vars are not set, throw up a login box.
if (! isset($_SERVER['PHP_AUTH_USER'])) {
@@ -272,6 +295,11 @@ abstract class DS {
break;
+ case 'proxy':
+ $CACHE[$this->index] = $this->login($this->getValue('login','bind_id'),$this->getValue('login','bind_pass'),$method);
+
+ break;
+
default:
$CACHE[$this->index] = is_null($this->getLogin($method)) ? false : true;
}
@@ -287,14 +315,10 @@ abstract class DS {
switch ($this->getAuthType()) {
case 'config':
- if (isset($_SESSION['USER'][$this->index][$method]))
- unset($_SESSION['USER'][$this->index][$method]);
-
return true;
case 'http':
- return true;
-
+ case 'proxy':
case 'session':
if (isset($_SESSION['USER'][$this->index][$method]))
unset($_SESSION['USER'][$this->index][$method]);
diff --git a/lib/ds_ldap.php b/lib/ds_ldap.php
index 2534ac8..9f8103e 100644
--- a/lib/ds_ldap.php
+++ b/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',
'default'=>array());
+ $this->default->proxy['attr'] = array(
+ 'desc'=>'Attribute to use to find the users DN for proxy based authentication',
+ 'default'=>array());
+
# SASL configuration
$this->default->server['sasl'] = array(
'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__);
$this->noconnect = true;
+ $CACHE[$this->index][$method] = null;
system_message(array(
'title'=>sprintf('%s %s',_('Unable to connect to LDAP server'),$this->getName()),
'body'=>sprintf('%s: %s (%s) for %s',_('Error'),$this->getErrorMessage($method),$this->getErrorNum($method),$method),
'type'=>'error'));
- } else
+ } else {
$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'))
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')
$userDN = $user;
else
- $userDN = $this->getLoginID($user,'unauth');
+ $userDN = $this->getLoginID($user,'anon');
if (! $userDN)
return false;
@@ -596,6 +609,106 @@ class ldap extends DS {
$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:
+ *
+ * $servers->setValue('login','auth_type','proxy');
+ *
+ *
+ * @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('%s: %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('%s: %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('%s: %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('%s: %s (%s) for %s',_('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
*/
@@ -946,6 +1059,20 @@ class ldap extends DS {
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 **/
/**
* This function will query the ldap server and request the subSchemaSubEntry which should be the Schema DN.