directory-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Sebastian Oerding <sebastian.oerd...@robotron.de>
Subject Re: Embedded Apache DS as proxy
Date Mon, 29 Sep 2014 14:23:32 GMT
Hello,

I made some progress with the code Kiran provided. However now 
everything is fine until I add my Interceptor.

When my interceptor extends BaseInterceptor I get the problem as 
desribed in 
http://markmail.org/message/pjqwd5hdqa2puqps#query:+page:1+mid:mybcrygmh6vg57po+state:results

Following Kiran's advice given in that thread to make my class extend 
from SchemaInterceptor I got the following stacktrace:

java.lang.IllegalStateException: Error when attempting to start the 
directory / LDAP service!
     at 
de.robotron.certificate.ldap.EmbeddedLdapServer.start(EmbeddedLdapServer.java:191)
     at 
de.robotron.certificate.ldap.EmbeddedLdapServer.<init>(EmbeddedLdapServer.java:101)
     at 
de.robotron.certificate.ldap.EmbeddedLdapServer.getInstance(EmbeddedLdapServer.java:80)
     at 
de.robotron.certificate.ldap.EmbeddedLdapServerTest.interceptorTest(EmbeddedLdapServerTest.java:33)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     at java.lang.reflect.Method.invoke(Method.java:597)
     at 
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
     at 
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
     at 
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
     at 
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
     at 
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
     at 
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
     at 
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
     at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
     at 
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
     at 
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
     at 
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
     at 
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
     at 
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
     at 
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.NullPointerException
     at 
org.apache.directory.server.core.schema.SchemaInterceptor.check(SchemaInterceptor.java:922)
     at 
org.apache.directory.server.core.schema.SchemaInterceptor.add(SchemaInterceptor.java:1051)
     at 
org.apache.directory.server.core.api.interceptor.BaseInterceptor.next(BaseInterceptor.java:422)
     at 
org.apache.directory.server.core.normalization.NormalizationInterceptor.add(NormalizationInterceptor.java:131)
     at 
org.apache.directory.server.core.DefaultOperationManager.add(DefaultOperationManager.java:394)
     at 
org.apache.directory.server.core.shared.DefaultCoreSession.add(DefaultCoreSession.java:215)
     at 
org.apache.directory.server.core.shared.DefaultCoreSession.add(DefaultCoreSession.java:192)
     at 
de.robotron.certificate.ldap.EmbeddedLdapServer.addEntry(EmbeddedLdapServer.java:228)
     at 
de.robotron.certificate.ldap.EmbeddedLdapServer.start(EmbeddedLdapServer.java:189)
     ... 27 more

I think that this is due to my interceptor as I use a self defined 
object class with self defined attribute types. However I'm unsure how 
to add these objectclass and attribute types to the schema. I'm adding 
the interceptor as described in the user guide by

private void addInterceptor(DirectoryService service, OperationsFactory 
opsFactory) {
         List<Interceptor> interceptors = service.getInterceptors();

         // Find Normalization interceptor in chain
         int insertionPosition = -1;
         for (int pos = 0; pos < interceptors.size(); ++pos) {
             Interceptor interceptor = interceptors.get(pos);
             if (interceptor instanceof NormalizationInterceptor) {
                 insertionPosition = pos;
                 break;
             }
         }

         interceptors.add(++insertionPosition, new 
CertSearchInterceptor(opsFactory));
         service.setInterceptors(interceptors);
     }

which is called after instantiating the DirectoryService but before it 
has been started (or the partition has been added). My 
SchemaInterceptor's code is

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.filter.BranchNode;
import org.apache.directory.api.ldap.model.filter.EqualityNode;
import org.apache.directory.api.ldap.model.filter.ExprNode;
import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
import 
org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
import org.apache.directory.server.core.schema.SchemaInterceptor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import de.robotron.certificate.database.CertificateOperations;
import de.robotron.certificate.database.OperationsFactory;

/**
  * The <code>CertSearchInterceptor</code> class represents an 
interceptor which
  * requests certificates from the database instead of a LDAP server.
  * <p>
  * This class is immutable. It is thread safe as far as the
  * {@link OperationsFactory} provided to the constructor is thread safe.
  *
  * @author Sebastian Oerding
  */
final class CertSearchInterceptor extends SchemaInterceptor {
     /**
      * The logger for this class.
      */
     private static final Logger LOG = 
LogManager.getLogger(CertSearchInterceptor.class);

     /**
      * The factory especially giving access to {@link 
CertificateOperations}.
      */
     private final OperationsFactory dbFactory;

     /**
      * Initializes a new instance with the argument factory.
      *
      * @param application
      *            the factory providing the required operations to 
access the
      *            database, must not be <code>null</code>
      * @throws IllegalArgumentException
      *             if the argument factory is <code>null</code>
      */
     CertSearchInterceptor(OperationsFactory opsFactory) {
         if (opsFactory == null) {
             throw new IllegalArgumentException("The OperationsFactory 
must not be null!");
         }
         this.dbFactory = opsFactory;
     }

     /**
      * Searches for a certificate in the database.
      * <p>
      * Note that this method will always return <code>null</code>. It 
extracts
      * the common name from the search filter of the argument search 
context and
      * uses the extracted common name to read a certificate from the 
database.
      * To do so the common must be the value of the 
SubjectKeyIdentifier X.509
      * extension of the required certificate but with the colons 
normally used
      * for pretty printing omitted. If such a certificate is found an 
entry is
      * created and added to the search context.
      * <p>
      * If any problem occurs getting the certificate this is written to 
the log
      * file. However as simply finding no matching certificate not 
necessarily
      * indicates an error this is not logged as error. Other problems 
especially
      * the ones indicating a bug are logged as errors.
      * <p>
      * An entry is added if and only if a certificate matching the 
extracted
      * common name is found in the database.
      *
      * @return <code>null</code>
      */
     @Override
     public EntryFilteringCursor search(SearchOperationContext 
searchContext) {
         // 
System.out.println(searchContext.getRequestControl("2.16.840.1.113730.3.4.2"));
         // searchContext.setRequestControls(Collections.<String, Control>
         // emptyMap());
         ExprNode searchNode = searchContext.getFilter();
         String commonName = extractCommonName(searchNode);
         if (commonName == null) {
             LOG.error("Common name not found in search filter!");
             return null;
         }
         // We need some kind of wrapper as we also have to get the 
revocation
         // state from the database.
         byte[] userCertificate = readUserCertificate(commonName);
         boolean revocation = false;
         if (userCertificate == null) {
             LOG.info("No certificate for SubjectKeyIdentifier {} 
found!", commonName);
             return null;
         }
         createSearchEntry(searchContext, commonName, userCertificate, 
revocation);
         return null;
     }

     /**
      * Creates an entry using the provided values and adds it to the 
provided
      * search context.
      *
      * @param searchContext
      *            the search context from which to get the 
distinguished name
      *            (DN) and to which to add the created entry
      * @param commonName
      *            the value of the SubjectKeyIdentifier X.509 extension 
of the
      *            certificate (but without colons)
      * @param userCertificate
      *            the DER encoded X.509 certificate
      * @param revocation
      *            <code>true</code> if the certificate has already been 
revoked,
      *            <code>false</code> otherwise
      */
     private void createSearchEntry(SearchOperationContext 
searchContext, String commonName, byte[] userCertificate,
         boolean revocation) {
         Entry entry = new DefaultEntry(searchContext.getDn());
         try {
             entry.add("2.5.4.0", "extensibleObject", "top", "smpki");
             entry.add("1.3.6.1.2.1.2.2.1.8", 
String.valueOf(revocation).toUpperCase());
             entry.add("2.5.29.14", commonName);
             entry.add("2.5.4.36", userCertificate);
             entry.add("2.5.4.3", commonName);
             entry.add("0.9.2342.19200300.100.1.25", "tr03109");
             entry.add("2.5.4.11", "tr03109");
             searchContext.setEntry(entry);
             LOG.trace("Added entry with common name {} to search 
context.", commonName);
         } catch (LdapException e) {
             LOG.error("Error creating an entry for common name {}!", 
commonName);
         }
     }

     /**
      * Returns the user certificate whose value of the SubjectKeyIdentifier
      * x.509 extension matches the argument name from the database.
      *
      * @param commonName
      *            the SubjectKeyIdentifier of the needed certificate 
with colons
      *            omitted
      * @return the certificate which matches the argument name,
      *         <code>null</code> if no such certificate exists in the 
database
      */
     private byte[] readUserCertificate(String commonName) {
         return null;
     }

     /**
      * Extracts the common name from the search filter.
      *
      * @param searchNode
      *            the node which contains the common name attribute or 
which has
      *            a child node containing the common name attribute
      * @return the common name used in the search filter, 
<code>null</code> if
      *         no node containing this attribute is found
      */
     // TODO this is a very specific implementation only matching the search
     // requests expected by us. It may not be generalized!
     private String extractCommonName(ExprNode searchNode) {
         if (searchNode instanceof BranchNode) {
             BranchNode bNode = (BranchNode) searchNode;
             for (ExprNode child : bNode.getChildren()) {
                 if (child instanceof EqualityNode<?>) {
                     EqualityNode<?> eNode = (EqualityNode<?>) child;
                     if 
(eNode.getAttributeType().getOid().equals("2.5.4.3")) {
                         return eNode.getValue().toString();
                     }
                 }
             }
         } else if (searchNode instanceof EqualityNode<?>) {
             EqualityNode<?> eNode = (EqualityNode<?>) searchNode;
             if (eNode.getAttributeType().getOid().equals("2.5.4.3")) {
                 return eNode.getValue().toString();
             }
         }
         return null;
     }
}

Furthermore there are a two more questions remaining:
1) When I have added the partition and the embedded server is shutdown 
(closing the JVM) and started again in a new JVM. Does I have to / may 
add the schema again or does that depend on whether the tmp file has 
been deleted? Should I take take by removing the partition on shutdown?
2) When do I have to add the interceptor? As I have done it or after 
startup or before startup but after adding the partition, ...?

Btw. sometimes I feel like I'm close to speaking ASN1 as well as English 
(not sure whether my English is bad or my ASN1 is well). As I'm 
sometimes dealing with ASN1 data structures I'm already used to it but I 
still prefer to use the Apache DS :-) .

With regards Sebastian

Mime
View raw message