spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.15k stars 40.68k forks source link

Actuator security breaks if userDetailsService is configured #7133

Closed ptahchiev closed 8 years ago

ptahchiev commented 8 years ago

Hello,

I found an issue with latest spring-boot 1.4.1 which works perfectly fine with spring-boot 1.3.8. Before I explain here's a sample repository that demonstrates the problem:

https://github.com/ptahchiev/spring-boot-actuator-problem

In my case I have registered a UserDetailsService which might throw an exception (perhaps the database is empty and I cannot find a user by the given username) but this means that spring boot actuators security login will not work.

In spring-boot 1.4.x and spring-security 4.1.x If you put a breakpoint in DaoAuthenticationProvider:setUserDetailsService you will see this method is called twice - first time it sets the InMemoryUserDetailsManager and second time it puts my UserDetailsService implementation.

In spring-boot 1.3.x and spring-security 4.0.x The method in DaoAuthenticationProvider:setUserDetailsService is called only once - with parameter InMemoryUserDetailsManager.

This means with 1.3.x users can login with login credentials from application.properties:

# Security
security.user.name=xxx
security.user.password=xxx

while with 1.4.x this is no longer possible if the UserDetailsSerrvice throws an error.

If you want to test my sample project, just run it with mvn spring-boot:run and try to access

http://localhost:8080/platform/health

and you will be prompted for username/password. Enter the values from application.properties but you will not be able to login. Now change the property in pom.xml to use the 1.3.8.RELEASE and you will see that you can login just fine.

vpavic commented 8 years ago

I think the cause of your problems are the Java Configuration improvements in Spring Security 4.1.

Regardless, I often use similar security setup (users stored in database + default user from config props) with global auth config similar to this:

@Configuration
public class AuthenticationManagerConfiguration
        extends GlobalAuthenticationConfigurerAdapter {

    @Value("#{securityProperties.user}")
    private SecurityProperties.User user;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser(this.user.getName())
                    .password(this.user.getPassword())
                    .roles(this.user.getRole().stream().toArray(String[]::new))
                    .and()
                .and()
            .userDetailsService(this.userDetailsService);
    }

}

HTH

wilkinsona commented 8 years ago

Thanks, @vpavic. I agree. @ptahchiev You'll see the same behaviour with Boot 1.3.8 if you override spring-security.version in your pom to use 4.1.x.

ptahchiev commented 8 years ago

Thanks @vpavic it worked. @wilkinsona I think at least the documentation needs to be updated - it tells you to use the security.user.name and security.user.password properties but like I said - even if you use them you can't login if you have declared a userDetailsService