Multiple fixes, changes and enhancements

* mass edit selection,
* child search during edit,
* attr login with bind_id,
* performance fix broke ldapservers that dont have havesubordinate attrs),
* enable "login,class",
* enable "login,base".
This commit is contained in:
Deon George 2009-08-21 15:02:12 +10:00
parent 95aedef718
commit 6e6a7a6e4e
9 changed files with 127 additions and 244 deletions

View File

@ -72,6 +72,13 @@
30 seconds or the setting of max_exection_time if this is null. */
// $config->custom->session['timelimit'] = 30;
/* Our local timezone
This is to make sure that when we ask the system for the current time, we
get the right local time. If this is not set, all time() calculations will
assume UTC if you have not set PHP date.timezone. */
// $config->custom->appearance['timezone'] = null;
# $config->custom->appearance['timezone'] = 'Australia/Melbourne';
/*********************************************/
/* Commands */
/*********************************************/
@ -290,12 +297,12 @@ $servers->setValue('server','name','My LDAP Server');
/* The DN of the user for phpLDAPadmin to bind with. For anonymous binds or
'cookie' or 'session' auth_types, LEAVE THE LOGIN_DN AND LOGIN_PASS BLANK. If
you specify a login_attr in conjunction with a cookie or session auth_type,
then you can also specify the login_dn/login_pass here for searching the
then you can also specify the bind_dn/bind_pass here for searching the
directory for users (ie, if your LDAP server does not allow anonymous binds. */
// $servers->setValue('login','bind_id','');
# $servers->setValue('login','bind_id','cn=Manager,dc=example,dc=com');
/* Your LDAP password. If you specified an empty login_dn above, this MUST also
/* Your LDAP password. If you specified an empty bind_dn above, this MUST also
be blank. */
// $servers->setValue('login','bind_pass','');
# $servers->setValue('login','bind_pass','secret');
@ -343,8 +350,7 @@ $servers->setValue('server','name','My LDAP Server');
# $servers->setValue('server','sasl_authz_id_replacement','$1');
/* SASL auth security props.
See http://beepcore-tcl.sourceforge.net/tclsasl.html#anchor5 for explanation.
*/
See http://beepcore-tcl.sourceforge.net/tclsasl.html#anchor5 for explanation. */
// $servers->setValue('server','sasl_props',null);
/* Default password hashing algorithm. One of md5, ssha, sha, md5crpyt, smd5,
@ -357,11 +363,19 @@ $servers->setValue('server','name','My LDAP Server');
and log in as that user.
Leave blank or specify 'dn' to use full DN for logging in. Note also that if
your LDAP server requires you to login to perform searches, you can enter the
DN to use when searching in 'login_dn' and 'login_pass' above. You may also
specify 'string', in which case you can provide a string to use for logging
users in. See 'login_string' directly below. */
DN to use when searching in 'bind_dn' and 'bind_pass' above.
// $servers->setValue('login','attr','dn');
/* Base DNs to used for logins. If this value is not set, then the LDAP server
Base DNs are used. */
// $servers->setValue('login','base',array());
/* If 'login,attr' is used above such that phpLDAPadmin will search for your DN
at login, you may restrict the search to a specific objectClasses. EG, set this
to array('posixAccount') or array('inetOrgPerson',..), depending upon your
setup. */
// $servers->setValue('login','class',array());
/* If you specified something different from 'dn', for example 'uid', as the
login_attr above, you can optionally specify here to fall back to
authentication with dn.
@ -371,19 +385,6 @@ $servers->setValue('server','name','My LDAP Server');
When using this feature, login_class is ignored. */
// $servers->setValue('login','fallback_dn',false);
/* If you specified 'cookie' or 'session' as the auth_type above, and you
specified 'string' for 'login_attr' above, you must provide a string here for
logging users in. If, for example, I have a lot of user entries with DNs like
"uid=dsmith,ou=People,dc=example,dc=com", then I can specify a string
"uid=<username>,ou=People,dc=example,dc=com" and my users can login with
their user names alone, ie: "dsmith" in this case. */
# $servers->setValue('login','string','uid=<username>,ou=People,dc=example,dc=com');
/* If 'login_attr' is used above such that phpLDAPadmin will search for your DN
at login, you may restrict the search to a specific objectClass. EG, set this
to 'posixAccount' or 'inetOrgPerson', depending upon your setup. */
// $servers->setValue('login','class',null);
/* Specify true If you want phpLDAPadmin to not display or permit any
modification to the LDAP server. */
// $servers->setValue('server','read_only',false);
@ -516,7 +517,6 @@ $servers->setValue('server','sasl_props',null);
$servers->setValue('appearance','password_hash','md5');
$servers->setValue('login','attr','dn');
$servers->setValue('login','fallback_dn',false);
$servers->setValue('login','string',null);
$servers->setValue('login','class',null);
$servers->setValue('server','read_only',false);
$servers->setValue('appearance','show_create',true);

View File

@ -1,76 +0,0 @@
// File: search_util.js
// Purpose:
// This JavaScript file defines some functions used by the two search forms for
// auto-populating the base DN dynamically when a server is selected from the
// drop-down.
// $Header$
//the array to store the server
var servers = new Array();
//---------------------------------------------------------------------
// Definition of the object server
//---------------------------------------------------------------------
//constructor of the server
//param id the id of the server
//param name the name of the server
//param base_dn the base dn of the server
function server(id,name,base_dn){
//the properties of the object
this.id =id;
this.name = name;
this.base_dn = base_dn;
// the method of the server
this.getId=getId;
this.setId=setId;
this.getName = getName;
this.setName = setName;
this.setBaseDn = setBaseDn;
this.getBaseDn = getBaseDn;
}
// set the id of the server
function setId(id){
this.id = id;
}
//return the id of the server
function getId(){
return this.id;
}
// set the name of the server
function setName(name){
this.name = name;
}
// return the name of the server
function getName(){
return this.name;
}
// return the base dn of the server
function getBaseDn(){
return this.base_dn;
}
// set the base dn of the server
function setBaseDn(base_dn){
this.base_dn = base_dn;
}
//-----------------------------------------------------------------------
// End of the definition of the server
//-----------------------------------------------------------------------
// add a server object to the array of server
function addToServersList(obj_server){
servers[servers.length] = obj_server;
}

View File

@ -271,6 +271,7 @@ function hideall(key,except) {
$this->drawBaseTabs();
$ado = $this->template->getAttrDisplayOrder();
$counter = 0;
$j = 0;
foreach ($this->template->results as $base => $results) {
$counter++;
@ -279,7 +280,7 @@ function hideall(key,except) {
$show = ($counter === 1 ? $this->getAjaxRef($base) : null);
printf('<div id="DN%s" style="display: %s">',
$this->getAjaxRef($base), ($show == $this->getAjaxRef($base) ? '' : 'none'));
$this->getAjaxRef($base), ($show == $this->getAjaxRef($base) ? 'block' : 'none'));
echo '<table class="result_box" border=0 width=100%>';
echo '<tr><td>';
@ -378,7 +379,6 @@ function hideall(key,except) {
echo '</thead>';
echo '<tbody class="scroll">';
$j = 0;
foreach ($results as $dndetails) {
$j++;
$dndetails = array_change_key_case($dndetails);
@ -386,12 +386,12 @@ function hideall(key,except) {
# Temporarily set our DN, for rendering that leverages our DN (eg: JpegPhoto)
$this->template->setDN($dndetails['dn']);
printf('<tr class="%s" id="tr_ma_%s_%s" onClick="var cb=document.getElementById(\'ma_%s_%s\'); cb.checked=!cb.checked;">',
$j%2 ? 'even' : 'odd',$j,$counter,$j,$counter);
printf('<tr class="%s" id="tr_ma_%s" onClick="var cb=document.getElementById(\'ma_%s\'); cb.checked=!cb.checked;">',
$j%2 ? 'even' : 'odd',$j,$j);
# Is mass action enabled.
if ($_SESSION[APPCONFIG]->getValue('mass','enabled'))
printf('<td><input type="checkbox" id="ma_%s_%s" name="dn[]" value="%s" onclick="this.checked=!this.checked;" /></td>',$j,$counter,$dndetails['dn']);
printf('<td><input type="checkbox" id="ma_%s" name="dn[]" value="%s" onclick="this.checked=!this.checked;" /></td>',$j,$dndetails['dn']);
$href = sprintf('cmd=template_engine&server_id=%s&dn=%s',$server->getIndex(),rawurlencode($dndetails['dn']));
printf('<td class="icon"><a href="cmd.php?%s"><img src="%s/%s" alt="icon" /></a></td>',
@ -478,8 +478,8 @@ function CheckAll(setbgcolor,form) {
if (e.checked) {
tr.style.backgroundColor='#DDDDFF';
} else {
var id = e.id.substr(2);
tr.style.backgroundColor= id%2 ? '#F0F0F0' : '#E0E0E0';
var id = e.id.substr(3);
tr.style.backgroundColor= id%2 ? '#E0E0E0' : '#F0F0F0';
}
}
}

View File

@ -1325,7 +1325,7 @@ class TemplateRender extends PageRender {
if (DEBUGTMP) printf('<font size=-2>%s</font><br />',__METHOD__);
$href = sprintf('cmd=query_engine&server_id=%s&filter=%s&base=%s&scope=one&query=none&size_limit=0',
$href = sprintf('cmd=query_engine&server_id=%s&filter=%s&base=%s&scope=one&query=none&size_limit=0&search=true',
$this->getServerID(),rawurlencode('objectClass=*'),rawurlencode($this->template->getDN()));
if (isAjaxEnabled())

View File

@ -178,7 +178,7 @@ abstract class Tree {
$tree_factory = new TreeItem($server->getIndex(),$dn);
$tree_factory->setObjectClasses($server->getDNAttrValue($dn,'objectClass'));
if ((($isleaf = $server->getDNAttrValue($dn,'hassubordinates')) && ! strcasecmp($isleaf[0],'false')) || ! $isleaf)
if ((($isleaf = $server->getDNAttrValue($dn,'hassubordinates')) && ! strcasecmp($isleaf[0],'false')))
$tree_factory->setLeaf();
$this->entries[$dnlower] = $tree_factory;

View File

@ -179,7 +179,8 @@ abstract class DS {
case 'http':
case 'session':
if (! isset($_SESSION['USER'][$this->index][$method]['name']))
return null;
# If our bind_id is set, we'll pass that back for logins.
return (! is_null($this->getValue('login','bind_id')) && $method == 'login') ? $this->getValue('login','bind_id') : null;
else
return blowfish_decrypt($_SESSION['USER'][$this->index][$method]['name']);
@ -244,7 +245,8 @@ abstract class DS {
case 'http':
case 'session':
if (! isset($_SESSION['USER'][$this->index][$method]['pass']))
return null;
# If our bind_pass is set, we'll pass that back for logins.
return (! is_null($this->getValue('login','bind_pass')) && $method == 'login') ? $this->getValue('login','bind_pass') : null;
else
return blowfish_decrypt($_SESSION['USER'][$this->index][$method]['pass']);

View File

@ -56,17 +56,6 @@ class ldap extends DS {
'desc'=>'Connect using TLS',
'default'=>false);
/*
* Not used by PLA
$this->default->login['dn'] = array(
'desc'=>'User Login DN',
'default'=>'');
$this->default->login['pass'] = array(
'desc'=>'User Login Password',
'default'=>'');
*/
# Login Details
$this->default->login['attr'] = array(
'desc'=>'Attribute to use to find the users DN',
@ -80,6 +69,14 @@ class ldap extends DS {
'desc'=>'Limit logins to users who match any of the following LDAP filters',
'default'=>array());
$this->default->login['base'] = array(
'desc'=>'Limit logins to users who are in these base DNs',
'default'=>array());
$this->default->login['class'] = array(
'desc'=>'Strict login to users containing a specific objectClasses',
'default'=>array());
$this->default->proxy['attr'] = array(
'desc'=>'Attribute to use to find the users DN for proxy based authentication',
'default'=>array());
@ -146,7 +143,7 @@ class ldap extends DS {
$bind['pass'] = is_null($this->getPassword($method)) && $method != 'anon' ? $this->getPassword('user') : $this->getPassword($method);
# If our bind id is still null, we are not logged in.
if (is_null($bind['id']) && $method != 'anon')
if (is_null($bind['id']) && ! in_array($method,array('anon','login')))
return null;
# If we bound to the LDAP server with these details for a different connection, return that resource
@ -260,7 +257,7 @@ class ldap extends DS {
if (($this->getValue('login','attr') == 'dn') || $method != 'user')
$userDN = $user;
else
$userDN = $this->getLoginID($user,'anon');
$userDN = $this->getLoginID($user,'login');
if (! $userDN)
return false;
@ -473,18 +470,52 @@ class ldap extends DS {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
$query['filter'] = sprintf('(&(uid=%s))',$user);
$query['filter'] = sprintf('(&(%s=%s)%s)',
$this->getValue('login','attr'),$user,
$this->getLoginClass() ? sprintf('(objectclass=%s)',join(')(objectclass=',$this->getLoginClass())) : '');
$query['attrs'] = array('dn');
$result = $this->query($query,$method);
if (count($result) > 1)
die('ERROR: should only have 1 result');
foreach ($this->getLoginBaseDN() as $base) {
$query['base'] = $base;
$result = $this->query($query,$method);
foreach ($result as $detail)
if (! isset($detail['dn']))
die('ERROR: DN missing?');
else
return $detail['dn'];
if (count($result) == 1)
break;
}
if (count($result) != 1)
return null;
$detail = array_shift($result);
if (! isset($detail['dn']))
die('ERROR: DN missing?');
else
return $detail['dn'];
}
/**
* Return the login base DNs
* If no login base DNs are defined, then the LDAP server Base DNs are used.
*/
private function getLoginBaseDN() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,1,__FILE__,__LINE__,__METHOD__,$fargs);
if ($this->getValue('login','base'))
return $this->getValue('login','base');
else
return $this->getBaseDN();
}
/**
* Return the login classes that a user must have to login
*/
private function getLoginClass() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,1,__FILE__,__LINE__,__METHOD__,$fargs);
return $this->getValue('login','class');
}
/**

View File

@ -119,7 +119,6 @@ class ldap_pla extends ldap {
'default'=>null);
}
/** FUNCTIONS TO BE REWORKED BELOW HERE **/
/**
* Gets whether the admin has configured phpLDAPadmin to show the "Create New" link in the tree viewer.
* <code>
@ -130,10 +129,10 @@ class ldap_pla extends ldap {
*
* The entry creation command must be available.
* <code>
* $config->custom->commands['all'] = array('entry_create' => true);
* $config->custom->commands['script'] = array('create' => true);
* </code>
*
* @return boolean True if the feature is enabled and false otherwise.
* @return boolean true if the feature is enabled and false otherwise.
*/
function isShowCreateEnabled() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
@ -145,76 +144,6 @@ class ldap_pla extends ldap {
return $this->getValue('appearance','show_create');
}
/**
* Fetches whether the login_attr feature is enabled for a specified server.
*
* This is configured in config.php thus:
* <code>
* $servers->setValue('login','attr','<ldap attr>');
* </code>
*
* By virtue of the fact that the login_attr is not blank and not 'dn', the
* feature is configured to be enabled.
*
* @return boolean
*/
function isLoginAttrEnabled() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
if ((strcasecmp($this->getLoginAttr(),'dn') != 0) && trim($this->getLoginAttr()))
$return = true;
else
$return = false;
if (DEBUG_ENABLED)
debug_log('Returning (%s)',17,0,__FILE__,__LINE__,__METHOD__,$return);
return $return;
}
/**
* Fetches whether the login_attr feature is enabled for a specified server.
*
* This is configured in config.php thus:
* <code>
* $servers->setValue('login','attr','string');
* </code>
*
* @return boolean
*/
function isLoginStringEnabled() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
if (! strcasecmp($this->getLoginAttr(),'string'))
$return = true;
else
$return = false;
if (DEBUG_ENABLED)
debug_log('Returning (%s)',17,0,__FILE__,__LINE__,__METHOD__,$return);
return $return;
}
/**
* Fetches the login_attr string if enabled for a specified server.
*
* This is configured in config.php thus:
* <code>
* $servers->setValue('login','login_string','uid=<username>,ou=People,dc=example,dc=com');
* </code>
*
* @return string|false
*/
function getLoginString() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
return $this->login_string;
}
/**
* Fetch whether the user has configured a certain server login to be non anonymous
*
@ -265,14 +194,13 @@ class ldap_pla extends ldap {
* Usage example:
* <code>
* if ($ldapserver->isMultiLineAttr('postalAddress'))
* echo "<textarea name=\"postalAddress\"></textarea>";
* echo '<textarea name="postalAddress"></textarea>';
* else
* echo "<input name=\"postalAddress\" type=\"text\">";
* echo '<input name="postalAddress" type="text">';
* </code>
*
* @param string $attr_name The name of the attribute of interestd (case insensivite)
* @param string $val (optional) The current value of the attribute (speeds up the
* process by searching for carriage returns already in the attribute value)
* @param string The name of the attribute of interested (case insensivite)
* @param string (optional) The current value of the attribute (speeds up the process by searching for carriage returns already in the attribute value)
* @return boolean
*/
function isMultiLineAttr($attr_name,$val=null) {
@ -317,23 +245,15 @@ class ldap_pla extends ldap {
}
/**
* Returns true if the specified attribute is configured as read only
* in config.php.
* Attributes are configured as read-only in config.php thus:
* <code>
* $config->custom->appearance['readonly_attrs'] = array('objectClass');
* </code>
* Returns true if the specified attribute is configured according to
* the test enabled in config.php
*
* @param string $attr The name of the attribute to test.
* @param string The name of the attribute to test.
* @param array The attributes to test against.
* @param dn A DN that is exempt from these tests.
* @return boolean
*/
public function isAttrReadOnly($attr) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
$attrs = $_SESSION[APPCONFIG]->getValue('appearance','readonly_attrs');
$except_dn = $_SESSION[APPCONFIG]->getValue('appearance','readonly_attrs_exempt');
private function isAttrTest($attr,$attrs,$except_dn) {
$attr = trim($attr);
if (! trim($attr) || ! count($attrs))
return false;
@ -349,6 +269,27 @@ class ldap_pla extends ldap {
return false;
}
/**
* Returns true if the specified attribute is configured as read only
* in config.php.
* Attributes are configured as read-only in config.php thus:
* <code>
* $config->custom->appearance['readonly_attrs'] = array('objectClass');
* </code>
*
* @param string The name of the attribute to test.
* @return boolean
*/
public function isAttrReadOnly($attr) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
$attrs = $_SESSION[APPCONFIG]->getValue('appearance','readonly_attrs');
$except_dn = $_SESSION[APPCONFIG]->getValue('appearance','readonly_attrs_exempt');
return $this->isAttrTest($attr,$attrs,$except_dn);
}
/**
* Returns true if the specified attribute is configured as hidden
* in config.php.
@ -357,7 +298,7 @@ class ldap_pla extends ldap {
* $config->custom->appearance['hide_attrs'] = array('objectClass');
* </code>
*
* @param string $attr The name of the attribute to test.
* @param string The name of the attribute to test.
* @return boolean
*/
public function isAttrHidden($attr) {
@ -367,19 +308,7 @@ class ldap_pla extends ldap {
$attrs = $_SESSION[APPCONFIG]->getValue('appearance','hide_attrs');
$except_dn = $_SESSION[APPCONFIG]->getValue('appearance','hide_attrs_exempt');
$attr = trim($attr);
if (! trim($attr) || ! count($attrs))
return false;
# Is the user excluded?
if ($except_dn && $this->userIsMember($this->getLogin(),$except_dn))
return false;
foreach ($attrs as $attr_name)
if (strcasecmp($attr,trim($attr_name)) == 0)
return true;
return false;
return $this->isAttrTest($attr,$attrs,$except_dn);
}
/**

View File

@ -208,19 +208,16 @@ function app_version() {
$CACHE = 'UNKNOWN';
else {
$f = fopen($version_file,'r');
$version = trim(fread($f, filesize($version_file)));
fclose($f);
$version = rtrim(file_get_contents($version_file));
$CACHE = preg_replace('/^RELEASE-([0-9\.]+(-.*)*)$/','$1',$version);
# Check if we are a CVS copy.
if (preg_match('/^$/',$CACHE))
$CACHE = 'CVS';
if (preg_match('/^(DEVEL)?$/',$CACHE))
$CACHE = 'DEVEL';
# Check if we are special CVS branch
elseif (preg_match('/^([a-zA-Z]+)?$/',$CACHE,$match))
$CACHE = $match[1];
# Check if we are special DEVEL version
elseif (preg_match('/^DEVEL-([0-9\.]+)+$/',$CACHE)) {}
# If return is still the same as version, then the tag is not one we expect.
elseif ($CACHE == $version)