I have a project that serves web pages that use form login. Now I would like the project to also expose an api that uses oauth. The idea is to have the ResourceServerConfigurerAdapter and WebSecurityConfigurerAdapter setup with requestMatchers to use different paths that don't overlap. However, I get either a OAuth2AuthenticationProcessingFilter or a UsernamePasswordAuthenticationFilter, but not both.
ResourceServerConfigurerAdapter:
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.mvcMatchers("/api/**")
...
}
If my WebSecurityConfigurerAdapter does not use any requestMatchers, I get a UsernamePasswordAuthenticationFilter but no OAuth2AuthenticationProcessingFilter.
http
.authorizeRequests()
...
If on the other hand I use any request matcher at all in the WebSecurityConfigurerAdapter, no matter how specific, I get a OAuth2AuthenticationProcessingFilter but no UsernamePasswordAuthenticationFilter.
http
.requestMatchers()
.mvcMatchers("/anything")
.authorizeRequests()
...
Solutions?
Or should I just go about this a different way? For instance, create a new project for the api? (even though that will mean duplicating some code, such as domain objects)
Consider Annotating ResourceServerConfigurerAdapter with #Order(40) and implement configure(HttpSecurity http) as the following:
http.antMatcher("/api/**").authorizeRequests().anyRequest().authenticated();
annotate WebSecurityConfigurerAdapter with #Order(50). Tested on spring boot 1.5.7.
try to secure all possible paths in the security configuration with the highest order.
Spring creates one security filter chain for security configuration in ResourceServerConfigurerAdapter and another for security configuration in WebSecurityConfigurerAdapter
Related
I've implemented OAuth2 using spring boot and spring security. Now I've different set of APIs available and I want to use different authentication methods for it. For e.g I want to use OAuth2 for /users/** apis and Http Basic Authentication for /admin/** APIs.
However, OAuth2 shouldn't work for /admin/** and HTTP basic shouldn't work for /users/** APIs.
Any help would be great!
In Spring Security you can have multiple filter chains that handle different requests.
So you can have one that handles requests to the /users/** uri which will have the Basic Authentication filter , and one that handles requests to /admin/** uri which will have the Oauth2 filters. To set this up, you need 2 instances of the WebSecurityConfigurerAdapter
One for Oauth2
#Configuration
#Order(1)
public static class Oauth2ConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.mvcMatcher("/user/**")
......
And another for Basic:
#Configuration
#Order(2)
public static class BasicConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.mvcMatcher("/admin/**")
......
This article explains it in more detail: https://www.baeldung.com/spring-security-multiple-entry-points
Also this code does something similar with Digest auth for /admin and Basic for all other. https://github.com/wlesniak/spring-security-authn-authz-course/tree/master/module_2/mod2_crypto_portfolio_digest
In an attempt to develop a generic identity service for a project I am working on, I need to support Azure ADFS-based SAML security for UI pages and Oauth2 based security for my REST APIs in a single spring-boot application
I have a spring boot application attempting to provide SAML based protection for some of my UI resources and Oauth2 based protection for my REST APIs. The UI pages and the REST APIs are hosted in the same spring boot based application. I have a SecurityConfiguration class that extends WebSecurityConfigurerAdapter and that contains my SAML configuration. I also have a ResourceServerConfig class that extends ResourceServerConfigurerAdapter where I have tried to configure the Oauth2 authentication for my REST APIs.
Here is what my code looks like
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
/////// Other methods //////
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests().anyRequest().authenticated();
http.httpBasic().authenticationEntryPoint(samlEntryPoint());
http.csrf().disable();
http.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class).addFilterAfter(samlFilter(), BasicAuthenticationFilter.class);
http.authorizeRequests().antMatchers("/oauth/token").permitAll().anyRequest().authenticated();
}
The ResourceServerConfig class looks something like the following
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
{
#Override
public void configure(HttpSecurity http) throws Exception
{
http
.csrf().disable()
.anonymous().and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/api/**").authenticated();
}
My problem is, with the above configuration in place, I can either get SAML protection on my UI pages OR Oauth2 protection on my APIs but not both. If I remove #EnableResourceServer from the ResourceServerConfig class and try to access one of my UI pages, I am reliably redirected to the microsoft Azure login page which redirects me back to my UI page after successful authentication. But with this, any attempt to access my apis (with valid bearer tokens) results in a redirection to the microsoft Azure login page. If I re-enable #EnableResourceServer my APIs get protected and behave as expected but SAML protection for all UI pages gets completely disabled with spring allowing unhindered access to all UI resources.
I can't figure out how to tell spring boot to use which authentication framework for the two kinds of URL patterns I have. Is such a thing even possible?
Any help with this would be appreciated.
Regards,
Dipak Jha
I think I have found an answer to my own question. This reply here provides a workable solution. A properly configured OAuthRequestedMatcher seems to do the trick. Please let me know if someone thinks this can be done in a better way.
Regards
Dipak Jha
I'm trying to understand how authorization with Spring Security works. I found out that a custom filter chain can be defined by extending WebSecurityConfigurerAdapter. But where exactly are the interceptors matched to a URL? For example, if I have something like
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(""/signup", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.anyRequest().authenticated();
where can I programmatically decide that the interceptor for /user/ should be CustomInterceptor (that extends AbstractSecurityInterceptor)? I do explicitly not want to do it in an xml-file, I'm trying to understand how it works programmatically.
I updated an already existing application from Spring Boot 1.3 to 2.0.1. This application makes use of the Actuator and exposes a REST-style API.
In Boot 1.3 the API could be used without authentication and the actuator endpoint was configured to be password protected:
security.user.name=foo
security.user.password=bar
security-user.role=ADMIN
I updated this like documented in the configuration changelog and renamed the entries from security.user.name to spring.security.user.name and alike.
But when I try to curl my API, I am denied because I do not provide credentials:
In the Spring Blog I found a possible solution how to configure Spring Security on a detailled level:
http
.authorizeRequests()
// 1
.requestMatchers(EndpointRequest.to("status", "info"))
.permitAll()
// 2
.requestMatchers(EndpointRequest.toAnyEndpoint())
.hasRole("ACTUATOR")
// 3
.requestMatchers(StaticResourceRequest.toCommonLocations())
.permitAll()
// 4
.antMatchers("/**")
.hasRole("USER")
.and()
...
but this is more fine-grained than I need and I am looking for an application.properties based solution.
Is there a way to solve this without additional code ?
When you set spring.security.user.name and spring.security.user.password, you are configuring form login via spring-security for the whole application, including the Actuator endpoints.
Unfortunately, in Spring Boot 2.0 you cannot set a different username/password or disable authentication for the Actuator endpoints using the properties. This means you have to explicitly allow the actuator endpoints through Security configuration.
Through spring-security, you can also allow public access to your endpoints and require credentials for the actuator endpoints very easily:
#Configuration
public class BasicSecurityConfig extends WebSecurityConfigurerAdapter {
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/actuator/**").hasRole("ACTUATOR")
.anyRequest().permitAll();
}
}
(I assumed you were using WebMvc, not WebFlux, which is a bit different)
Verify that you have the following in the application.properties:
spring.security.user.name=user
spring.security.user.password=pass
spring.security.user.roles=ACTUATOR,USER # and others, if you like
management.endpoint.health.roles=ACTUATOR
See here for a quick and nice explanation between the differences in Actuator in Spring 1.x vs 2.0.
For Spring Boot 2.0, when we override the configure method of WebSecurityConfigurerAdapter all existing security backs off and we can provide our custom security. In your case you just need to authenticate the actuator endpoints, which can be done as follows:
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/actuator/**").authenticated();
}
}
No changes are required in the application.properties file.
So i have a simple spring boot app with out-of-the-box security configuration. In my 'dev' profile I've open access to all URLS with these properties
# dev
security.basic.enabled=false
management.security.enabled=false
and I can enable authentication for all URL's in my 'production' profile by changing the values to
# production
security.basic.enabled=true
management.security.enabled=true
The real security requirement for the application is that it has two pages
The '/' index page should be public to all.
The '/admin' page should be restricted.
I know from countless other stackoverflow questions in spring-boot-security and spring-security that I can override the default spring-boot security config by using the #EnableWebSecurity and then defining custom rules
#EnableWebSecurity
public class WebMvcConfig extends WebMvcConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()....
}
I'm wondering is there not a simpler way which configures spring-boot only, and which doesn't involve the customisation of the spring-security to achieve this requirement?
There's a difference between overriding and configuring. By using #EnableWebSecurity, you're still just configuring Spring Security to work the way you want it to work. So to answer your question, no, there is not a "simpler way". This is how you do it and it isn't difficult.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.and()
.authorizeRequests()
.antMatchers("/admin/**").authenticated();
}
}
Something like that is more or less all you need based on your requirements.