Spring Boot HttpSecurity fluent api order? - java

Spring 2.0.3.RELEASE
Goal: Implement Spring Boot Security (basic auth for starters) on all endpoints except /actuator/health, /actuator/info and /ping (a custom controller that just returns ResponseEntity.status(HttpStatus.NO_CONTENT).build()).
The below gives me a 401. Any combination seems to either give me complete anonymous access to all endpoints or 401 to all.
I've set the spring.security.user.name and ...password in application.yml and it is working correctly.
I've implemented...
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
// just trying to get health working for starters
http.authorizeRequests().antMatchers("/actuator/health").permitAll()
.anyRequest().authenticated()
.and().formLogin().permitAll();
}
}
The below seemed like it was restricted to Actuator's /health and /info endpoints, but instead is also opening up my custom /ping endpoint as well (it's not in this list).
http.requestMatcher(EndpointRequest.to("health", "info"))
.authorizeRequests().anyRequest().permitAll();

The issue ended up being a bug in Spring Tool Suite. Using Boot Dashboard with a Gradle project wasn't always picking up build output. It seems to be using a different directory and I cannot figure it out.
The HttpSecurity configuration that ended up working for me was:
#Override
protected void configure(final HttpSecurity http) throws Exception {
// #formatter:off
http.
authorizeRequests().
antMatchers("/ping", "/actuator/health", "/actuator/info", "/login").permitAll().
anyRequest().authenticated().and().
httpBasic().and().
// CSRF tokens for API access
csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
// #formatter:on
}

Related

Spring Security: Purpose of .oauth2Client(withDefaults()); in HttpSecurity

This is from the doc
public HttpSecurity
oauth2Client​(Customizer<OAuth2ClientConfigurer>
oauth2ClientCustomizer) throws java.lang.Exception
Configures OAuth 2.0 Client support.
Example Configuration
The following example demonstrates how to enable OAuth 2.0 Client
support for all endpoints.
#Configuration
#EnableWebSecurity
public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().authenticated()
)
.oauth2Client(withDefaults());
}
}
Parameters: auth2ClientCustomizer - the Customizer to provide more
options for the OAuth2ClientConfigurer
Returns: the HttpSecurity for further customizations
The thing I understood is any requests coming to this server should be authenticated.
How does
.oauth2Client(withDefaults()); help in this case?
If I'm not wrong, an oAuth2 client is the one sending the requet, what can we actually configure about this? The documentation doesnt really explain much.
The http instance of HttpSecurity is a "bean settings server/application side".
Its method oauth2Client is not related to client configurations, but how and where the server/application should handle them.
Example:
Which clients have been authorized
Where to store authorized clients
How to authorize clients
How to remove an old authorized client
I think here , you can find more details about oauth2Client defaults .
#EnableWebSecurity
public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Client(oauth2Client ->
oauth2Client
.clientRegistrationRepository(this.clientRegistrationRepository())
.authorizedClientRepository(this.authorizedClientRepository())
.authorizedClientService(this.authorizedClientService())
.authorizationCodeGrant(authorizationCodeGrant ->
authorizationCodeGrant
.authorizationRequestRepository(this.authorizationRequestRepository())
.authorizationRequestResolver(this.authorizationRequestResolver())
.accessTokenResponseClient(this.accessTokenResponseClient())
)
);
}
}

Spring Boot Security PermitAll with RequestHeaderMatcher not working

After having followed a tutorial about microserves and OAuth2 in Maven Spring Boot, I got a problem. I want to exclude a request from the authentication, so unauthorized data can be gotten. This only doesn't seem to work in the way I do it. Can someone help me with this?
Tutorial I followed: https://developer.okta.com/blog/2018/02/13/secure-spring-microservices-with-oauth#microservices-architectures-with-spring-boot--spring-cloud
What I tried:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatcher(new RequestHeaderRequestMatcher("Authorization"))
.authorizeRequests()
.antMatchers("/**").authenticated()
.and()
.authorizeRequests()
.andMatchers(HttpMethod.GET, "/beers").permitAll();
}
}
I have to authenticate when I try to do the request. How do I solve this?
spring-security-oauth2-autoconfigure: 2.1.1.RELEASE
Firstly, your configuration is the same as the followings . Just removing those unnecessary duplicated authorizeRequests() and and() , which make it look more clearly :
http.requestMatcher(new RequestHeaderRequestMatcher("Authorization"))
.authorizeRequests()
.antMatchers("/**").authenticated()
.andMatchers(HttpMethod.GET, "/beers").permitAll();
It means spring security will only handle the requests if it has Authorization header. Otherwise ,the request will be ignored and no spring security stuff will apply to it.
So if the request has the Authorization header , it will then start to check the rules (i.e. those matcher things configured by authorizeRequests()) from the top to the bottom according to the declaration order.Once a rule is matched , the bottom rule will be ignored and will not be checked.
Since your first rule is to match every HTTP request ("/**") which makes all rules below it never execute and does not have any meaning.
On the other hand , if you want spring security totally ignore "/beers" even its request has Authorization header , you should configure WebSecurity to ignore it :
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.GET, "/beers");
}

Spring Boot OAuth2 SSO not working when authorizeRequests antMatcher is not set to root url

I've been trying to make an application with Spring Boot that uses Google as an identity provider for logging in.
The following configuration (using Spring Security) seems to work for this:
#Configuration
#EnableOAuth2Sso
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**","/callback/", "/error**")
.permitAll()
.anyRequest()
.authenticated();
}
}
However, I only really want to secure a small part of the website (e.g. everything under the /secured/ path).
So I thought changing the antMatcher that requests are authorized for would work for this:
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
antMatcher("/secured**")
.authorizeRequests()
...
When I try this the application still redirects me to /login, but it gives me a 404 on that page instead of redirecting me to google's servers.
I could of course add all public urls to the permitAll antMatcher, but that seems cumbersome to do everytime a new one is added.
Putting all public things on a /public** path is also not something I'd like to do since it'd look weird in the url
Could anybody shed some light on what is happening here or maybe offer alternative solutions?
Thanks in advance!

Spring Security .permitAll() no longer effective after upgrading to Spring Boot 2.0.2

I work with a web app that exposes a REST API to mobile apps. I upgraded my Spring Boot version from 1.5.3.RELEASE to 2.0.2.RELEASE and after fixing a few breaking changes I am facing one that I cannot solve.
I followed this Spring Boot 2.0 Migration Guide and Spring Boot Security 2.0 and also looked into Security changes in Spring Boot 2.0 M4.
The issue is that the app uses JWT authentication and there is an endpoint (/auth/login) accepts user credentials and generates a long-lived JWT in return.
There is a filter that examines the JWT token sent by the client and determines whether the client can access the requested resource.
Custom security config is like this:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfiguration {
#Configuration
#Order(1)
public class AuthenticationConfiguration extends WebSecurityConfigurerAdapter {
// Some dependencies omitted
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// we don't need CSRF because JWT token is invulnerable
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// don't create session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers(HttpMethod.GET, "/version/**").permitAll()
// Some more antMatchers() lines omitted
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
// disable page caching
httpSecurity.headers().cacheControl();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationTokenFilter(jwtTokenUtil);
}
}
#Configuration
#Order(2)
public class ClientVersionSupportConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry
.addInterceptor(versionCheckingFilter())
.addPathPatterns("/**")
.excludePathPatterns("/error"); // Some more endpoints omitted
}
#Bean
public VersionCheckingInterceptor versionCheckingFilter() {
return new VersionCheckingInterceptor();
}
}
}
Note the .antMatchers("/auth/**").permitAll() line. /auth endpoints should be accessible without JWT since the JWT has not yet been generated when the user has not yet logged in.
Before upgrading Spring Boot, it worked fine, now it is not working. Login attemps are rejected by the filter that checks the JWT. Looks like .permitAll() is not making the requests pass through. /version/** does not work either. Hitting it from the browser gives an error page.
I also tried to delete lines from the config until this remained:
httpSecurity
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
It did not help. Could you please help with restoring the original behavior?
Do you have a base path for you api, e.g. /api ?
The server.contextPath default Spring property name has changed to server.servlet.context-path.
So if you use a default base path for you api, you won't find the endpoints where you expect them. Unless you update the property ;)

Filter ordering with spring security and spring boot

I'm trying to use spring security to secure a rest/stateless api using JWT tokens. From the research I've been seeing, it involves turning off the spring security session management and then adding some custom filters to handle the user logging in as well as checking for the jwt token.
The problem I'm having is that once i add a filter, it's run on every instead of just the endpoints I want it on. I need to open up the login endpoint as well as a few others that will facilitate enrollment and reference data that doesn't need to be secured.
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/user").permitAll()
.anyRequest().authenticated().and()
.addFilterBefore(new StatelessAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
;
}
}
All StatelessAuthenticationFilter does is print "in here". I'm only expecting to see that message print when you go to localhost:8080/api/order, but i see it show up when you go to localhost:8080/api/user.
Is there a way to get this behavior?
The way you configured, the HttpSecurity will be applied to all the URLs including the user endpoint.
authorizeRequests() .antMatchers("/api/user").permitAll() line won't prevent "user" endpoint from authentication filter being called.
It just says that any authenticated user can call it.
You need to apply the filter to "order" endpoint only. Like this:
http .requestMatchers().antMatchers("/api/user") .and() .authorizeRequests().
#tsolakp's answer sorta works for me. I ended up overriding the
configure(Websecurity) method though
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/user");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated().and()
.addFilterBefore(new StatelessAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
;
}

Categories

Resources