diff --git a/interceptors/members/pom.xml b/interceptors/members/pom.xml new file mode 100644 index 0000000000..7b3f5276c8 --- /dev/null +++ b/interceptors/members/pom.xml @@ -0,0 +1,195 @@ + + + + + + 4.0.0 + + org.apache.directory.server + apacheds-interceptors + 2.0.0.AM26-SNAPSHOT + + + apacheds-interceptors-members + ApacheDS memberOf Virtual Attribute Interceptor + bundle + + + Virtual Attribute interceptor to add memberOf attributes to results + + + + + org.apache.directory.junit + junit-addons + test + + + + ${project.groupId} + apacheds-i18n + + + + ${project.groupId} + apacheds-core-api + + + + ${project.groupId} + apacheds-core-api + test-jar + test + + + + org.apache.commons + commons-collections4 + + + + org.apache.directory.api + api-ldap-client-api + + + + org.apache.directory.api + api-i18n + + + + org.apache.directory.api + api-ldap-codec-standalone + provided + + + + org.apache.directory.api + api-ldap-codec-core + + + + org.apache.directory.api + api-ldap-extras-aci + + + + org.apache.directory.api + api-ldap-extras-trigger + + + + org.apache.directory.api + api-ldap-extras-util + + + + org.apache.directory.api + api-ldap-model + + + + org.apache.directory.api + api-ldap-schema-data + + + + org.apache.directory.api + api-ldap-extras-codec + provided + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${basedir}/target/server-work + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + verify + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + META-INF/MANIFEST.MF + false + + + + + + org.apache.felix + maven-bundle-plugin + true + true + + META-INF + + ${project.groupId}.interceptors.logger + + org.apache.directory.server.core.logger;version=${project.version} + + + org.apache.directory.api.ldap.model.constants;version=${org.apache.directory.api.version}, + org.apache.directory.api.ldap.model.entry;version=${org.apache.directory.api.version}, + org.apache.directory.api.ldap.model.exception;version=${org.apache.directory.api.version}, + org.apache.directory.server.core.api;version=${project.version}, + org.apache.directory.server.core.api.filtering;version=${project.version}, + org.apache.directory.server.core.api.interceptor;version=${project.version}, + org.apache.directory.server.core.api.interceptor.context;version=${project.version}, + org.slf4j;version=${slf4j.api.bundleversion} + + + + + + + + + src/main/resources + true + + **/*.gif + + + + + + diff --git a/interceptors/members/src/main/java/org/apache/directory/server/core/memberof/MemberOfInterceptor.java b/interceptors/members/src/main/java/org/apache/directory/server/core/memberof/MemberOfInterceptor.java new file mode 100644 index 0000000000..c116d4c667 --- /dev/null +++ b/interceptors/members/src/main/java/org/apache/directory/server/core/memberof/MemberOfInterceptor.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.directory.server.core.memberof; + + +import org.apache.directory.api.ldap.model.constants.Loggers; +import org.apache.directory.api.ldap.model.entry.Entry; +import org.apache.directory.api.ldap.model.entry.Value; +import org.apache.directory.api.ldap.model.exception.LdapException; +import org.apache.directory.api.ldap.model.exception.LdapOperationException; +import org.apache.directory.api.ldap.model.exception.LdapOtherException; +import org.apache.directory.api.ldap.model.filter.ExprNode; +import org.apache.directory.api.ldap.model.filter.PresenceNode; +import org.apache.directory.api.ldap.model.message.AliasDerefMode; +import org.apache.directory.api.ldap.model.message.SearchScope; +import org.apache.directory.api.ldap.model.name.Dn; +import org.apache.directory.server.core.api.CoreSession; +import org.apache.directory.server.core.api.filtering.EntryFilteringCursor; +import org.apache.directory.server.core.api.interceptor.BaseInterceptor; +import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext; +import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext; +import org.apache.directory.server.core.api.partition.Partition; +import org.apache.directory.server.core.api.partition.PartitionNexus; +import org.apache.directory.server.core.api.partition.PartitionTxn; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * An interceptor for adding virtual memberOf attributes to {code}Entry{code}s. + * + * + * @author Apache Directory Project + */ +public class MemberOfInterceptor extends BaseInterceptor +{ + /** A aggregating logger */ + private static final Logger OPERATION_STATS = LoggerFactory.getLogger( Loggers.OPERATION_STAT.getName() ); + + /** An operation logger */ + private static final Logger OPERATION_TIME = LoggerFactory.getLogger( Loggers.OPERATION_TIME.getName() ); + + /** + * + * Creates a new instance of MemberOfInterceptor. + * + * @param name This interceptor's getName() + */ + public MemberOfInterceptor( String name ) + { + super( name ); + } + + /** + * {@inheritDoc} + */ + @Override + public Entry lookup( LookupOperationContext lookupContext ) throws LdapException + { + Entry entry = next( lookupContext ); + + CoreSession adminSession = directoryService.getAdminSession(); + Value dnValue = new Value( directoryService.getAtProvider().getMember(), entry.getDn().getNormName() ); + PartitionNexus nexus = directoryService.getPartitionNexus(); + + // either + ExprNode filter = new PresenceNode( directoryService.getAtProvider().getAdministrativeRole() ); + // or +// ExprNode filter = new PresenceNode( dnValue ); + + SearchOperationContext searchOperationContext = new SearchOperationContext( adminSession, Dn.ROOT_DSE, SearchScope.SUBTREE, filter, "1.1" ); + Partition partition = nexus.getPartition( Dn.ROOT_DSE ); + searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES ); + searchOperationContext.setPartition( partition ); + + try ( PartitionTxn partitionTxn = partition.beginReadTransaction() ) + { + searchOperationContext.setTransaction( partitionTxn ); + EntryFilteringCursor results = nexus.search( searchOperationContext ); + + try + { + String memberOf = "memberOf"; + while ( results.next() ) + { + Entry memberEntry = results.get(); + + entry = entry.add( memberOf, memberEntry.getDn().getName() ); + // Note: not sure f I should: + // if has memberOf + // add to memberOf + // else + // create memberOf with value of + } + + results.close(); + } + catch ( Exception e ) + { + throw new LdapOperationException( e.getMessage(), e ); + } + } + catch ( Exception e ) + { + throw new LdapOtherException( e.getMessage(), e ); + } + + return entry; + } + + /** + * {@inheritDoc} + */ + @Override + public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException + { + EntryFilteringCursor cursor = next( searchContext ); + + return cursor; + } +} diff --git a/interceptors/pom.xml b/interceptors/pom.xml index 651de828f0..93a259e861 100644 --- a/interceptors/pom.xml +++ b/interceptors/pom.xml @@ -48,6 +48,7 @@ operational collective logger + members exception hash schema diff --git a/server-integ/src/test/java/org/apache/directory/server/kerberos/KeyDerivationServiceIT.java b/server-integ/src/test/java/org/apache/directory/server/kerberos/KeyDerivationServiceIT.java index a591bce28f..515e6dd71e 100644 --- a/server-integ/src/test/java/org/apache/directory/server/kerberos/KeyDerivationServiceIT.java +++ b/server-integ/src/test/java/org/apache/directory/server/kerberos/KeyDerivationServiceIT.java @@ -177,9 +177,13 @@ else if ( vendor.equalsIgnoreCase( "AdoptOpenJDK" ) ) { assertTrue( "Number of keys", krb5key.size() > 4 ); } + else if ( vendor.equalsIgnoreCase( "Eclipse OpenJ9" ) ) + { + assertTrue( "Number of keys", krb5key.size() > 4 ); + } else { - fail( "Unkown JVM: " + vendor ); + fail( "Unkown JVM/keysize: '" + vendor + "' / " + krb5key.size() ); } } diff --git a/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchMembersIT.java b/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchMembersIT.java new file mode 100644 index 0000000000..cb9a9e7e98 --- /dev/null +++ b/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchMembersIT.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.directory.server.operations.search; + +import org.apache.directory.api.ldap.model.constants.SchemaConstants; +import org.apache.directory.api.ldap.model.cursor.Cursor; +import org.apache.directory.api.ldap.model.cursor.EntryCursor; +import org.apache.directory.api.ldap.model.cursor.SearchCursor; +import org.apache.directory.api.ldap.model.entry.DefaultEntry; +import org.apache.directory.api.ldap.model.entry.Entry; +import org.apache.directory.api.ldap.model.exception.LdapException; +import org.apache.directory.api.ldap.model.message.Control; +import org.apache.directory.api.ldap.model.message.Response; +import org.apache.directory.api.ldap.model.message.SearchRequest; +import org.apache.directory.api.ldap.model.message.SearchRequestImpl; +import org.apache.directory.api.ldap.model.message.SearchScope; +import org.apache.directory.api.ldap.model.message.controls.Subentries; +import org.apache.directory.api.ldap.model.message.controls.SubentriesImpl; +import org.apache.directory.api.ldap.model.name.Dn; +import org.apache.directory.api.ldap.util.JndiUtils; +import org.apache.directory.api.util.Network; +import org.apache.directory.ldap.client.api.LdapConnection; +import org.apache.directory.ldap.client.api.LdapNetworkConnection; +import org.apache.directory.server.annotations.CreateLdapServer; +import org.apache.directory.server.annotations.CreateTransport; +import org.apache.directory.server.core.annotations.ApplyLdifs; +import org.apache.directory.server.core.annotations.ContextEntry; +import org.apache.directory.server.core.annotations.CreateDS; +import org.apache.directory.server.core.annotations.CreateIndex; +import org.apache.directory.server.core.annotations.CreatePartition; +import org.apache.directory.server.core.integ.AbstractLdapTestUnit; +import org.apache.directory.server.core.integ.FrameworkRunner; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.naming.InvalidNameException; +import javax.naming.NameNotFoundException; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttribute; +import javax.naming.directory.BasicAttributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.naming.ldap.LdapContext; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import static org.apache.directory.server.integ.ServerIntegrationUtils.getAdminConnection; +import static org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Testcase with different modify operations on a person entry. Each includes a + * single add op only. Created to demonstrate DIREVE-241 ("Adding an already + * existing attribute value with a modify operation does not cause an error."). + * + * @author Apache Directory Project + */ +@RunWith(FrameworkRunner.class) +@CreateDS(partitions = +{ + @CreatePartition( + name = "example", + suffix = "dc=example,dc=com", + indexes = + { + @CreateIndex(attribute = "objectClass"), + @CreateIndex(attribute = "dc"), + @CreateIndex(attribute = "ou"), + @CreateIndex(attribute = "uniqueMember") + }, + contextEntry = @ContextEntry(entryLdif = + "dn: dc=example,dc=com\n" + + "objectClass: domain\n" + + "dc: example")) +}) +@CreateLdapServer(transports = + { @CreateTransport(protocol = "LDAP") }) + +public class SearchMembersIT extends AbstractLdapTestUnit +{ + /** + * Test for DIRSERVER-1844 + */ + @ApplyLdifs({ + "dn: ou=users,dc=example,dc=com", + "ObjectClass: top", + "ObjectClass: organizationalUnit", + "ou: users", + + "dn: cn=User1,ou=users,dc=example,dc=com", + "objectClass: person", + "objectClass: top", + "cn: User1", + "sn: user 1", + "description: User1", + + "dn: ou=groups,dc=example,dc=com", + "ObjectClass: top", + "ObjectClass: organizationalUnit", + "ou: groups", + + "dn: cn=Group1,ou=groups,dc=example,dc=com", + "objectClass: groupOfUniqueNames", + "objectClass: top", + "cn: Group1", + "uniqueMember: cn=user1,ou=users,dc=example,dc=com", + "description: Group" + }) + + @Test + public void testSearchMemberOf() throws Exception + { + LdapConnection connection = getAdminConnection( getLdapServer() ); + SearchRequest req = new SearchRequestImpl(); + req.setBase( new Dn( "dc=example,dc=com" ) ); + req.setFilter( "(&(objectClass=person)(memberOf=CN=Group1,ou=groups,DC=example,DC=com))"); + req.setScope( SearchScope.SUBTREE ); + + SearchCursor cursor = connection.search( req ); + int count = 0; + while( cursor.next() ) + { + Entry result = cursor.getEntry(); + count++; + assertTrue(result.contains("memberOf" , "CN=Group1,ou=groups,DC=example,DC=com")); + } + + assertEquals( 1, count ); + + cursor.close(); + + connection.close(); + } +}