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();
+ }
+}