I'm running two jvms. One with webapp jwt auth and another one for mutual auth. It creates lot of overhead to the hosting machine? Is it possible to auth different paths with different auth mode in spring?
Yes, you can use multiple filter chains, one for each path:
#Bean
#Order(0)
SecurityFilterChain jwtPaths(HttpSecurity http) throws Exception {
http
.requestMatchers((requests) -> requests.mvcMatchers("/jwt-paths/**"))
// configuration for paths that use JWT auth
return http.build();
}
#Bean
#Order(1)
SecurityFilterChain x509Paths(HttpSecurity http) throws Exception {
http
.requestMatchers((requests) -> requests.mvcMatchers("/x509Paths/**"))
// configuration for paths that use X.509 auth
return http.build();
}
Related
Currently, my configuration is using HTTP basic and issuing JWT to the client. Can someone please help to make it such a way that JWT is issued from a single REST controller?
Without using HTTP basic.
I just want to do JWT authentication in my application.
Your effort and support is highly appreciated.
#Bean
public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception {
http.cors().disable();
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
http.authorizeHttpRequests().antMatchers("/token").permitAll().and()
.antMatcher("/**")
.authorizeHttpRequests(userauthz ->
userauthz.antMatchers("/myaccount").authenticated()
)
.authenticationProvider(userAuthProvider())
.httpBasic();
return http.build();
}
This is my related spring security configuration:
#Bean
SecurityWebFilterChain springSecurityFilterChain(
ServerHttpSecurity http,
AuthenticationWebFilter authenticationWebFilter
) {
return http
.httpBasic(HttpBasicSpec::disable)
.csrf(CsrfSpec::disable)
.formLogin(FormLoginSpec::disable)
.anonymous(AnonymousSpec::disable)
.logout(LogoutSpec::disable)
.authorizeExchange((authorize) -> authorize
.pathMatchers("/actuator/**").permitAll()
.pathMatchers("/login/**").permitAll()
.anyExchange().authenticated()
)
.addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION)
.build();
}
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("/actuator/**", "/login/**");
}
As you can see, I'm setting an AuthenticationWebFilter at SecurityWebFiltersOrder.AUTHENTICATION level.
I'm also avoiding to authorize "/actuator/**" and "/login/**" paths and I'm avoiding authentication for using WebSecurityCustomizer.
However, when I'm trying to reach above paths, I see authentication process is launched for above paths since, authenticationFilter is reached at code.
How could avoid authorization and authentication only for "/actuator/**" and "/login/**"?
EDIT:
I've took a look on this question, but its approach is what I'm using exactly with WebSecurityCustomizer...
I'm checking latest Spring Authorization Server v0.2.0 and found two formLogin() configured on the provided sample authorizationserver.
One is AuthorizationServerConfig.java:
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http.formLogin(Customizer.withDefaults()).build();
}
Another one is DefaultSecurityConfig.java:
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
My question is:
why there are two formLogin()s configured
If I wanted to customize formLogin() which one should I change?
The reason for the formLogin() configuration in AuthorizationServerConfig is purely a "convenience configuration", as it will setup the LoginUrlAuthenticationEntryPoint and perform the redirect to /login when the current request is not authenticated.
For example, when the client is redirected to /oauth2/authorize and the user is not authenticated, the user will be redirected to /login, which will match on the SecurityFilterChain defined by DefaultSecurityConfig NOT AuthorizationServerConfig.
Basically, the formLogin() in AuthorizationServerConfig serves the sole purpose of performing the redirect to /login, which is ultimately matched on the DefaultSecurityConfig SecurityFilterChain.
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.
We have a microservice architecture with securities for front to back with JWT, and back-to-back security with HTTP Basic.
Here is our configuration class for JWT :
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers(endpointsProperties.getJwtWithWildcard())
.and()
.csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
}
jwtFilter is a simple filter that reads the Authorization header, and set the SecurityContextHolder.
And the HTTP Basic :
#Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
for (Map<String, String> userData : properties.getUsers()) {
auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser(userData.get("login")).password(userData.get("password")).authorities(BASIC_AUTH_AUTHORITY);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers(endpoints.getBasicWithWildcard() )
.and().csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().httpBasic();
}
Those configuration class are used in differnets services, with distinct JWT and HTTP Auth endpoints. They are used either at the same time or independently. EndpointsProperties are loaded from application.yml.
But now, we have some referential microservices that we want to be reached either by other services or direclty by a (web) frontend application. We want to know if it is possible to secure a same URL ('/api/referential', for example) with the two different methods. Combining those configuration class with the same endpoints does not work, and it seems one configuration eraze the other.
Is it possible to secure a same URL path with different methods like that ? If yes, what do we need to change to enable it ?
Thanks for your support.
I think you can just add the two filters to the filter chain in this order
BasicAuthenticationFilter
JwtFilter
and make sure the ignoreFailure property of the BasicAuthenticationFilter is set to true.
This will make The basicAuthFilter authenticate requests with basicAuth and just continue down the filter chain if no basicAuth is sent - thus delegating to the JwtFilter.
then remove .httpBasic() from the WebsecurityConfig - as it will try to add another BasicSecurityFilter.
Just an off the cuff idea