From 6e6a7a6e4ef51dbe9489aff3b306e1c208de272a Mon Sep 17 00:00:00 2001 From: Deon George Date: Fri, 21 Aug 2009 15:02:12 +1000 Subject: [PATCH] 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". --- config/config.php.example | 42 ++++++------ htdocs/js/search_util.js | 76 -------------------- lib/QueryRender.php | 14 ++-- lib/TemplateRender.php | 2 +- lib/Tree.php | 2 +- lib/ds.php | 6 +- lib/ds_ldap.php | 75 ++++++++++++++------ lib/ds_ldap_pla.php | 141 ++++++++++---------------------------- lib/functions.php | 13 ++-- 9 files changed, 127 insertions(+), 244 deletions(-) delete mode 100644 htdocs/js/search_util.js diff --git a/config/config.php.example b/config/config.php.example index 2ce0b22..f809a0b 100644 --- a/config/config.php.example +++ b/config/config.php.example @@ -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=,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=,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); diff --git a/htdocs/js/search_util.js b/htdocs/js/search_util.js deleted file mode 100644 index 205ee94..0000000 --- a/htdocs/js/search_util.js +++ /dev/null @@ -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; -} - - diff --git a/lib/QueryRender.php b/lib/QueryRender.php index 9b23962..74a7caf 100644 --- a/lib/QueryRender.php +++ b/lib/QueryRender.php @@ -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('
', - $this->getAjaxRef($base), ($show == $this->getAjaxRef($base) ? '' : 'none')); + $this->getAjaxRef($base), ($show == $this->getAjaxRef($base) ? 'block' : 'none')); echo ''; echo ''; - $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('', - $j%2 ? 'even' : 'odd',$j,$counter,$j,$counter); + printf('', + $j%2 ? 'even' : 'odd',$j,$j); # Is mass action enabled. if ($_SESSION[APPCONFIG]->getValue('mass','enabled')) - printf('',$j,$counter,$dndetails['dn']); + printf('',$j,$dndetails['dn']); $href = sprintf('cmd=template_engine&server_id=%s&dn=%s',$server->getIndex(),rawurlencode($dndetails['dn'])); printf('', @@ -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'; } } } diff --git a/lib/TemplateRender.php b/lib/TemplateRender.php index 2784cce..b731544 100644 --- a/lib/TemplateRender.php +++ b/lib/TemplateRender.php @@ -1325,7 +1325,7 @@ class TemplateRender extends PageRender { if (DEBUGTMP) printf('%s
',__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()) diff --git a/lib/Tree.php b/lib/Tree.php index 4224ad7..55bba8f 100644 --- a/lib/Tree.php +++ b/lib/Tree.php @@ -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; diff --git a/lib/ds.php b/lib/ds.php index badec59..43807d2 100644 --- a/lib/ds.php +++ b/lib/ds.php @@ -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']); diff --git a/lib/ds_ldap.php b/lib/ds_ldap.php index ed84c3a..bc8a70c 100644 --- a/lib/ds_ldap.php +++ b/lib/ds_ldap.php @@ -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'); } /** diff --git a/lib/ds_ldap_pla.php b/lib/ds_ldap_pla.php index 02bee5c..f45b1de 100644 --- a/lib/ds_ldap_pla.php +++ b/lib/ds_ldap_pla.php @@ -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. * @@ -130,10 +129,10 @@ class ldap_pla extends ldap { * * The entry creation command must be available. * - * $config->custom->commands['all'] = array('entry_create' => true); + * $config->custom->commands['script'] = array('create' => true); * * - * @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: - * - * $servers->setValue('login','attr',''); - * - * - * 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: - * - * $servers->setValue('login','attr','string'); - * - * - * @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: - * - * $servers->setValue('login','login_string','uid=,ou=People,dc=example,dc=com'); - * - * - * @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: * * if ($ldapserver->isMultiLineAttr('postalAddress')) - * echo ""; + * echo ''; * else - * echo ""; + * echo ''; * * - * @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: - * - * $config->custom->appearance['readonly_attrs'] = array('objectClass'); - * + * 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: + * + * $config->custom->appearance['readonly_attrs'] = array('objectClass'); + * + * + * @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'); * * - * @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); } /** diff --git a/lib/functions.php b/lib/functions.php index 05e4a13..3bcbc63 100644 --- a/lib/functions.php +++ b/lib/functions.php @@ -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)
'; @@ -378,7 +379,6 @@ function hideall(key,except) { echo ''; echo '
icon