/** * {@inheritdoc} */ public function toLdap($password) { $this->validateConfiguration(); if (!is_null($this->getLdapConnection())) { $password = LdapUtilities::encode($password, $this->getLdapConnection()->getConfig()->getEncoding()); } return iconv("UTF-8", "UTF-16LE", '"' . $password . '"'); }
/** * {@inheritdoc} */ public function getUsername($username) { if (LdapUtilities::isValidGuid($username)) { $username = '******' . $username . '}'; } elseif (!(LdapUtilities::isValidSid($username) || $this->isValidUserDn($username) || $this->isInUpnForm($username))) { $username = parent::getUsername($username); } return $username; }
/** * @param string $sid The SID in string, short name, or binary form. */ public function __construct($sid) { if (LdapUtilities::isValidSid($sid)) { $this->decodeFromString($sid); } elseif (array_key_exists(strtoupper($sid), self::SHORT_NAME)) { $this->decodeFromString(self::SHORT_NAME[strtoupper($sid)]); } else { $this->decodeFromBinary($sid); } }
/** * @param array $attributes * @param null|string $alias * @return array */ protected function getAttributesForAlias(array $attributes, $alias) { $toSelect = []; foreach ($attributes as $attribute) { list($attrAlias, $attrSelect) = LdapUtilities::getAliasAndAttribute($attribute); if (!$attrAlias || $attrAlias == $alias) { $toSelect[] = $attrSelect; } } return $toSelect; }
/** * {@inheritdoc} */ public function toLdap($sid) { if (!LdapUtilities::isValidSid($sid)) { throw new AttributeConverterException(sprintf('Expected a string SID but got "%s".', $sid)); } $sid = (new SID($sid))->toBinary(); if ($this->getOperationType() == self::TYPE_SEARCH_TO) { // All hex parts must have a leading backslash for the search. $sid = '\\' . implode('\\', str_split(bin2hex($sid), '2')); } return $sid; }
/** * {@inheritdoc} */ public function toLdap($guid) { $guid = strtolower($guid) === self::AUTO ? LdapUtilities::uuid4() : $guid; if (!LdapUtilities::isValidGuid($guid)) { throw new AttributeConverterException(sprintf('The value "%s" is not a valid GUID.', $guid)); } $guid = (new GUID($guid))->toBinary(); if ($this->getOperationType() == self::TYPE_SEARCH_TO) { $guid = implode('', preg_filter('/^/', '\\', str_split(bin2hex($guid), 2))); } return $guid; }
/** * @param string $guid */ protected function decodeFromBinary($guid) { $hex = unpack('H*hex', $guid)['hex']; $guidStrings = []; foreach ($this->guidSections as $section) { $guidStrings[] = $this->parseSection($hex, $section); } $guid = implode('-', $guidStrings); if (!LdapUtilities::isValidGuid($guid)) { throw new \UnexpectedValueException(sprintf('The GUID with value "%s" is not valid.', $guid)); } $this->guid = $guid; }
/** * {@inheritdoc} */ public function toLdapFilter($alias = null) { if ($this->skipFilterForAlias($alias)) { return ''; } if (!LdapUtilities::isValidAttributeFormat($this->oid)) { throw new LdapQueryException(sprintf('Matching rule "%s" is not a valid format.', $this->oid)); } if ($this->getValueForQuery($alias) instanceof BaseOperator) { return $this->getValueForQuery($alias)->toLdapFilter($alias); } return self::SEPARATOR_START . $this->getAttributeToQuery($alias) . ':' . $this->oid . ':' . $this->operatorSymbol . LdapUtilities::escapeValue($this->getValueForQuery($alias), null, LDAP_ESCAPE_FILTER) . self::SEPARATOR_END; }
/** * Determine how to get the value for the attribute from the LDAP entry being compared, and return that value. * * @param array|LdapObject $entry * @param string $attribute * @return mixed */ protected function getComparisonValue($entry, $attribute) { $alias = null; if (!empty($this->aliases)) { list($alias, $attribute) = LdapUtilities::getAliasAndAttribute($attribute); } $value = ''; if (is_array($entry) && isset($entry[$attribute])) { $value = $entry[$attribute]; // Be forgiving if they are hydrating to an array and the case of the attribute was not correct. } elseif (is_array($entry) && array_key_exists(MBString::strtolower($attribute), MBString::array_change_key_case($entry))) { $value = MBString::array_change_key_case($entry)[MBString::strtolower($attribute)]; // Only get the value if there is no alias requested, or if an alias was requested the object type must match the alias. } elseif ($entry instanceof LdapObject && (!$alias || $entry->isType($this->aliases[$alias]->getObjectType())) && $entry->has($attribute)) { $value = $entry->get($attribute); } // How to handle multi-valued attributes? This will at least prevent errors, but may not be accurate. $value = is_array($value) ? reset($value) : $value; return $this->convertValueToString($value); }
/** * This formats the orderBy array to ignore case differences between the orderBy name and the actually selected name, * such as for sorting arrays. * * @param $selected * @param $aliases * @return array */ protected function getFormattedOrderBy($selected, $aliases) { if (!empty($aliases) && !$this->isWildCardSelection()) { $orderBy = []; foreach ($this->orderBy as $attribute => $direction) { list($alias, $attr) = LdapUtilities::getAliasAndAttribute($attribute); $orderAttr = MBString::array_search_get_value($attr, $selected); $orderAttr = $alias ? "{$alias}.{$orderAttr}" : $orderAttr; $orderBy[$orderAttr] = $direction; } } else { $orderBy = $this->orderBy; } return $orderBy; }
/** * Check all of the groups that are valid for a specific role against all of the LDAP groups that the user belongs * to. * * @param array $roleGroups * @param LdapObjectCollection $ldapGroups * @return bool */ protected function hasGroupForRoles(array $roleGroups, LdapObjectCollection $ldapGroups) { foreach ($roleGroups as $roleGroup) { if (LdapUtilities::isValidLdapObjectDn($roleGroup)) { $attribute = 'dn'; } elseif (preg_match(LdapUtilities::MATCH_GUID, $roleGroup)) { $attribute = $this->roleAttrMap['guid']; } elseif (preg_match(LdapUtilities::MATCH_SID, $roleGroup)) { $attribute = $this->roleAttrMap['sid']; } else { $attribute = $this->roleAttrMap['name']; } if ($this->hasGroupWithAttributeValue($ldapGroups, $attribute, $roleGroup)) { return true; } } return false; }
/** * Builds the DN based off of the "name" attribute. The name attribute should be mapped to the "cn" attribute in * pretty much all cases except for creating an OU object. Then the "name" attribute should be mapped to "ou". * * @param AddOperation $operation */ protected function setDnToUse(AddOperation $operation) { // If the DN was explicitly set, don't do anything. if ($operation->getDn()) { return; } if (!$this->schema) { throw new LogicException("You must explicitly set the DN or specify a schema type."); } if (!$this->schema->hasAttribute('name')) { throw new LogicException('To create an object you must specify the name attribute in the schema. That attribute should typically' . ' map to the "cn" attribute, as it will use that as the base of the distinguished name.'); } $location = $operation->getLocation() ?: $this->schema->getDefaultContainer(); if (empty($location)) { throw new LogicException('You must specify a container or OU to place this LDAP object in.'); } $attribute = $this->schema->getAttributeToLdap('name'); $rdnValue = LdapUtilities::escapeValue($operation->getAttributes()[$attribute], null, LDAP_ESCAPE_DN); $location = $this->resolveParameters(['container' => $location])['container']; $operation->setDn($attribute . '=' . $rdnValue . ',' . $location); }
/** * {@inheritdoc} */ public function getLogArray() { return $this->mergeLogDefaults(['DN' => $this->properties['dn'], 'Batch' => print_r(LdapUtilities::sanitizeBatchArray($this->getBatchArray()), true)]); }
/** * Encodes any values with the needed type for LDAP. * * @param array|string $values * @return array */ protected function encodeValues($values) { if (is_null($this->connection) || $this->type == AttributeConverterInterface::TYPE_SEARCH_FROM) { return $values; } $encoded = is_array($values) ? $values : [$values]; foreach ($encoded as $index => $value) { if (is_string($value)) { $encoded[$index] = LdapUtilities::encode($value, $this->connection->getConfig()->getEncoding()); } } // This is to pass it back the same way it was received. ldap_modify_batch is picky about values being an array. return is_array($values) ? $encoded : reset($encoded); }
/** * {@inheritdoc} */ public function toLdapFilter($alias = null) { if ($this->skipFilterForAlias($alias)) { return ''; } if ($this->getValueForQuery($alias) instanceof BaseOperator) { return $this->getValueForQuery($alias)->toLdapFilter($alias); } if ($this->wildcardType == self::CONTAINS) { $value = '*' . LdapUtilities::escapeValue($this->getValueForQuery($alias), null, LDAP_ESCAPE_FILTER) . '*'; } elseif ($this->wildcardType == self::STARTS_WITH) { $value = LdapUtilities::escapeValue($this->getValueForQuery($alias), null, LDAP_ESCAPE_FILTER) . '*'; } elseif ($this->wildcardType == self::ENDS_WITH) { $value = '*' . LdapUtilities::escapeValue($this->getValueForQuery($alias), null, LDAP_ESCAPE_FILTER); } elseif ($this->wildcardType == self::LIKE) { $value = LdapUtilities::escapeValue($this->getValueForQuery($alias), '*', LDAP_ESCAPE_FILTER); } else { $value = '*'; } return self::SEPARATOR_START . $this->getAttributeToQuery($alias) . $this->operatorSymbol . $value . self::SEPARATOR_END; }
/** * {@inheritdoc} */ public function toOperation() { // If this is a move operation to a new OU and we have a DN already, then we can figure out the RDN. if (is_null($this->newRdn) && !is_null($this->newSuperior)) { $rdn = LdapUtilities::getRdnFromDn($this->dn); } else { $rdn = $this->newRdn; } return new RenameOperation($this->dn, $rdn, $this->newSuperior, $this->deleteOldRdn); }
/** * @param LdapQueryBuilder $query * @param string $value * @return bOr */ protected function getQueryOrStatement(LdapQueryBuilder $query, $value) { $bOr = $query->filter()->bOr(); $opType = AttributeConverterInterface::TYPE_SEARCH_TO; if (LdapUtilities::isValidGuid($value)) { $bOr->add($query->filter()->eq('objectGuid', (new ConvertWindowsGuid())->setOperationType($opType)->toLdap($value))); } elseif (LdapUtilities::isValidSid($value)) { $bOr->add($query->filter()->eq('objectSid', (new ConvertWindowsSid())->setOperationType($opType)->toLdap($value))); } return $bOr; }
function it_should_check_if_a_value_is_a_valid_GUID() { $this::isValidGuid(LdapUtilities::uuid4())->shouldBeEqualTo(true); $this::isValidGuid('bc7d93d1-3d4d-4535-88bb-d61758684700')->shouldBeEqualTo(true); $this::isValidGuid('bc7d93d1-3d4d-4535-88bb')->shouldBeEqualTo(false); $this::isValidGuid('bc7d93d-3d4-4535-88bb-d6175868470')->shouldBeEqualTo(false); $this::isValidGuid('foo')->shouldBeEqualTo(false); }
/** * This will get the translated attribute or just the attribute if no schema translation was done. * * @param null|string $alias * @return string * @throws LdapQueryException */ protected function getAttributeToQuery($alias) { $attribute = $this->getTranslatedAttribute($alias) ?: $this->getAttribute(); // This avoids possible LDAP injection from unverified input for an attribute name. if (!LdapUtilities::isValidAttributeFormat($attribute)) { throw new LdapQueryException(sprintf('Attribute "%s" is not a valid name or OID.', $attribute)); } return $attribute; }
/** * Binds to LDAP with the supplied credentials or anonymously if specified. * * @param string $username The username to bind with. * @param string $password The password to bind with. * @param bool $anonymous Whether this is an anonymous bind attempt. * @throws LdapBindException */ protected function bind($username, $password, $anonymous = false) { if ($anonymous) { $this->isBound = @ldap_bind($this->connection); } else { $this->isBound = @ldap_bind($this->connection, LdapUtilities::encode($username, $this->config->getEncoding()), LdapUtilities::encode($password, $this->config->getEncoding())); } if (!$this->isBound) { throw new LdapBindException(sprintf('Unable to bind to LDAP: %s', $this->getLastError()), $this->getExtendedErrorNumber()); } }
/** * @param string $sid * @param string $type * @return SID * @throws SddlParserException */ protected function getSid($sid, $type) { $sid = strtoupper($sid); // This is a SID short name, or explicit SID, that requires no domain SID lookup... if (array_key_exists($sid, SID::SHORT_NAME) || LdapUtilities::isValidSid($sid)) { $sid = new SID($sid); // This is a SID that requires a domain SID or root domain SID lookup... } elseif (array_key_exists($sid, SID::SHORT_NAME_DOMAIN) || array_key_exists($sid, SID::SHORT_NAME_ROOT_DOMAIN)) { $sid = $this->getWellKnownDomainSid($sid, array_key_exists($sid, SID::SHORT_NAME_ROOT_DOMAIN)); } else { throw new SddlParserException(sprintf('The value "%s" is not a valid SID for the %s.', $sid, $type)); } return $sid; }
/** * Moves an object from one container/OU to another in LDAP. * * @param LdapObject $ldapObject * @param string $container */ public function move(LdapObject $ldapObject, $container) { $event = new LdapObjectMoveEvent(Event::LDAP_OBJECT_BEFORE_MOVE, $ldapObject, $container); $this->dispatcher->dispatch($event); $container = $event->getContainer(); $this->validateObject($ldapObject); $operation = new RenameOperation($ldapObject->get('dn'), LdapUtilities::getRdnFromDn($ldapObject->get('dn')), $container, true); $this->connection->execute($operation); // Update the object to reference the new DN after the move... $newDn = LdapUtilities::getRdnFromDn($ldapObject->get('dn')) . ',' . $container; $ldapObject->refresh(['dn' => $newDn]); $ldapObject->getBatchCollection()->setDn($newDn); $this->dispatcher->dispatch(new LdapObjectMoveEvent(Event::LDAP_OBJECT_AFTER_MOVE, $ldapObject, $container)); }
/** * {@inheritdoc} */ public function getLogArray() { return $this->mergeLogDefaults(['DN' => $this->properties['dn'], 'Attributes' => print_r(LdapUtilities::sanitizeAttributeArray($this->properties['attributes']), true)]); }