I'm facing a use where I have to check oauth token against 2 different oauth provider given an input context (private call to may api vs public call)
Is there a simple way to define 2 oauth provider in spring boot and how to configure this balancing between the 2 providers ?
First you will need to implement 2 AuthenticationProvider then in your configuration class that implements WebSecurityConfigurerAdapter you would autowire those providers. Finally override the public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { to add those providers.
#Configuration
public class SampleAuthConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider1 provider1;
#Autowired
private CustomAuthenticationProvider2 provider2;
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.authenticationProvider(this.provider1)
.authenticationProvider(this.provider2);
}
}
Below are some tutorials. The may be outdated but may help you to figure it out.
https://dzone.com/articles/spring-security-authentication
https://www.baeldung.com/spring-security-multiple-auth-providers
Related
Hello GUYS I am new in spring security, I found article about authentication global (#Autowired configure) and local authentication (#Override configure)
could you tell me what is the difference between #Autowired configure() and #Override configure.
//Global
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin#password").roles("ROLE_ADMIN");
}
}
//local
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin#password").roles("ROLE_ADMIN");
}
}
One way of looking at it is that the global AuthenticationManager is "global" because it can be shared across the application as a bean, so when you #Autowire an AuthenticationManager, you must be configuring the global AuthenticationManager. If not, the AuthenticationManager you configure locally as you do above will only exist within the context of your WebSecurityConfigurerAdapter.
Take a look at this guide in the Spring website.
The Authentication and Access Control guide ( the same NatFar has provided link to) describes the following
Sometimes an application has logical groups of protected resources
(e.g. all web resources that match a path pattern /api/**), and each
group can have its own dedicated AuthenticationManager. Often, each of
those is a ProviderManager, and they share a parent. The parent is
then a kind of "global" resource, acting as a fallback for all
providers.
The image depicts the global (parent) and local resources , which is self explanatory
Also go through the links :
https://github.com/spring-projects/spring-security/issues/4571
https://github.com/spring-projects/spring-security/issues/4324
I'm using Spring Boot 2.0 (leveraging Spring Security 5.0). I'm trying to add a custom AuthenticationProvider to the AuthenticationManager in my WebSecurityConfigurerAdapter subclass. If I override the configure(AuthenticationManagerBuilder) method to supply my new provider, then I do not know how to retrieve the AuthenticationManager as a bean.
Ex:
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(customAuthenticationProvider);
}
}
where customAuthenticationProvider implements AuthenticationProvider.
In the Spring docs, it seems to specify that the two are incompatible:
5.8.4 AuthenticationProvider You can define custom authentication by exposing a custom AuthenticationProvider as a bean. For example, the
following will customize authentication assuming that
SpringAuthenticationProvider implements AuthenticationProvider:
[Note] This is only used if the AuthenticationManagerBuilder has not
been populated
Indeed, if I try to retrieve the AuthenticationManager bean using:
#Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManagerBean();
}
then the configure() method is never even called.
So how can I add my own custom provider to the default list of providers, and still be able to retrieve the AuthenticationManager?
You can just override WebSecurityConfigurerAdapter.authenticationManagerBean() method and annotate it with #Bean annotation
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
And there is no Spring Boot 5.0, The latest release is Spring Boot 2.0. I believe you are talking about Spring Security 5.0.
I am configuring Spring Security. To authenticate and authorize users, I override configure(AuthenticationManagerBuilder auth) of WebSecurityConfigurerAdapter. This works fine. Below is my code:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(customUserDetailsService)
.passwordEncoder(getPasswordEncoder());
}
But when I try to to enable method level security, per action, using #EnableGlobalMethodSecurity(securedEnabled = true) it throws an exception:
No AuthenticationManager found
As per my understanding AuthenticationManager is used to authenticate and authorize users, which I was already doing using configure(AuthenticationManagerBuilder auth) and Spring was injecting auth object itself.
Why I need to register AuthenticationManager manually?
#Bean #Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
What are the differennt purposes configure(AuthenticationManagerBuilder auth) and authenticationManagerBean() serves?
I am extending WebSecurityConfigurerAdapter. Why I need to provide a custom AuthenticationManager by overriding authenticationManagerBean().
Your configuration class extends WebSecurityConfigurerAdapter, which only configures web security (not method security):
Provides a convenient base class for creating a WebSecurityConfigurer instance. The implementation allows customization by overriding methods.
So your AuthenticationManager is only used for web security.
If you want to configure (change the defaults) method security, you can extend GlobalMethodSecurityConfiguration:
Base Configuration for enabling global method security. Classes may extend this class to customize the defaults, but must be sure to specify the EnableGlobalMethodSecurity annotation on the subclass.
To configure AuthenticationManager for method security, you can
overwrite GlobalMethodSecurityConfiguration#configure:
Sub classes can override this method to register different types of authentication. If not overridden, configure(AuthenticationManagerBuilder) will attempt to autowire by type.
expose your AuthenticationManager as a bean that can be autowired by GlobalMethodSecurityConfiguration, see WebSecurityConfigurerAdapter#authenticationManagerBean:
Override this method to expose the AuthenticationManager from configure(AuthenticationManagerBuilder) to be exposed as a Bean.
use only one global AuthenticationManager by autowiring the global AuthenticationManagerBuild, see Spring Security 3.2.0.RC2 Released:
For example, if you want to configure global authentication (i.e. you only have a single AuthenticationManager) you should autowire the AuthenticationMangerBuilder:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
// ... configure it ...
}
I started off looking at the Oauth2 starter project and minimal configuration.
https://github.com/spring-projects/spring-security-oauth/blob/master/tests/annotation/jdbc/src/main/java/demo/Application.java
All the examples either use in memory configuration or jdbc configuration for storing client roles (e.g ClientDetailsServiceConfigurer) . In my case the details should come in LDAP. So I have two questions.
How do override the default to go to ldap instead of memory or jdbc.
In general , where how do I unravel the Spring Boot thread and read the starter source code and how to change default config ? All I see is a high level annotation.
org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer
This indirection in Spring Boot makes it extremely difficult to follow and scant documentation doesn't help. Or maybe I am missing something?
thanks !!! this has been bugging me for a while.
To implement Oauth2 with LDAP, you may follow this tutorial : https://raymondhlee.wordpress.com/2015/12/05/oauth2-authorization-server-with-spring-security.
You may also take a look a this other question: spring-security-oauth2 2.0.7 refresh token UserDetailsService Configuration - UserDetailsService is required
As for your other question "I want to follow the request and see what components get invoked and when": I suggest you add logging.
(1) Add logging in every method
(2) Set log level for security package in application.properties:
logging.level.org.springframework.security=DEBUG
(3) Add CommonsRequestLoggingFilter:
#Bean
public CommonsRequestLoggingFilter requestLoggingFilter() {
LOGGER.info("Creating CommonsRequestLoggingFilter");
CommonsRequestLoggingFilter crlf = new CommonsRequestLoggingFilter();
crlf.setIncludeClientInfo(true);
crlf.setIncludeQueryString(true);
crlf.setIncludePayload(true);
return crlf;
}
(4) Add log level for CommonsRequestLoggingFilter (in application.properties):
logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG
For the OAuth/LDAP tutorial, here's the notable parts (quoted from https://raymondhlee.wordpress.com/2015/12/05/oauth2-authorization-server-with-spring-security):
Authorization Server Configuration Below is my implementation of the
AuthorizationServerConfigurerAdapter. The database schema for JDBC
client details and token services can be found in here.
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private DataSource dataSource;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(new JdbcTokenStore(dataSource)).authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
}
Login Security Configuration Below is the security configuration
handling user authorization.
#Configuration
#Order(Ordered.HIGHEST_PRECEDENCE) // note 1
public class LoginConfig extends WebSecurityConfigurerAdapter {
#Value("${ldap.domain}")
private String DOMAIN;
#Value("${ldap.url}")
private String URL;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requiresChannel().anyRequest().requiresSecure();
// Only requests matching regex are handled by this security configurer
http.requestMatchers().regexMatchers("/login", "/login.+", "/oauth/.+", "/j_spring_security_check", "/logout"); //
AuthenticationEntryPoint entryPoint = entryPoint();
http.exceptionHandling().authenticationEntryPoint(entryPoint);
http.formLogin(); // note 3i
http.addFilter(usernamePasswordAuthenticationFilter());
http.authorizeRequests().antMatchers("/login").permitAll();
http.authorizeRequests().antMatchers("/oauth/**").authenticated();
http.authorizeRequests().antMatchers("/j_spring_security_check").anonymous().and().csrf().disable();
}
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception { // note 4
authManagerBuilder.parentAuthenticationManager(authenticationManager());
}
protected AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
private AuthenticationEntryPoint entryPoint() {
return new LoginUrlAuthenticationEntryPoint("/login");
}
private UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() {
UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager();
AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler("/login?login_error=true");
filter.setAuthenticationFailureHandler(failureHandler);
return filter;
}
}
I have created additional authentication providers. I am registering them like following:
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAP());
auth.authenticationProvider(usernameAndPasswordAP());
auth.userDetailsService(getUserDetailsService());
}
Later in my code I am using AuthenticationManager to authenticate users. The issue is that I have only one authentication provider registered in authentication manager which is DaoAuthenticationProvider. It looks like my authentication providers are not registered at all. Should I do some additional config to make it work? I am using spring boot 1.2.6 Thanks in advance for any tips. Best Regards
When you override the configure(AuthenticationManagerBuilder auth), the underlying AuthenticationManager is exposed in one of 2 ways:
1) within SecurityConfig, you can simply call authenticationManager()
2) if you need AuthenticationManager outside of your SecurityConfig you will need to expose it as a bean, for example:
class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAP());
auth.authenticationProvider(usernameAndPasswordAP());
auth.userDetailsService(getUserDetailsService());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
The way we have authentication providers configured in our Spring Boot web applications is similar to what is discussed in the example Spring Security Java configuration from the current release reference guide, which modifies the default autowired AuthenticationManagerBuilder. Using your methods, it might look like:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAP())
.authenticationProvider(usernameAndPasswordAP())
.userDetailsService(getUserDetailsService());
}
If I am reading the Javadocs for the configure(AuthenticationManagerBuilder) method correctly, when you override this method you must specify your own AuthenticationManager. By using the autowired instance as described above, the default AuthenticationManager (which is ProviderManager, which in turn delegates to one or more configured AuthorizationProvider instances).
You may also need to annotate your configuration class with:
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
So that your access control rules are applied before the defaults that Spring Boot will otherwise configure for you.