function it_should_get_an_operator_filter_for_a_schema_adding_the_objectClass_objectCategory_and_filter_array() { $schema = new LdapObjectSchema('ad', 'user'); $schema->setObjectClass(['user']); $schema->setObjectCategory('person'); $this->getOperatorForSchema($schema, [])->toLdapFilter()->shouldBeEqualTo('(&(objectCategory=person)(objectClass=user))'); $this->getOperatorForSchema($schema, ['starts_with' => ['username', 'admin']])->toLdapFilter()->shouldBeEqualTo('(&(&(objectCategory=person)(objectClass=user))(&(username=admin*)))'); }
function it_should_return_all_LDAP_attributes_merged_with_the_schema_if_a_wildcard_was_used() { $map = ['firstName' => 'givenName', 'lastName' => 'sn', 'emailAddress' => 'mail', 'name' => 'cn']; $schema = new LdapObjectSchema('ad', 'user'); $schema->setAttributeMap($map); $fromLdap = ['givenName' => 'Egon', 'sn' => 'Spengler', 'mail' => '*****@*****.**', 'cn' => 'Egon', 'dn' => 'CN=Egon,dc=whhhhhy,dc=local']; $keys = array_unique(array_merge(array_keys($fromLdap), array_keys($map))); $this->beConstructedWith($schema); $this->fromLdap($fromLdap, ['*'])->shouldHaveKeys($keys); }
function let(LdapConnectionInterface $connection, AddOperation $operation) { $schema = new LdapObjectSchema('ad', 'user'); $schema->setAttributeMap(['username' => 'sAMAccountName', 'emailAddress' => 'mail', 'disabled' => 'userAccountControl', 'passwordMustChange' => 'pwdLastSet', 'passwordNeverExpires' => 'userAccountControl', 'trustedForAllDelegation' => 'userAccountControl', 'groups' => 'memberOf']); $schema->setConverterMap(['disabled' => 'user_account_control', 'passwordMustChange' => 'password_must_change', 'trustedForAllDelegation' => 'user_account_control', 'passwordNeverExpires' => 'user_account_control', 'groups' => 'group_membership']); $schema->setConverterOptions(['user_account_control' => ['uacMap' => ['disabled' => '2', 'passwordNeverExpires' => '65536', 'smartCardRequired' => '262144', 'trustedForAllDelegation' => '524288', 'passwordIsReversible' => '128'], 'defaultValue' => '512'], 'group_membership' => ['groups' => ['to_attribute' => 'member', 'from_attribute' => 'memberOf', 'attribute' => 'sAMAccountName', 'filter' => ['objectClass' => 'group']]]]); $this->schema = $schema; $connection->getConfig()->willReturn(new DomainConfiguration('foo.bar')); $this->beConstructedThrough('getInstance', [$schema, $this->entryTo, AttributeConverterInterface::TYPE_CREATE]); }
function let(LdapConnectionInterface $connection) { $schema = new LdapObjectSchema('ad', 'user'); $schema->setAttributeMap(['username' => 'sAMAccountName', 'emailAddress' => 'mail', 'disabled' => 'userAccountControl', 'passwordMustChange' => 'pwdLastSet', 'passwordNeverExpires' => 'userAccountControl', 'trustedForAllDelegation' => 'userAccountControl', 'groups' => 'memberOf']); $schema->setConverterMap(['disabled' => 'user_account_control', 'passwordMustChange' => 'password_must_change', 'trustedForAllDelegation' => 'user_account_control', 'passwordNeverExpires' => 'user_account_control', 'groups' => 'group_membership']); $schema->setConverterOptions(['user_account_control' => ['uacMap' => ['disabled' => '2', 'passwordNeverExpires' => '65536', 'smartCardRequired' => '262144', 'trustedForAllDelegation' => '524288', 'passwordIsReversible' => '128'], 'defaultValue' => '512'], 'group_membership' => ['groups' => ['to_attribute' => 'member', 'from_attribute' => 'memberOf', 'attribute' => 'sAMAccountName', 'filter' => ['objectClass' => 'group']]]]); $this->expectedSearch = new QueryOperation('(&(distinguishedName=cn=foo,dc=foo,dc=bar))', ['userAccountControl']); $this->schema = $schema; $connection->getConfig()->willReturn(new DomainConfiguration('foo.bar')); $connection->getRootDse()->willReturn(new LdapObject(['foo' => 'bar'])); }
/** * Determine what attributes should be selected. This helps account for all attributes being selected both within * and out of the context of a schema. * * @param array $attributes * @param LdapObjectSchema|null $schema * @return array */ protected function getSelectedQueryAttributes(array $attributes, LdapObjectSchema $schema = null) { // Interpret a single wildcard as only schema attributes. if ($schema && !empty($attributes) && $attributes[0] == '*') { $attributes = array_keys($schema->getAttributeMap()); // Interpret a double wildcard as all LDAP attributes even if they aren't in the schema file. } elseif ($schema && !empty($attributes) && $attributes[0] == '**') { $attributes = ['*']; } return $attributes; }
/** * Add a LdapObjectSchema for a object type that will be selected for. Optionally specify a specific alias that is * used to reference it. If no alias is specified, then it uses the object type name for the schema. * * @param LdapObjectSchema $schema * @param null|string $alias */ public function addLdapObjectSchema(LdapObjectSchema $schema, $alias = null) { if (!is_null($alias) && !is_string($alias)) { throw new InvalidArgumentException(sprintf('The alias for type "%s" must be a string, but "%s" was given.', $schema->getObjectType(), is_string($alias) ? $alias : gettype($alias))); } $alias = $alias ?: $schema->getObjectType(); if (!preg_match(self::ALIAS_REGEX, $alias)) { throw new InvalidArgumentException(sprintf('The alias "%s" for type "%s" is invalid. Allowed characters are: A-Z, a-z, 0-9, -, _', $alias, $schema->getObjectType())); } $this->aliases[$alias] = $schema; }
function it_should_hydrate_a_ldap_object_with_batch_modification() { $schema = new LdapObjectSchema('ad', 'user'); $schema->setAttributeMap(['firstName' => 'givenName', 'lastName' => 'sn', 'emailAddress' => 'mail', 'username' => 'sAMAccountName']); $this->setLdapObjectSchema($schema); $ldapObject = new LdapObject(['dn' => 'cn=foo,dc=foo,dc=bar'], [], 'user', 'user'); $ldapObject->set('firstName', 'Chad'); $ldapObject->add('lastName', 'Sikorra'); $ldapObject->remove('username', 'csikorra'); $ldapObject->reset('emailAddress'); $this->hydrateToLdap($ldapObject)->shouldBeEqualTo($this->batch); $this->hydrateToLdap($ldapObject)->shouldHaveCount(4); }
function it_should_set_the_scope_based_off_the_schema($connection) { $operation = new QueryOperation('(foo=bar)'); $this->setLdapObjectSchema($this->schema); $this->setLdapConnection($connection); $this->hydrateToLdap($operation)->getScope()->shouldBeEqualTo('subtree'); $this->schema->setScope(QueryOperation::SCOPE['ONELEVEL']); $this->hydrateToLdap($operation)->getScope()->shouldBeEqualTo('onelevel'); }
/** * Determine what attributes should be selected. This accounts for a query wanting all attributes. * * @param array $selected * @param array $entry * @return array */ protected function getSelectedAttributes(array $selected, array $entry) { if (count($selected) === 1 && $selected[0] == '*' && !$this->schema) { $selected = array_keys($entry); } elseif (count($selected) === 1 && $selected[0] == '*' && $this->schema) { $selected = array_unique(array_merge(array_keys($this->schema->getAttributeMap()), array_keys($entry))); } return $selected; }
/** * Determines which method to actually call. * * @param string $method * @param mixed $arguments * @return mixed */ public function __call($method, $arguments) { if (!preg_match('/^(findOneBy|findBy)(.*)$/', $method, $matches)) { throw new \RuntimeException(sprintf('The method name should begin with "findOneBy" or "findBy". "%s" is unknown.', $method)); } if (empty($arguments)) { throw new \RuntimeException(sprintf('The method name should begin with "findOneBy" or "findBy". "%s" is unknown.', $method)); } $method = $matches[1]; $attribute = lcfirst($matches[2]); if (!$this->schema->hasAttribute($attribute)) { throw new \RuntimeException(sprintf('To call "%s" you must define the attribute "%s" in your schema.', $method, $attribute)); } if (1 == count($arguments)) { return $this->{$method}([$attribute => $arguments[0]]); } else { return $this->{$method}(array_merge([$attribute => array_shift($arguments)], $arguments)); } }
/** * Whether or not the item needs to be parsed and cached. * * @param string $schemaName * @param string $cacheItem * @return bool */ protected function shouldBuildCacheItem($schemaName, $cacheItem) { $cacheOutOfDate = false; if ($this->cache->getUseAutoCache()) { $lastModTime = $this->parser->getSchemaModificationTime($schemaName); $cacheCreationTime = $this->cache->getCacheCreationTime(LdapObjectSchema::getCacheType(), $cacheItem); $cacheOutOfDate = !$lastModTime || $lastModTime > $cacheCreationTime; } return $cacheOutOfDate || !$this->cache->contains(LdapObjectSchema::getCacheType(), $cacheItem); }
/** * @param array $filter * @param BaseOperator|null $operator * @return BaseOperator */ protected function getOperatorForArray(array $filter, BaseOperator $operator = null) { $filter = !empty($filter) ? $this->filterBuilder->bAnd(...$this->parseFilterToOperators($filter)) : null; if (!$filter && !$operator) { throw new InvalidArgumentException(sprintf('Type "%s" for schema "%s" needs to have one of the following defined: objectClass, objectCategory, or filter.', $this->schema->getObjectType(), $this->schema->getSchemaName())); } elseif ($filter && $operator) { $operator = $this->filterBuilder->bAnd($operator, $filter); } else { $operator = $operator ?: $filter; } return $operator; }
/** * Convert a set of values for an attribute. * * @param string $attribute * @param array $values * @param string $direction * @param AttributeConverterInterface|null $converter * @return mixed */ protected function doConvertValues($attribute, array $values, $direction, AttributeConverterInterface $converter = null) { $converter = is_null($converter) ? $this->getConverterWithOptions($this->schema->getConverter($attribute)) : $converter; $converter->setAttribute($attribute); if ($converter->getIsMultiValuedConverter()) { $values = $converter->{$direction}($values); } else { foreach ($values as $index => $value) { $values[$index] = $converter->{$direction}($value); } } return $values; }
/** * Checks to make sure all required attributes are present. * * @param array $attributes */ protected function validateAttributesToLdap(array $attributes) { if (!$this->schema) { return; } $missing = []; foreach ($this->schema->getRequiredAttributes() as $attribute) { if (!array_key_exists(MBString::strtolower($attribute), MBString::array_change_key_case($attributes))) { $missing[] = $attribute; } } if (!empty($missing)) { throw new LogicException(sprintf('The following required attributes are missing: %s', implode(', ', $missing))); } }
function it_should_pass_operation_options_on_to_the_LdapQuery_class_correctly() { $this->objectSchema->setAttributesToSelect(['foo', 'bar']); $this->select(); $this->from($this->objectSchema); $this->setScopeOneLevel(); $this->setBaseDn('ou=stuff,dc=foo,dc=bar'); $this->setPageSize('9001'); $this->getLdapQuery()->getQueryOperation()->getAttributes()->shouldBeEqualTo([]); $this->getLdapQuery()->getQueryOperation()->getBaseDn()->shouldBeEqualTo('ou=stuff,dc=foo,dc=bar'); $this->getLdapQuery()->getQueryOperation()->getScope()->shouldBeEqualTo(QueryOperation::SCOPE['ONELEVEL']); $this->getLdapQuery()->getQueryOperation()->getPageSize()->shouldBeEqualTo('9001'); $this->getLdapQuery()->getQueryOperation()->getFilter()->toLdapFilter()->shouldBeEqualTo('(&(objectCategory=person)(objectClass=user))'); $this->select('foo'); $this->getLdapQuery()->getQueryOperation()->getAttributes()->shouldBeEqualTo(['foo']); }
function it_should_convert_the_filter_for_a_schema_if_it_uses_mapped_attribute_names_with_converters() { $this->schema->setFilter(new Comparison('exchangeHideFromGAL', '=', true)); $this->toLdap()->toLdapFilter()->shouldEqual('(|(msExchHideFromAddressLists=TRUE)(objectClass=organizationalUnit))'); }
function it_should_be_case_insensitive_when_looking_up_an_item_in_the_cache() { $this->setCacheFolder($this->testCacheDir); $item = new LdapObjectSchema('foo', 'bar'); $this->set($item); $this->contains(LdapObjectSchema::getCacheType(), 'Foo.Bar')->shouldBeEqualTo(true); $this->get(LdapObjectSchema::getCacheType(), 'Foo.Bar')->shouldBeLike($item); $this->deleteAll(); }
/** * Validate that an object schema meets the minimum requirements. * * @param LdapObjectSchema $schema * @throws SchemaParserException */ protected function validateObjectSchema($schema) { if (empty($schema->getAttributeMap())) { throw new SchemaParserException(sprintf('Object type "%s" has no attributes defined.', $schema->getObjectType())); } elseif (!(bool) count(array_filter(array_keys($schema->getAttributeMap()), 'is_string'))) { throw new SchemaParserException('The attributes for a schema should be an associative array.'); } if ($schema->getScope() && !in_array($schema->getScope(), QueryOperation::SCOPE)) { throw new SchemaParserException(sprintf('The scope "%s" is not valid. Valid types are: %s', $schema->getScope(), implode(', ', QueryOperation::SCOPE))); } }
public function it_should_always_return_null_when_calling_get() { $item = new LdapObjectSchema('foo', 'bar'); $this->get($item->getCacheType(), $item->getSchemaName() . '.' . $item->getObjectType())->shouldBeNull(); }
function it_should_get_the_ldap_filter_for_a_specific_alias() { $foo = new LdapObjectSchema('foo', 'foo'); $foo->setFilter(new Comparison('foo', Comparison::EQ, 'bar')); $bar = new LdapObjectSchema('foo', 'bar'); $bar->setFilter(new Comparison('bar', Comparison::EQ, 'foo')); $this->addLdapObjectSchema($bar); $this->addLdapObjectSchema($foo); $this->toLdapFilter('foo')->shouldBeEqualTo('(foo=bar)'); $this->toLdapFilter('bar')->shouldBeEqualTo('(bar=foo)'); }
function it_should_convert_values_when_hydrating_to_ldap() { $schema = new LdapObjectSchema('ad', 'user'); $schema->setAttributeMap(['foo' => 'bar']); $schema->setConverterMap(['foo' => 'bool']); $this->setLdapObjectSchema($schema); $attributes = $this->objectToLdap; $attributes['foo'] = true; $this->hydrateToLdap($attributes)->shouldContain('TRUE'); }
function it_should_limit_the_results_for_subsequent_operations_if_a_size_limit_is_set_so_we_dont_go_over_the_limit($connection) { $foo = new LdapObjectSchema('foo', 'foo'); $bar = new LdapObjectSchema('foo', 'bar'); $foo->setFilter(new Comparison('foo', '=', 'bar')); $bar->setFilter(new Comparison('bar', '=', 'foo')); $filter = new OperatorCollection(); $filter->addLdapObjectSchema($foo); $filter->addLdapObjectSchema($bar); $this->operation->setFilter($filter); $this->operation->setAttributes([]); $this->operation->setSizeLimit(4); $connection->execute(Argument::that(function ($op) { return $op->getFilter() == '(foo=bar)' && $op->getSizeLimit() == 4; }))->shouldBeCalled()->willReturn($this->ldapEntries); // The above returns 2 results, since the limit is 4 this next call should be set to a max of 2... $connection->execute(Argument::that(function ($op) { return $op->getFilter() == '(bar=foo)' && $op->getSizeLimit() == 2; }))->shouldBeCalled()->willReturn($this->sortEntries); $this->getResult(); }
function it_should_not_call_the_load_schema_event_when_retrieving_from_the_cache(CacheInterface $cache, SchemaParserInterface $parser, $dispatcher) { $cache->getUseAutoCache()->willReturn(true); $cache->contains(LdapObjectSchema::getCacheType(), 'ad.user')->willReturn(true); $cache->getCacheCreationTime(LdapObjectSchema::getCacheType(), 'ad.user')->willReturn(new \DateTime('2015-1-3')); $cache->set(Argument::any())->shouldNotBeCalled(); $cache->get(LdapObjectSchema::getCacheType(), 'ad.user')->willReturn(new LdapObjectSchema('ad', 'user')); $parser->parse('ad', 'user')->shouldNotBeCalled(); $parser->getSchemaModificationTime('ad')->willReturn(new \DateTime('2015-1-2')); new LdapObjectSchemaEvent(Event::LDAP_SCHEMA_LOAD, new LdapObjectSchema('ad', 'user')); $dispatcher->dispatch(Argument::type('\\LdapTools\\Event\\LdapObjectSchemaEvent'))->shouldNotBeCalled(); $this->beConstructedWith($cache, $parser, $dispatcher); $this->get('ad', LdapObjectType::USER); }