You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2020/12/01 08:18:57 UTC

[directory-server] 01/01: Created a branch for the member-of interceptor implementation

This is an automated email from the ASF dual-hosted git repository.

elecharny pushed a commit to branch member
in repository https://gitbox.apache.org/repos/asf/directory-server.git

commit 9c1782bae4aa34e8e70046d0e1f13e6ba4da9849
Author: emmanuel lecharny <em...@busit.com>
AuthorDate: Tue Dec 1 09:17:45 2020 +0100

    Created a branch for the member-of interceptor implementation
---
 interceptors/members/pom.xml                       | 194 +++++++++++++++++++++
 .../server/core/memberof/MemberOfInterceptor.java  | 138 +++++++++++++++
 interceptors/pom.xml                               |   1 +
 .../server/operations/search/SearchMembersIT.java  | 129 ++++++++++++++
 4 files changed, 462 insertions(+)

diff --git a/interceptors/members/pom.xml b/interceptors/members/pom.xml
new file mode 100644
index 0000000..c0639e6
--- /dev/null
+++ b/interceptors/members/pom.xml
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.server</groupId>
+    <artifactId>apacheds-interceptors</artifactId>
+    <version>2.0.0.AM26-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>apacheds-interceptors-members</artifactId>
+  <name>ApacheDS memberOf Virtual Attribute Interceptor</name>
+  <packaging>bundle</packaging>
+
+  <description>
+    Virtual Attribute interceptor to add memberOf attributes to results
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-collections4</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-client-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-codec-standalone</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-codec-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-extras-aci</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-extras-trigger</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-extras-util</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-schema-data</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-extras-codec</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration> 
+          <systemPropertyVariables>
+            <workingDirectory>${basedir}/target/server-work</workingDirectory>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar-no-fork</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.interceptors.logger</Bundle-SymbolicName>
+            <Export-Package>
+                org.apache.directory.server.core.logger;version=${project.version}
+            </Export-Package>
+            <Import-Package>
+                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}
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+        <excludes>
+          <exclude>**/*.gif</exclude>
+        </excludes>
+      </resource>
+    </resources>
+  </build>
+</project>
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 0000000..c116d4c
--- /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 <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+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 3532d91..ecf2c30 100644
--- a/interceptors/pom.xml
+++ b/interceptors/pom.xml
@@ -48,6 +48,7 @@
     <module>operational</module>
     <module>collective</module>
     <module>logger</module>
+    <module>members</module>
     <module>exception</module>
     <module>hash</module>
     <module>schema</module>
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 0000000..87f6f6b
--- /dev/null
+++ b/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchMembersIT.java
@@ -0,0 +1,129 @@
+/*
+ *  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.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.entry.Entry;
+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.name.Dn;
+import org.apache.directory.ldap.client.api.LdapConnection;
+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.Test;
+import org.junit.runner.RunWith;
+
+import static org.apache.directory.server.integ.ServerIntegrationUtils.getAdminConnection;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * 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 <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@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();
+    }
+}