authorizeRequests() vs. authorizeHttpRequests​(Customizer<AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry> - spring

I want to configure my spring application security, all of requests should be authenticated before being served.
So I created a filter chain bean:
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
throws Exception {
return http
.authorizeRequests().anyRequest().authenticated()
.and().formLogin()
.and().build();
}
I also found out authorizeRequests method has an overload version which accepts an Customizer interface parameter.
So I tried the parameterized version.
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
throws Exception {
return http
.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.formLogin()
.and().build();
}
I noticed parameterized authorizeRequests method would return the same HttpSecurity object so you can keep configuring without calling and().
Is that the only difference between them ? If that so, wouldn't this overloaded version seemed to be redundant ?

Both ways of declaring authorizeRequests are valid. The one that accepts a customizer is a way to make your code easier to read because it avoids multiple indentation levels. Using the lambda customizer is recommended.
The difference between authorizeRequests and authorizeHttpRequests is explained here. The authorizeHttpRequests uses the new simplified AuthorizationManager API and the AuthorizationFilter, while authorizeRequests uses the AccessDecisionManager and FilterSecurityInterceptor. The latter will be deprecated in future version of Spring Security.

Related

Spring Security 6.0 allows me to see the h2-console login page but doesn't allow me to go inside, how do I do?

I'm struggling to access my h2-console under the protection of Spring Security 6.0, here is the code
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorizeRequests -> authorizeRequests
.requestMatchers("/h2-console/**").authenticated()
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin
.permitAll()
)
.csrf(csrf -> csrf
.ignoringRequestMatchers("/h2-console/**"))
.headers(headers -> headers
.frameOptions().sameOrigin());
return http.build();
}
I can see the h2-console login page though I'm not allowed to go inside.
similar code works well with Spring Security 5.7.5
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorizeRequests -> authorizeRequests
.antMatchers("/h2-console/**").authenticated()
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin
.permitAll()
)
.csrf(csrf -> csrf
.ignoringAntMatchers("/h2-console/**"))
.headers(headers -> headers
.frameOptions().sameOrigin())
;
return http.build();
}
I also tried WebSecurityCustomizer, which doesn't work either.
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring()
.requestMatchers("/h2-console/**");
}
Here is the debug log
Securing POST
/h2-console/login.do?jsessionid=aa31e312f86f5a876457524984cad7e0
Invalid CSRF token found for
http://127.0.0.1:8080/h2-console/login.do?jsessionid=aa31e312f86f5a876457524984cad7e0
Responding with 403 status code
What am I missing?
All the merits go to this github issue.
I'm just copying the solution over here to make it more convenient to find, as I experienced myself various h2 console problems (401, 403, ...) when I migrated my app from spring boot 2.7.x to 3.0.x (e.g. spring core 5.x to 6.x, and spring security 5.x to 6.x), and it took a little while to fall on that actual github issue and find that solution, which works perfectly fine (more details on why the antMatcher is still being used can be found in the linked github issue...):
#Configuration
public class SecurityConfiguration {
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers(AntPathRequestMatcher.antMatcher("/h2-console/**")).permitAll()
)
.headers(headers -> headers.frameOptions().disable())
.csrf(csrf -> csrf
.ignoringRequestMatchers(AntPathRequestMatcher.antMatcher("/h2-console/**")));
return http.build();
}
}
I traced the source codes from CsrfFilter.java, checked the comparison logic that happens inside. Only to find that it is comparing the provided ignoring URL /h2-console/** with the requesting URL,let's say it is /h2-console/login.do, from which the servlet name counterpart /h2-console/ gets removed, therefore comparing /h2-console/** with login.do instead, end up being evaluated to false.
I dont know what the new purpose would be for doing this, but set CSRF disabled could fix this problem.
Or you could manually put a custom matching logic instead of telling Spring nothing but a URL pattern:
http.csrf().ignoringRequestMatchers(new RequestMatcher() {
#Override
public boolean matches(HttpServletRequest request) {
String contextPath = request.getServletContext().getContextPath();
return request.getRequestURI().startsWith(contextPath + "/h2-console/");
}
});
I dont like lambda at all. I will update this answer if I know something new.
I had to disable csrf, frameOptions, and allow path through requestMatcher to make it all work. I also used toH2Console as it automatically provides correct matcher.
import static org.springframework.boot.autoconfigure.security.servlet.PathRequest.toH2Console;
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.csrf()
.disable()
.headers().frameOptions().disable()
.and()
.authorizeHttpRequests()
.requestMatchers(toH2Console())
.permitAll()
...

Pom.xml file dependencies not found

When I try to check my spring registration request, it should return the message "it Works," but I get nothing. Does anyone have any ideas what might be wrong?
I had missed an API link in the.antMatchers section of the WebSecurityConfig file.
If you preview your postman response you can see a login form which means you are not authenticated. If your signup request does not need any authentication you can simply exclude your registration api endpoint from spring checks. To do that permit all requests to the particular url in your configuration file
If you are using WebSecurityConfigurerAdapter, add an antMatcher entry to your configure method.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/v1/registration").permitAll()
.anyRequest().authenticated();
}
Since WebSecurityConfigurerAdapter is deprecated now if you want to use SecurityFilterChain you can do it as follows. For more info refer documentation.
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/v1/registration").permitAll()
.anyRequest().authenticated();
return http.build();
}

Spring Security filter chain with custom user ID check [duplicate]

This question already has answers here:
How to fix role in Spring Security?
(2 answers)
Closed 6 months ago.
I am trying to use an expression-based check for an user ID path variable, so users can only access resources that belong to them. It is pretty clearly described in the Spring documentation. But I cannot access the bean, with the error that a String is provided.
This is my security filter chain and the bean:
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.cors()
.and()
.csrf().disable()
.authorizeHttpRequests()
.antMatchers(WHITELIST_URLS).permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/api/**/users/{userId}/**").access("#userSecurity.checkUserId(authentication,#userId)")
.and()
.oauth2Login(oauth2login ->
oauth2login.loginPage("/oauth2/authorization/api-client-oidc"))
.oauth2Client(Customizer.withDefaults())
.build();
}
public static class UserSecurityConfig extends WebSecurityConfiguration {
#Bean("userSecurity")
private boolean checkUserId(Authentication authentication, String userId) {
return authentication.getPrincipal().equals(userId);
}
}
Error:
Required type: AuthorizationManager
<org.springframework.security.web.access.intercept.RequestAuthorizationContext>
Provided: String
I also have been trying to use an AuthorizationDecision (as lambda expression) but could not access the path variable.
Is the spring documentation wrong on this one? Been searching for quiet a while, but mostly found the same thing as in the Spring documentation.
Actually, I would like to manage this globally in the config and not on each mapping in the controllers by using the #PreAuthorize annotation.
Edit:
I have been unsuccessffuly trying to solve this using something like:
.access((authentication, object) ->
new AuthorizationDecision(object.getRequest().getServletPath().contains(
authentication.get().getName())))
or
.access((authentication, object) ->
new AuthorizationDecision(authentication.get().getPrincipal().equals(
object.getVariables().get("#userId"))))
I figured it out, the following example works. The more specific matcher has to be called first, otherwise it will not work.
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.cors()
.and()
.csrf()
.disable()
.authorizeHttpRequests()
.antMatchers("/api/v1/users/{userId}/**")
.access((authentication, object) -> new AuthorizationDecision(
object.getRequest().getServletPath().contains(
authentication.get().getName())
))
.antMatchers(WHITELIST_URLS)
.permitAll()
.antMatchers("/api/v1/**")
.authenticated()
.and()
.oauth2Login(oauth2login ->
oauth2login.loginPage("/oauth2/authorization/api-client-oidc"))
.oauth2Client(Customizer.withDefaults())
.build();
}

Spring HttpSecurity: Custom web security expressions

I am trying to configure the security of a new spring web application to check requests done against some of my urls.
Since none of the built-in expressions were valid for my logic, I decided to write my own, but it is not working at all.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().cacheControl();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/**/actuator/**").permitAll()
.antMatchers("/**/instances/**").permitAll()
//Custom expresion to check against
.antMatchers("/(?!login|user-profiles)/**").access("#checkAccess.hasRoleSelected()")
.anyRequest().authenticated()
.and()
.httpBasic().disable()
.addFilterBefore(new JWTLoginFilter(jwtConfig.getUri(), authenticationManager(), tokenService), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JwtTokenAuthenticationFilter(tokenService), UsernamePasswordAuthenticationFilter.class);
}
#Service
public class CheckAccess {
public boolean hasRoleSelected() {
return true;
}
}
As you can see in the documentation, to get this done you need a bean with a method returning a boolean value. While I do have both, the method is never called and no error is thrown.
What am I missing?
Btw, I am running 5.2.2 version of spring security.
Your antMatcher is invalid.
.antMatchers("/(?!login|user-profiles)/**").
Have a look at the allowed patterns in the AntPathMatcher doc.
It is basically, "?", "*" and "**".
You might want to give the regexMatcher a try, instead.

Reactive-Spring-Security-5.1.3.RELEASE, multiple authorizations

We have some endpoints, that are secured and before to access them we're verifying that the jws is correctly. In order to do that, we've defined a SecurityContext that actually persist the Auth pojo and to manipulate it downstream into the controller. The SecurityWebFilterChain config looks like that:
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http.csrf().disable()
.formLogin().disable()
.logout().disable()
.httpBasic().disable()
.securityContextRepository(securityContext)
.authorizeExchange()
.anyExchange().authenticated()
.and()
.build();
}
The calls were internally made, and we just verified the jws token.
Right now some external clients need to integrate with us, and we need to verify a jwe token. The thing is, that somehow we need to tell spring-security to validate for the existent endpoints the jws and for the new one the jwe.
I tried by specifying multiple security matchers but it failed :( . Do you have any other suggestions ?
You can expose more than one bean. I recommend specifying an order:
#Bean
#Order(1)
public SecurityWebFilterChain first(ServerHttpSecurity http) {
http
.securityMatcher(...)
...
return http.build();
}
#Bean
#Order(2)
public SecurityWebFilterChain second(ServerHttpSecurity http) {
http
.securityMatcher(...)
...
return http.build();
}
As a side note, Spring Security does ship with support for verifying JWS tokens reactively, and you might be able to remove some boilerplate by using it.

Resources