Hi Eugen !
You are courageous an persistent ;-)
So some insights about how the server deals with schemas.
When you create the DefaultDirectoryServiceFactory() instance, it gets
'inited' at some point, and the initSchema() method is called:
in DefaultDirectoryServiceFactory:
public void init( String name ) throws Exception
{
if ( ( directoryService != null ) && directoryService.isStarted() )
{
return;
}
build( name );
...
private void build( String name ) throws Exception
{
directoryService.setInstanceId( name );
buildInstanceDirectory( name );
// Init the service now
initSchema();
...
and finally:
private void initSchema() throws Exception
{
File workingDirectory =
directoryService.getInstanceLayout().getPartitionsDirectory();
// Extract the schema on disk (a brand new one) and load the
registries
File schemaRepository = new File( workingDirectory, "schema" );
SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor(
workingDirectory );
try
{
extractor.extractOrCopy();
...
The key here is that we are going to fetch all files that match this
pattern in the file system (at least in the files that are resources):
".*schema[/\Q\\E]ou=schema.*\.ldif".
Either you have a system property that tells the server where to fetch
those files (schema.resource.location) or it defaults to the files that
are associated with the ResourceMap class loader (cl.getResources(
"META-INF/apacheds-schema.index" );)
FYI, this index is created while building the Apache LDAP API package,
using this maven plugin:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<configuration>
<target>
<!-- Various properties -->
<property name="schema.index"
value="target/generated-resources/apacheds/META-INF/apacheds-schema.index"
/>
<property name="schema.location"
value="src${file.separator}main${file.separator}resources${file.separator}"
/>
<!-- Listing all LDIF files under schema location -->
<path id="schema.files.path">
<fileset dir="${schema.location}">
<include name="**/*.ldif" />
<exclude name="schema-all.ldif" />
</fileset>
</path>
<property name="schema.files" refid="schema.files.path" />
<!-- Creating the schema index file -->
<echo message="${schema.files}" file="${schema.index}" />
<replace file="${schema.index}">
<!-- Replace the path separator (':' on Unix, ';' on
Windows) by a new line -->
<replacefilter token="${path.separator}"
value="${line.separator}" />
<!-- Remove the full path of the schema location to
get relative paths for files -->
<replacefilter
token="${basedir}${file.separator}${schema.location}" value="" />
<!-- Replace the file separator ('/' on Unix, '\' on
Windows) by a '/' - Useful on Windows -->
<replacefilter token="${file.separator}" value="/" />
</replace>
<attachartifact file="${schema.index}"
classifier="schema" type="index" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
(for the sake of completeness)
In any case, if you want to avoid processing this long list of files
(which is kind of costly), all you have to do is to set the
"schema.resource.location" system property that points to an empty
directory.
I'm not sure though that you won't need some part of the schemas for the
server to work properly, as we need to parse the DNs and the attributes
type within.
IMO, you should just get the minimal schema files (core, system), copy
them in the location you chose, to minimize the cost of loading the
schema at startup.
Side remark: up to a point, it would make sense to have a pre-loaded
schema based on the files, to avoid the parsing that is quite costly.
But that is an extension we have to include...
Hope it helps !
On 03/05/2022 02:27, Eugen Stan wrote:
Hi,
After a few hours of hacking at this I managed to get something working.
Thank you Emmanuel for your pointers.
I would like to improve startup time and avoid loading all (any of) the
schemas.
I am using DefaultDirectoryServiceFactory and LdapServer .
I replace the AuthenticatorInterceptor with my own.
I am able to run a simple ldap query and I log the username and passowrd:
ldapsearch -x -b "ou=system" -H ldap://localhost:10389 -D
"uid=admin,ou=system" -w secret
Using DefaultDirectoryServiceFactory loads all the schemas and does some
disk IO + starts slow.
Can I avoid loading the schemas and doing this much IO ?
I don't plan to use the schemas at all.
I gave it a shot but did not get far with that since
DefaultDirectoryService requires locks the disk and has some schema
initialization hardcoded inside - at specific paths.
I tink this logic could be made to be all in memory or to use a single
file but the code is too complex for me to figure out right now.
Thanks,
Eugen
For who is interested, the code is bellow (clojure) :
----
(ns ieugen.ldap-auth-provider.core
(:require [babashka.fs :as fs]
[taoensso.timbre :as log])
(:import (org.apache.directory.api.ldap.model.constants
AuthenticationLevel)
(org.apache.directory.server.core.api LdapPrincipal)
(org.apache.directory.server.core.api.interceptor.context
BindOperationContext)
(org.apache.directory.server.core.authn Authenticator)
(org.apache.directory.server.core.authn
AuthenticationInterceptor)
(org.apache.directory.server.core.factory
DefaultDirectoryServiceFactory)
(org.apache.directory.server.ldap LdapServer)
(org.apache.directory.server.protocol.shared.transport
Transport
TcpTransport)))
(defn ->transport
"Create a Transport for ^LdapServer."
(^Transport [& {:keys [address port nbThreads backlog]
:or {address "localhost"
port 389
nbThreads 3
backlog 50}}]
(into-array Transport [(TcpTransport. address port nbThreads
backlog)])))
(defn authenticate
(^LdapPrincipal [schema-manager _this ^BindOperationContext
bind-context]
(let [credentials (.getCredentials bind-context)
principal (.getPrincipal bind-context)
dn (.getDn bind-context)
dn-name (.getName dn)
auth-rdn (.getRdn dn)
username (.getValue auth-rdn)
auth-lvl (.getAuthenticationLevel bind-context)]
(log/info "Create principal with"
(String. credentials "UTF-8")
"principal" principal
"->" dn-name
"type -> val:" (.getType auth-rdn) "->" username
" | " (.getRdns dn))
(LdapPrincipal. schema-manager dn auth-lvl credentials))))
(defn delegating-authenticator
([schema-manager]
(reify Authenticator
(getAuthenticatorType [_this]
(log/info "getAuthenticatorType")
AuthenticationLevel/SIMPLE)
(init [_this directory-service]
(log/info "init" directory-service))
(destroy [_this]
(log/info "destroy"))
(invalidateCache [_this bind-dn]
(log/info "invalidateCache" bind-dn))
(authenticate [_this bind-context]
(log/info "authenticate" bind-context)
(authenticate schema-manager _this bind-context))
(checkPwdPolicy [_this user-entry]
(log/info "checkPwdPolicy" user-entry))
(isValid [_this bind-dn]
(log/info "isValid" bind-dn)
true)
(getBaseDn [_this]
(log/info "getBaseDn"))
(setBaseDn [_this base-dn]
(log/info "setBaseDn" base-dn)))))
(defn authentication-interceptor
[]
(proxy [AuthenticationInterceptor]
[]
(loadPwdPolicyStateAttributeTypes []
(log/info "loadPwdPolicyStateAttributeTypes"))))
(defn index-of-class [clazz coll]
(count (take-while #(not (instance? clazz %)) coll)))
(comment
(let [_ (do
(System/setProperty "workingDirectory" "tmp")
(fs/create-dirs "tmp"))
ds-factory (DefaultDirectoryServiceFactory.)
ds (doto (.getDirectoryService ds-factory)
(.setShutdownHookEnabled true)
(.setAllowAnonymousAccess true))
schema-manager (.getSchemaManager ds)
interceptors (.getInterceptors ds)
my-delegate-auth (delegating-authenticator schema-manager)
my-auth-interceptor (doto (authentication-interceptor)
(.setAuthenticators (java.util.HashSet.
[my-delegate-auth])))
auth-interceptor-idx (index-of-class AuthenticationInterceptor
interceptors)
_ (.set interceptors auth-interceptor-idx my-auth-interceptor)
_ (.setInterceptors ds interceptors)
ldap-server (doto (LdapServer.)
(.addTransports (->transport :port 10389))
(.setDirectoryService ds))
_ (do
(def ldaps ldap-server)
(-> ds .getChangeLog (.setEnabled true))
_ (.init ds-factory "ldap-auth-provider"))]
(log/info "Starting server")
(.start ldap-server)
(log/info "Server started"))
(.stop ldaps))
----
--
*Emmanuel Lécharny - CTO* 205 Promenade des Anglais – 06200 NICE
T. +33 (0)4 89 97 36 50
P. +33 (0)6 08 33 32 61
emmanuel.lecha...@busit.com https://www.busit.com/
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@directory.apache.org
For additional commands, e-mail: users-h...@directory.apache.org