Search code examples
javaspringspring-bootspring-elspring-ldap

SpEL not supported in Spring annotation @Entry.base


I use Spring Data LDAP and Spring Boot provides out of the box support for an embedded UnboundID server. However, when I use Spring Data LDAP's @Entry annotation, I need to specify a different base in the annotation based on whether I'm using the embedded UnboundID LDAP server, or a remote Active Directory server.

I was attempting to do this with SpEL and profile-based properties by specifying:

@Entry(base = "${ldap.person.base}", ...)

Then I have an application.propreties with ldap.person.base=OU=AD Person Base and an application-embedded.properties with ldap.person.base=OU=Embedded Person Base.

However, the @Entry annotation does not seem to support SpEL evaluation:

javax.naming.InvalidNameException: Invalid name: ${ldap.person.base}

There is an open issue in Spring LDAP to add support for this, but is there any workaround or some other way I can accomplish this until it is supported in Spring LDAP?


Solution

  • Turns out the reason I needed a different base in the first place is because Spring was not setting the base on the ContextSource.

    When you let Spring Boot autoconfigure the embedded LDAP server, it creates a ContextSource as such in EmbeddedLdapAutoConfiguration:

    @Bean
    @DependsOn("directoryServer")
    @ConditionalOnMissingBean
    public ContextSource ldapContextSource() {
        LdapContextSource source = new LdapContextSource();
        if (hasCredentials(this.embeddedProperties.getCredential())) {
            source.setUserDn(this.embeddedProperties.getCredential().getUsername());
            source.setPassword(this.embeddedProperties.getCredential().getPassword());
        }
        source.setUrls(this.properties.determineUrls(this.environment));
        return source;
    }
    

    As you can see, nowhere in there does it call source.setBase(). So to solve this, I added a configuration file with @Profile("embedded") and manually created a ContextSource where I set the base myself (I leave off the credentials part because I don't use credentials for the embedded server):

    @Configuration
    @Profile("embedded")
    @EnableConfigurationProperties({ LdapProperties.class })
    public class EmbeddedLdapConfig {
    
        private final Environment environment;
        private final LdapProperties properties;
    
        public EmbeddedLdapConfig(final Environment environment, final LdapProperties properties) {
            this.environment = environment;
            this.properties = properties;
        }
    
        @Bean
        @DependsOn("directoryServer")
        public ContextSource ldapContextSource() {
            final LdapContextSource source = new LdapContextSource();
            source.setUrls(this.properties.determineUrls(this.environment));
            source.setBase(this.properties.getBase());
            return source;
        }
    }
    

    Now, I can leave the value of the base attribute in my @Entry the same for both the Active Directory server and the embedded UnboundID server and it works properly.