array( 'columns' => array( 'is_active desc', 'user_name' ) ) ); protected $groupOptions; /** * Normed attribute names based on known LDAP environments * * @var array */ protected $normedAttributes = array( 'uid' => 'uid', 'user' => 'user', 'inetorgperson' => 'inetOrgPerson', 'samaccountname' => 'sAMAccountName' ); /** * Set the base DN to use for a query * * @param string $baseDn * * @return $this */ public function setBaseDn($baseDn) { if (($baseDn = trim($baseDn))) { $this->baseDn = $baseDn; } return $this; } /** * Return the base DN to use for a query * * @return string */ public function getBaseDn() { return $this->baseDn; } /** * Set the objectClass where to look for users * * Sets also the base table name for the underlying repository. * * @param string $userClass * * @return $this */ public function setUserClass($userClass) { $this->baseTable = $this->userClass = $this->getNormedAttribute($userClass); return $this; } /** * Return the objectClass where to look for users * * @return string */ public function getUserClass() { return $this->userClass; } /** * Set the attribute name where to find a user's name * * @param string $userNameAttribute * * @return $this */ public function setUserNameAttribute($userNameAttribute) { $this->userNameAttribute = $this->getNormedAttribute($userNameAttribute); return $this; } /** * Return the attribute name where to find a user's name * * @return string */ public function getUserNameAttribute() { return $this->userNameAttribute; } /** * Set the custom LDAP filter to apply on search queries * * @param string $filter * * @return $this */ public function setFilter($filter) { if (($filter = trim($filter))) { $this->filter = $filter; } return $this; } /** * Return the custom LDAP filter to apply on search queries * * @return string */ public function getFilter() { return $this->filter; } public function setGroupOptions(array $options) { $this->groupOptions = $options; return $this; } public function getGroupOptions() { return $this->groupOptions; } /** * Return the given attribute name normed to known LDAP enviroments, if possible * * @param string $name * * @return string */ protected function getNormedAttribute($name) { $loweredName = strtolower($name); if (array_key_exists($loweredName, $this->normedAttributes)) { return $this->normedAttributes[$loweredName]; } return $name; } /** * Apply the given configuration to this backend * * @param ConfigObject $config * * @return $this */ public function setConfig(ConfigObject $config) { return $this ->setBaseDn($config->base_dn) ->setUserClass($config->user_class) ->setUserNameAttribute($config->user_name_attribute) ->setFilter($config->filter); } /** * Return a new query for the given columns * * @param array $columns The desired columns, if null all columns will be queried * * @return RepositoryQuery */ public function select(array $columns = null) { $query = parent::select($columns); $query->getQuery()->setBase($this->baseDn); if ($this->filter) { $query->getQuery()->where(new Expression($this->filter)); } return $query; } /** * Initialize this repository's query columns * * @return array * * @throws ProgrammingError In case either $this->userNameAttribute or $this->userClass has not been set yet */ protected function initializeQueryColumns() { if ($this->userClass === null) { throw new ProgrammingError('It is required to set the objectClass where to look for users first'); } if ($this->userNameAttribute === null) { throw new ProgrammingError('It is required to set a attribute name where to find a user\'s name first'); } if ($this->ds->getCapabilities()->hasAdOid()) { $isActiveAttribute = 'userAccountControl'; $createdAtAttribute = 'whenCreated'; $lastModifiedAttribute = 'whenChanged'; } else { $isActiveAttribute = 'unknown'; $createdAtAttribute = 'unknown'; $lastModifiedAttribute = 'unknown'; } return array( $this->userClass => array( 'user' => $this->userNameAttribute, 'user_name' => $this->userNameAttribute, 'is_active' => $isActiveAttribute, 'created_at' => $createdAtAttribute, 'last_modified' => $lastModifiedAttribute ) ); } /** * Initialize this repository's conversion rules * * @return array * * @throws ProgrammingError In case $this->userClass has not been set yet */ protected function initializeConversionRules() { if ($this->userClass === null) { throw new ProgrammingError('It is required to set the objectClass where to look for users first'); } if ($this->ds->getCapabilities()->hasAdOid()) { $stateConverter = 'user_account_control'; $timeConverter = 'generalized_time'; } else { $timeConverter = null; $stateConverter = null; } return array( $this->userClass => array( 'is_active' => $stateConverter, 'created_at' => $timeConverter, 'last_modified' => $timeConverter ) ); } /** * Return whether the given userAccountControl value defines that a user is permitted to login * * @param string|null $value * * @return bool */ protected function retrieveUserAccountControl($value) { if ($value === null) { return $value; } $ADS_UF_ACCOUNTDISABLE = 2; return ((int) $value & $ADS_UF_ACCOUNTDISABLE) === 0; } /** * Parse the given value based on the ASN.1 standard (GeneralizedTime) and return its timestamp representation * * @param string|null $value * * @return int */ protected function retrieveGeneralizedTime($value) { if ($value === null) { return $value; } if ( ($dateTime = DateTime::createFromFormat('YmdHis.uO', $value)) !== false || ($dateTime = DateTime::createFromFormat('YmdHis.uZ', $value)) !== false || ($dateTime = DateTime::createFromFormat('YmdHis.u', $value)) !== false ) { return $dateTime->getTimeStamp(); } else { Logger::debug(sprintf( 'Failed to parse "%s" based on the ASN.1 standard (GeneralizedTime) for user backend "%s".', $value, $this->getName() )); } } /** * Probe the backend to test if authentication is possible * * Try to bind to the backend and fetch a single user to check if: *