How to permitAll anonymous access in Spring Boot 3 or above? - java

After upgraded to Spring Boot 3.0.0 from 2.7.6, public API are not accessible.
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(CsrfConfigurer::disable)
.authorizeHttpRequests(requests -> requests
.anyRequest().authenticated())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.build();
}
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> web
.ignoring()
.requestMatchers(CorsUtils::isPreFlightRequest)
.requestMatchers("/actuator/**", "/graphiql/**", "/voyager/**", "/vendor/**", "/rest/**",
"/swagger-ui/**", "/v3/api-docs/**");
}

You are almost there: move requestMatchers with permitAll to SecurityFilterChain definition (and remove WebSecurityCustomizer):
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.csrf(CsrfConfigurer::disable)
.authorizeHttpRequests(requests -> requests
.requestMatchers("/resources/**", "/signup", "/about").permitAll()
.anyRequest().authenticated())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.build();
}
Also, make sure the configuration class containing your SecurityFilterChain bean declaration is decorated with #Configuration (set a breakpoint or log line to ensure it is instantiated).
Few notes:
never disable CSRF protection if you don't also disable sessions with http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
CORS is configured with SecurityFilterChain too: http.cors().configurationSource(corsConfigurationSource())
you might need to map roles or groups or whatever your authorization-server populates as private-claim to Spring authorities by providing your own jwtAuthenticationConverter to JWT oauth2ResourceServer configurer
You can do all of above with no Java conf (just a few properties) with thin wrappers around spring-boot-starter-oauth2-resource-server I wrote:
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-webmvc-jwt-resource-server</artifactId>
<version>6.0.9</version>
</dependency>
#Configuration
#EnableMethodSecurity
public static class SecurityConfig {
}
com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443/realms/master
# This is adapted to Keycloak with a client-id spring-addons-public. Replace with the claim(s) your authorization-server puts roles into
com.c4-soft.springaddons.security.issuers[0].authorities.claims=realm_access.roles,resource_access.spring-addons-public.roles
# you might want something more restrictive as allowed origins (accepts a list), at least for a part of your endpoints
com.c4-soft.springaddons.security.cors[0].path=/**
com.c4-soft.springaddons.security.cors[0].allowed-origins=*
Complete (short) tutorials there (with spring libs only or "my" wrappers): https://github.com/ch4mpy/spring-addons/tree/master/samples/tutorials

The methods have not changed too much.
Sample :
#Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
// ...
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/resources/**", "/signup", "/about").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/db/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') and hasRole('DBA')"))
// .requestMatchers("/db/**").access(AuthorizationManagers.allOf(AuthorityAuthorizationManager.hasRole("ADMIN"), AuthorityAuthorizationManager.hasRole("DBA")))
.anyRequest().denyAll()
);
return http.build();
}
Provided of https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html
EDIT : To complete my answer, you have access to all methods, so to set up a resource server you need to add this :
#Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
// ...
.authorizeHttpRequests(authorize -> authorize
// ...
)
.and()
.oauth2ResourceServer( OAuth2ResourceServerConfigurer::jwt )
return http.build();
}
Remember to add the variables corresponding to your OAuth2 provider
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://{your-ouath2-provider}/{issuer-uri}
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://{your-ouath2-provider}/{jwk-uri} (optionnal)
The links depend on your oauth2 provider.
For more information about the resource owner server
: https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/index.html

Related

Spring Security ignores URL patterns from requestMatchers

I just created a new Spring Boot application with the following web security config (using spring-security-config:6.0.0):
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/", "/login", "/info/**").permitAll()
.anyRequest()
.authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll()
)
.logout(LogoutConfigurer::permitAll);
return http.build();
}
}
When trying to access any url I get redirected to /login with ERR_TOO_MANY_REDIRECTS. Something seems to be wrong with my SecurityConfig.
In previous versions I always used http.authorizeHttpRequests().antMatchers("/") instead of requestMatchers but it seems like they removed it.
Does requestMatchers() do the same thing or how can I configure url patterns that don't require login?

Disable spring security for subdomain

I have an application which can be accessed via different domains of type
www.*.example.com
For ex-
www.test.example.com
www.npc.example.com
www.train.example.com
When configuring the spring security (authentication/oauth) , I'd like to enable security only for certain subdomains and keep it disabled for others.
Say enable it for only "www.test.example.com"
Here's my filter config -
#Bean
fun securityWebFilterChain(
http: ServerHttpSecurity
): SecurityWebFilterChain {
return http.csrf().disable()
.cors().configurationSource(corsConfigurationSource())
.and()
.authorizeExchange()
.pathMatchers("/**")
.authenticated()
.and().httpBasic().and().oauth2Login { oauth2 ->
oauth2.authenticationSuccessHandler(oauthSuccessHandler)
.authorizedClientService(redisOauthClientService)
}
.build()
}
The base url is present as another header. Is there a way to use the header to enable/disable security config? Any other approach would also be fine.
You can create a custom ServerWebExchangeMatcher implementation that checks if the request comes from a subdomain and use it in your DSL, something like:
http
.authorizeExchange()
.matcher(new MySubdomainMatcher()).permitAll()
.pathMatchers("/**").authenticated();
class MySubdomainMatcher implements ServerWebExchangeMatcher {
public Mono<MatchResult> matches(ServerWebExchange exchange) {
// perform the logic in the request
}
}

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 HttpSecurity fluent api order?

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
}

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 ;)

Categories

Resources