From 732ea8b9783caae8716aa1a08617bcf5ccbbbf6f Mon Sep 17 00:00:00 2001 From: Deon George Date: Thu, 13 Feb 2014 16:07:03 +1100 Subject: [PATCH] Added Schema Retreival --- classes/Kohana/Database/LDAP.php | 51 +- .../Database/LDAP/Search/Builder/Query.php | 3 +- classes/Kohana/LDAP.php | 3 + classes/Kohana/ORM/LDAP.php | 6 + classes/Kohana/Schema.php | 66 +++ classes/Kohana/Schema/Attribute.php | 464 ++++++++++++++++++ classes/Model/LDAP/Schema.php | 11 + classes/Schema.php | 4 + classes/Schema/Attribute.php | 4 + 9 files changed, 589 insertions(+), 23 deletions(-) create mode 100644 classes/Kohana/Schema.php create mode 100644 classes/Kohana/Schema/Attribute.php create mode 100644 classes/Schema.php create mode 100644 classes/Schema/Attribute.php diff --git a/classes/Kohana/Database/LDAP.php b/classes/Kohana/Database/LDAP.php index 748f3b8..c13a4ba 100644 --- a/classes/Kohana/Database/LDAP.php +++ b/classes/Kohana/Database/LDAP.php @@ -116,29 +116,8 @@ abstract class Kohana_Database_LDAP extends Kohana_LDAP { } if ($this->_instance == 'auth') { - $x = LDAP::factory('schema',NULL,$this->_config); + $this->getSchema(); - try { - // Our Auth Bind credentials are wrong - if ($x->bind((isset($this->_config['schema']['dn']) ? $this->_config['schema']['dn'] : 'fred'),(isset($this->_config['schema']['password']) ? $this->_config['schema']['password'] : 'fred'))) { - - $u = $x->search(array('')) - ->scope('base') - ->where('objectclass','=','*') - ->execute(); - - if (! $u OR ! isset($u[''][0]['subschemasubentry'][0])) - throw new Kohana_Exception('Couldnt find schema?'); - - $x->setSchema(ORM::factory('LDAP_Schema',$u[''][0]['subschemasubentry'][0])); - } - - } catch (Exception $e) { - // If we are a command line, we can just print the error - echo _('Unable to retrieve the SCHEMA from the LDAP server.'); - echo _('The error message is').': '.$e->getMessage(); - die(); - } } if (isset($benchmark)) @@ -305,6 +284,34 @@ abstract class Kohana_Database_LDAP extends Kohana_LDAP { return $status; } + public function getSchema() { + // Make sure our login_attr is DN + if ($this->_instance == 'schema' AND $this->_config['login_attr'] != 'DN') + $this->_config['login_attr'] = 'DN'; + + $x = LDAP::factory('schema'); + + try { + // @todo We should bind as specific shema DN, logged in User or anonymous. + if ($x->bind((isset($this->_config['schema']['dn']) ? $this->_config['schema']['dn'] : FALSE),(isset($this->_config['schema']['password']) ? $this->_config['schema']['password'] : FALSE))) { + $u = $x->search(array('')) + ->scope('base') + ->execute(); + + if (! $u OR ! isset($u[''][0]['subschemasubentry'][0])) + throw new Kohana_Exception('Couldnt find schema?'); + + $x->setSchema(ORM::factory('LDAP_Schema',$u[''][0]['subschemasubentry'][0])); + } + + } catch (Exception $e) { + // If we are a command line, we can just print the error + echo _('Unable to retrieve the SCHEMA from the LDAP server.'); + echo _('The error message is').': '.$e->getMessage(); + die(); + } + } + public function search($base=array()) { return new Database_LDAP_Search($this,$base); } diff --git a/classes/Kohana/Database/LDAP/Search/Builder/Query.php b/classes/Kohana/Database/LDAP/Search/Builder/Query.php index 1234886..2aef85d 100644 --- a/classes/Kohana/Database/LDAP/Search/Builder/Query.php +++ b/classes/Kohana/Database/LDAP/Search/Builder/Query.php @@ -212,7 +212,8 @@ abstract class Kohana_Database_LDAP_Search_Builder_Query extends Database_Query_ return '(|'.$filter.')'; case '': - return '(&(objectClass=*))'; + return 'objectClass=*'; + default: throw new Kohana_Exception('Condition ":condition" not handled.',array(':condition'=>$current_condition)); } diff --git a/classes/Kohana/LDAP.php b/classes/Kohana/LDAP.php index 48478fb..de33e61 100644 --- a/classes/Kohana/LDAP.php +++ b/classes/Kohana/LDAP.php @@ -107,6 +107,9 @@ abstract class Kohana_LDAP extends Database { } public function schema() { + if (is_null($this->_schema)) + $this->getSchema(); + return $this->_schema; } } diff --git a/classes/Kohana/ORM/LDAP.php b/classes/Kohana/ORM/LDAP.php index 4d44765..098b02d 100644 --- a/classes/Kohana/ORM/LDAP.php +++ b/classes/Kohana/ORM/LDAP.php @@ -34,6 +34,12 @@ abstract class Kohana_ORM_LDAP extends ORM { } } + public function __get($column) { + $x = parent::__get($column); + + return (! is_object($x) AND is_object(LDAP::factory('schema')->schema()->attribute($column)) AND LDAP::factory('schema')->schema()->attribute($column)->getIsSingleValue()) ? $x[0] : $x; + } + /** * Initializes the Database Builder to given query type * diff --git a/classes/Kohana/Schema.php b/classes/Kohana/Schema.php new file mode 100644 index 0000000..e59e280 --- /dev/null +++ b/classes/Kohana/Schema.php @@ -0,0 +1,66 @@ +description; + } + + /** + * Gets whether this objectClass is flagged as obsolete by the LDAP server. + */ + public function getIsObsolete() { + return $this->is_obsolete; + } + + /** + * Return the objects name. + * + * param boolean $lower Return the name in lower case (default) + * @return string The name + */ + public function getName($lower=true) { + return $lower ? strtolower($this->name) : $this->name; + } + + public function getOID() { + return $this->oid; + } + + public function setDescription($desc) { + $this->description = $desc; + } + + /** + * Sets this attriute's name. + * + * @param string $name The new name to give this attribute. + */ + public function setName($name) { + $this->name = $name; + } + + public function setOID($oid) { + $this->oid = $oid; + } +} +?> diff --git a/classes/Kohana/Schema/Attribute.php b/classes/Kohana/Schema/Attribute.php new file mode 100644 index 0000000..f610c1f --- /dev/null +++ b/classes/Kohana/Schema/Attribute.php @@ -0,0 +1,464 @@ +get($line)) + return $x; + + $strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE); + + for ($i=0; $iname)==0) + $this->name = $strings[$i]; + else + $this->name .= ' '.$strings[$i]; + + } while (! preg_match("/\'$/s",$strings[$i])); + + # This attribute has no aliases + $this->aliases = array(); + + } else { + $i++; + do { + # In case we came here becaues of a (' + if (preg_match('/^\(/',$strings[$i])) + $strings[$i] = preg_replace('/^\(/','',$strings[$i]); + else + $i++; + + if (strlen($this->name) == 0) + $this->name = $strings[$i]; + else + $this->name .= ' '.$strings[$i]; + + } while (! preg_match("/\'$/s",$strings[$i])); + + # Add alias names for this attribute + while ($strings[++$i] != ')') { + $alias = $strings[$i]; + $alias = preg_replace("/^\'/",'',$alias); + $alias = preg_replace("/\'$/",'',$alias); + $this->addAlias($alias); + } + } + + break; + + case 'DESC': + do { + $i++; + if (strlen($this->description)==0) + $this->description=$this->description.$strings[$i]; + else + $this->description=$this->description.' '.$strings[$i]; + } while (! preg_match("/\'$/s",$strings[$i])); + + break; + + case 'OBSOLETE': + $this->is_obsolete = TRUE; + + break; + + case 'SUP': + $i++; + $this->sup_attribute = $strings[$i]; + + break; + + case 'EQUALITY': + $i++; + $this->equality = $strings[$i]; + + break; + + case 'ORDERING': + $i++; + $this->ordering = $strings[$i]; + + break; + + case 'SUBSTR': + $i++; + $this->sub_str = $strings[$i]; + + break; + + case 'SYNTAX': + $i++; + $this->syntax = $strings[$i]; + $this->syntax_oid = preg_replace('/{\d+}$/','',$this->syntax); + + # Does this SYNTAX string specify a max length (ie, 1.2.3.4{16}) + if (preg_match('/{(\d+)}$/',$this->syntax,$this->max_length)) + $this->max_length = $this->max_length[1]; + else + $this->max_length = null; + + if ($i < count($strings) - 1 && $strings[$i+1] == '{') { + do { + $i++; + $this->name .= ' '.$strings[$i]; + } while ($strings[$i] != '}'); + } + + break; + + case 'SINGLE-VALUE': + $this->is_single_value = TRUE; + + break; + + case 'COLLECTIVE': + $this->is_collective = TRUE; + + break; + + case 'NO-USER-MODIFICATION': + $this->is_no_user_modification = TRUE; + + break; + + case 'USAGE': + $i++; + $this->usage = $strings[$i]; + + break; + + default: + if (preg_match('/[\d\.]+/i',$strings[$i]) && $i == 1) + $this->oid = $strings[$i]; + } + } + + $this->name = preg_replace("/^\'/",'',$this->name); + $this->name = preg_replace("/\'$/",'',$this->name); + $this->description = preg_replace("/^\'/",'',$this->description); + $this->description = preg_replace("/\'$/",'',$this->description); + $this->syntax = preg_replace("/^\'/",'',$this->syntax); + $this->syntax = preg_replace("/\'$/",'',$this->syntax); + $this->syntax_oid = preg_replace("/^\'/",'',$this->syntax_oid); + $this->syntax_oid = preg_replace("/\'$/",'',$this->syntax_oid); + $this->sup_attribute = preg_replace("/^\'/",'',$this->sup_attribute); + $this->sup_attribute = preg_replace("/\'$/",'',$this->sup_attribute); + + Cache::instance()->set($line,$this,$this->_cache_time); + } + + /** + * Adds an attribute name to the alias array. + * + * @param string $alias The name of a new attribute to add to this attribute's list of aliases. + */ + public function addAlias($alias) { + array_push($this->aliases,$alias); + } + + /** + * Adds an objectClass name to this attribute's list of "required by" objectClasses, + * that is the list of objectClasses which must have this attribute. + * + * @param string $name The name of the objectClass to add. + */ + public function addRequiredByObjectClass($name) { + foreach ($this->required_by_object_classes as $required_by_object_class) + if (strcasecmp($required_by_object_class,$name) == 0) + return false; + + array_push($this->required_by_object_classes,$name); + } + + /** + * Adds an objectClass name to this attribute's list of "used in" objectClasses, + * that is the list of objectClasses which provide this attribute. + * + * @param string $name The name of the objectClass to add. + */ + public function addUsedInObjectClass($name) { + foreach ($this->used_in_object_classes as $used_in_object_class) { + if (strcasecmp($used_in_object_class,$name) == 0) + return false; + } + + array_push($this->used_in_object_classes,$name); + } + + /** + * Gets the names of attributes that are an alias for this attribute (if any). + * + * @return array An array of names of attributes which alias this attribute or + * an empty array if no attribute aliases this object. + */ + public function getAliases() { + return $this->aliases; + } + + /** + * Gets this attribute's equality string + * + * @return string + */ + public function getEquality() { + return $this->equality; + } + + /** + * Gets whether this attribute is collective. + * + * @return boolean Returns true if this attribute is collective and false otherwise. + */ + public function getIsCollective() { + return $this->is_collective; + } + + /** + * Gets whether this attribute is not modifiable by users. + * + * @return boolean Returns true if this attribute is not modifiable by users. + */ + public function getIsNoUserModification() { + return $this->is_no_user_modification; + } + + /** + * Gets whether this attribute is single-valued. If this attribute only supports single values, true + * is returned. If this attribute supports multiple values, false is returned. + * + * @return boolean Returns true if this attribute is single-valued or false otherwise. + */ + public function getIsSingleValue() { + return $this->is_single_value; + } + + /** + * Gets this attribute's the maximum length. If no maximum is defined by the LDAP server, null is returned. + * + * @return int The maximum length (in characters) of this attribute or null if no maximum is specified. + */ + public function getMaxLength() { + return $this->max_length; + } + + /** + * Gets this attribute's ordering specification. + * + * @return string + */ + public function getOrdering() { + return $this->ordering; + } + + /** + * Gets the list of "required by" objectClasses, that is the list of objectClasses + * which provide must have attribute. + * + * @return array An array of names of objectclasses (strings) which provide this attribute + */ + public function getRequiredByObjectClasses() { + return $this->required_by_object_classes; + } + + /** + * Gets this attribute's parent attribute (if any). If this attribute does not + * inherit from another attribute, null is returned. + * + * @return string + */ + public function getSupAttribute() { + return $this->sup_attribute; + } + + /** + * Gets this attribute's substring matching specification + * + * @return string + */ + public function getSubstr() { + return $this->sub_str; + } + + /** + * Gets this attribute's syntax OID. Differs from getSyntaxString() in that this + * function only returns the actual OID with any length specification removed. + * Ie, if the syntax string is "1.2.3.4{16}", this function only retruns + * "1.2.3.4". + * + * @return string The syntax OID string. + */ + public function getSyntaxOID() { + return $this->syntax_oid; + } + + /** + * Gets this attribute's raw syntax string (ie: "1.2.3.4{16}"). + * + * @return string The raw syntax string + */ + public function getSyntaxString() { + return $this->syntax; + } + + /** + * Gets this attribute's type + * + * @return string The attribute's type. + */ + public function getType() { + return $this->type; + } + + /** + * Gets this attribute's usage string as defined by the LDAP server + * + * @return string + */ + public function getUsage() { + return $this->usage; + } + + /** + * Gets the list of "used in" objectClasses, that is the list of objectClasses + * which provide this attribute. + * + * @return array An array of names of objectclasses (strings) which provide this attribute + */ + public function getUsedInObjectClasses() { + return $this->used_in_object_classes; + } + + /** + * Returns whether the specified attribute is an alias for this one (based on this attribute's alias list). + * + * @param string $attr_name The name of the attribute to check. + * @return boolean True if the specified attribute is an alias for this one, or false otherwise. + */ + public function isAliasFor($attr_name) { + foreach ($this->aliases as $alias_attr_name) + if (strcasecmp($alias_attr_name,$attr_name) == 0) + return true; + + return false; + } + + public function isForceMay() { + return $this->forced_as_may; + } + + /** + * Removes an attribute name from this attribute's alias array. + * + * @param string $remove_alias_name The name of the attribute to remove. + * @return boolean true on success or false on failure (ie, if the specified + * attribute name is not found in this attribute's list of aliases) + */ + public function removeAlias($remove_alias_name) { + foreach ($this->aliases as $i => $alias_name) { + + if (strcasecmp($alias_name,$remove_alias_name) == 0) { + unset($this->aliases[$i]); + + $this->aliases = array_values($this->aliases); + return true; + } + } + return false; + } + + /** + * Sets this attribute's list of aliases. + * + * @param array $aliases The array of alias names (strings) + */ + public function setAliases($aliases) { + $this->aliases = $aliases; + } + + /** + * This function will mark this attribute as a forced MAY attribute + */ + public function setForceMay() { + $this->forced_as_may = true; + } + + /** + * Sets whether this attribute is single-valued. + * + * @param boolean $is + */ + public function setIsSingleValue($is) { + $this->is_single_value = $is; + } + + /** + * Sets this attriute's SUP attribute (ie, the attribute from which this attribute inherits). + * + * @param string $attr The name of the new parent (SUP) attribute + */ + public function setSupAttribute($attr) { + $this->sup_attribute = $attr; + } + + /** + * Sets this attribute's type. + * + * @param string $type The new type. + */ + public function setType($type) { + $this->type = $type; + } +} +?> diff --git a/classes/Model/LDAP/Schema.php b/classes/Model/LDAP/Schema.php index e36cbc6..1b30318 100644 --- a/classes/Model/LDAP/Schema.php +++ b/classes/Model/LDAP/Schema.php @@ -10,5 +10,16 @@ * @license http://dev.phpldapadmin.org/license.html */ class Model_LDAP_Schema extends ORM_LDAP { + public function attribute($column) { + $k = 'attributetypes'; + + return new Schema_Attribute(($x = $this->_attr_search($k,$column) ? $this->_object[$k][$x] : ''); + } + + private function _attr_search($key,$column) { + foreach ($this->_object[$key] as $k=>$v) + if (preg_match("/^\( (.*) NAME (\( )?\'$column\' /i",$v)) + return $k; + } } ?> diff --git a/classes/Schema.php b/classes/Schema.php new file mode 100644 index 0000000..f9a470f --- /dev/null +++ b/classes/Schema.php @@ -0,0 +1,4 @@ + diff --git a/classes/Schema/Attribute.php b/classes/Schema/Attribute.php new file mode 100644 index 0000000..b97e66a --- /dev/null +++ b/classes/Schema/Attribute.php @@ -0,0 +1,4 @@ +