0

I am implementing ldap authentication using Spring Security. It works when I hardcode all the ldap server information in following configuration class.

//WebSecurityConfig.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
            .formLogin();
    }

    @Configuration
    protected static class AuthenticationConfiguration extends
            GlobalAuthenticationConfigurerAdapter {

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception { 

            DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://ldap.mdanderson.edu:389/dc=mdanderson,dc=edu");
            contextSource.setUserDn("cn=ris_flow,ou=service accounts,ou=institution,ou=service accounts,dc=mdanderson,dc=edu");
            contextSource.setPassword("xxxyyyzzz");
            contextSource.setReferral("follow"); 
            contextSource.afterPropertiesSet();  
            LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth.ldapAuthentication();

            ldapAuthenticationProviderConfigurer
                .userDnPatterns("cn={0},ou=institution,ou=people")
                .userSearchBase("")
                .contextSource(contextSource);
        }
    }
}

I decided to put these server information in application.properties and set the variables using @Value in my config class, so I add the following right before AuthenticationConfiguration.

@Value("${ldap.contextSource.url")
private static String url;

@Value("${ldap.contextSource.managerDn")
private static String userDn;

@Value("${ldap.contextSource.managerPass")
private static String userPass;

And replaced the lines of contextSource to:

    DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(url);
    contextSource.setUserDn(userDn);
    contextSource.setPassword(userPass);

However when I ran it again, the application failed to start with errors below:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource.......
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate....
Caused by: java.lang.IllegalArgumentException: An LDAP connection URL must be supplied.


org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource....
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate....
Caused by: org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built

What did I do wrong?

1 Answer 1

1

Check this piece of code

    @Value("${ldap.contextSource.url") 
private static String url; 
    @Value("${ldap.contextSource.managerDn") 
private static String userDn; 
    @Value("${ldap.contextSource.managerPass") 
private static String userPass;

You need to close the brackets properly this way

@Value("${ldap.contextSource.url}") private static String url; 
@Value("${ldap.contextSource.managerDn}") private static String userDn; 
@Value("${ldap.contextSource.managerPass}") private static String userPass;

From Spring In Action Fourth Edition book:

When relying on component-scanning and autowiring to create and initialize your application components, there’s no configuration file or class where you can specify the placeholders. Instead, you can use the @Value annotation in much the same way as you might use the @Autowired annotation. In order to use placeholder values, you must configure either a PropertyPlaceholderConfigurer bean or a PropertySourcesPlaceholderConfigurer bean. Starting with Spring 3.1, PropertySourcesPlaceholderConfigurer is preferred because it resolves placeholders against the Spring Environment and its set of property sources. The following @Bean method configures PropertySourcesPlaceholderConfigurer in Java configuration:

@Bean
public
static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}

EDIT: Complete example accesing properties using SPRING 4.2.5 RELEASE

Configuration Class:

@Configuration
@ComponentScan
@PropertySource("classpath:/your/package/example.properties")
// In my case, this package is stored in src/main/resources folder, which is in the classpath of the application
public class SpringPropertiesConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

Component (Bean) accessing the properties:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class ComponentAccessingProperties {

    @Value("${first.property}")
    private String propertyOne;

    @Value("${second.property}")
    private String propertyTwo;


    public String getPropertyOne() {
        return propertyOne;
    }

    public String getPropertyTwo() {
        return propertyTwo;
    }

}

Example properties file (/your/package/example.properties):

first.property=ONE
second.property=SECOND

Test Class:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import your.package.ComponentAccessingProperties;
import your.package.SpringPropertiesConfig;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringPropertiesConfig.class)
public class TestAccessingProperties {

    @Autowired
    private ComponentAccessingProperties componentAccesingProperties;

    @Test
    public void shouldNotBeNull() {
        assertNotNull(componentAccesingProperties);
    }

    @Test
    public void checkProperties() {
        assertEquals("ONE", componentAccesingProperties.getPropertyOne());
        assertEquals("SECOND", componentAccesingProperties.getPropertyTwo());
    }
}
Sign up to request clarification or add additional context in comments.

13 Comments

unfortunately still the same
Ok, checking your code, in your configuration class your should annotate the class with @PropertySource to indicate where properties are located and use a bean of class PropertiesPlaceholderConfigurer. Check this link where you can find an example websystique.com/spring/…. I didn't try it but seems to be fine
I am getting the error FileNotFoundException: class path resource [application.properties] cannot be opened because it does not exist. I have my application.properties under /src/main/resources/config. I think that is in classpath with auto config of Spring Boot. I have db connection information in that file which was apparently picked up correctly.
I understand that "/src/main/resources" should be the classpath main resources folder, so your application.properties would be in config/application.properties. Try to set this path "@PropertySource(value = { "classpath:config/application.properties" })" and tell me ok?
You have used $ or # in your value annotation?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.