spring-attic / spring-security-javaconfig

Spring Security Java Configuration Support (to be merged with spring-security-config)
175 stars 121 forks source link

How to add password encoder for in memory authentication #113

Closed marceloverdijk closed 11 years ago

marceloverdijk commented 11 years ago

I have this snippet of code:

@Override
protected void registerAuthentication(AuthenticationRegistry registry) throws Exception {
    registry
            .inMemoryAuthentication()
            .withUser("me").password("mypassword").roles("USER");
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new StandardPasswordEncoder("verysecret");
}

I don't see a way to connect the in memory authentication with the password encoder.

In xml this would be:

<beans:bean id="encoder" 
    class="org.springframework.security.crypto.password.StandardPasswordEncoder"/>

<authentication-manager>
  <authentication-provider>
    <password-encoder ref="encoder" />
    <user-service>
      <user name="rod" 
          password="864acff7515e4e419d4266e474ea14a889dce340784038b704a30453e01245eed374f881f3df8e1e" 
          authorities="supervisor, teller, user" />
      <user name="dianne" 
          password="9992e040d32b6a688ff45b6e53fd0f5f1689c754ecf638cce5f09aa57a68be3c6dae699091e58324" 
          authorities="teller, user" />
      <user name="scott" 
          password="ab8d9744fa4dd5cee6eb692406fd29564267bad7c606837a70c44583b72e5684ec5f55c9dea869a5"
          authorities="user" />
      <user name="peter" 
          password="e446d30fcb00dc48d7e9fac49c2fec6a945171702e6822e1ec48f1ac1407902759fe30ed66a068df" 
          authorities="user" />
      </user-service>
  </authentication-provider>
</authentication-manager>

as from the Spring Security tutorial: http://static.springsource.org/spring-security/site/tutorial.html

rwinch commented 11 years ago

The mappings for many of the XML namespace configurations are demonstrated in tests which was mentioned in the README. I have since made this more obvious by making the XML Namespace a heading. Unfortunately while there was support for it there was no sample (as you pointed out) for password-encoder@ref. I have since added PasswordEncoderTests.groovy that demonstrates how to use it.

Please verify this resolves your issue.

marceloverdijk commented 11 years ago

Hi Rob,

I tried this below configuration:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpConfiguration http) throws Exception {
        http
                .authorizeUrls()
                .antMatchers...
                .and()
                .formLogin()...
                .and()
                .logout()...
                .and()
                .rememberMe();
    }

    @Override
    public void configure(WebSecurityBuilder builder) throws Exception {
        builder
                .ignoring()
                .antMatchers...;
    }

    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        BCryptPasswordEncoder encoder = passwordEncoder();
        return new AuthenticationManagerBuilder()
                .inMemoryAuthentication()
                .withUser("user").password(encoder.encode("password")).roles("USER")
                .and()
                .passwordEncoder(encoder)
                .and()
                .build();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

but it gives me:

[INFO] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class org.springframework.security.config.annotation.web.WebSecurityConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.security.web.FilterChainProxy org.springframework.security.config.annotation.web.WebSecurityConfiguration.springSecurityFilterChain() throws java.lang.Exception] threw exception; nested exception is java.lang.IllegalArgumentException: UserDetailsService cannot be null

Note: I'm using Spring 3.2.3 and Spring Security 3.1.4 so I should not worry about SPR-10546.

rwinch commented 11 years ago

Since you are not using the registerAuthentication, the UserDetailsService is not defaulted for rememberMe(). Try using the following instead:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpConfiguration http) throws Exception {
        http
                .authorizeUrls()
                .antMatchers...
                .and()
                .formLogin()...
                .and()
                .logout()...
                .and()
                .rememberMe();
    }

    @Override
    public void configure(WebSecurityBuilder builder) throws Exception {
        builder
                .ignoring()
                .antMatchers...;
    }

    @Override
    protected void registerAuthentication(AuthenticationRegistry registry) throws Exception {
        BCryptPasswordEncoder encoder = passwordEncoder();
        registry
                .inMemoryAuthentication()
                    .passwordEncoder(encoder)
                    .withUser("user").password(encoder.encode("password")).roles("USER")
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Alternatively provide a UserDetailsService to the rememberMe() method explicitly using rememberMe().userDetailsService. I'm still working on complete test coverage and error messages, but I created #114 to ensure that this gets a better error message prior to being released.

marceloverdijk commented 11 years ago

OK, I tried with the registerAuthentication as I was having that one anyway.

But neither AuthenticationRegistry or UserDetailsManagerRegistry has a passwordEncoder method to set the encoder (in current master branch).

rwinch commented 11 years ago

Thanks for pointing this out. I suppose that is what I get for using Groovy for the tests (it automatically handled the fact that AuthenticationRegistry is an AuthenticationBuilder and invoked the method). I will fix this issue.

marceloverdijk commented 11 years ago

Great to hear, I will try again as soon as it is fixed.

rwinch commented 11 years ago

I pushed out a fix for this. The javaconfig for the test was also moved to be .java to prevent such issues again. Please try with the updates and let me know if this resolves your issue.

marceloverdijk commented 11 years ago

Thanks!, just verified the fix and I can add the password encoder like:

@Override
protected void registerAuthentication(AuthenticationRegistry registry) throws Exception {
    registry
            .inMemoryAuthentication()
            .passwordEncoder(passwordEncoder())
            .withUser("username").password("password").roles("USER");
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
rwinch commented 11 years ago

Thanks for following up :)

marceloverdijk commented 11 years ago

ps: don't let @glaforge hear you removed that Groovy test :-)

rwinch commented 11 years ago

@marceloverdijk Haha...he will be glad to see the test stayed in Groovy. I only changed the config to Java since that was the only piece of code hiding this issue.