How to get ServerWebExchange object in SecurityWebFilterChain bean - spring-boot

Hello Spring WebFlux community,
I have implemented x509 based authentication in spring webflux security bean using below code:
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
ReactiveAuthenticationManager authMan = auth0 -> {
..//lambda logic of setAuthenticated true, HERE I NEED TO ACCESS CURRENT REQUEST HEADERS VALUE BEFORE SETTING IT TO TRUE
};
http.x509(x509 -> x509
.principalExtractor(myx509PrincipalExtractor())
.authenticationManager(authMan ))
.authorizeExchange(exchanges ->
exchanges.anyExchange().authenticated());
return http.build();
}
Now, please observe the comment part inside auth0 lambda, there I need to access header values of current request. How can I get that ?

Related

Can I use both introspection server and local check for authorize token? Spring Boot - Security

I want to
introspect JWT token on remote server
and then check locally if scope/aud/iss/exp are correct
How can this be done most easily in Spring Boot?
As I understand first case is something similar to opauqeToken functionality (but I have normal JWT) and second case is more like using jwt
Spring Security only supports JWTs or Opaque Tokens, not both at the same time.
If I use opaqueToken, then validation on remote server is done without any effort (even if that's JWT)
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.mvcMatchers("/api/**").hasAuthority("SCOPE_" + scope)
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.opaqueToken(opaque -> opaque
.introspectionUri(this.introspectionUri)
.introspectionClientCredentials(this.clientId, this.clientSecret)
));
return http.build();
I have scope verified. Now I want to check iss, aud, exp. Is that doable with opaqueToken?
Or should I use jwt auth instead?
IMHO opaqueToken can be JWT, so now the question is how to verify and inspect it locally after remote introspection?
It's kind of hybrid of two different approaches, but hopefully you know the simple way how to do it.
Ok, I think I have my answer. I created my own introspector which is implementing OpaqueTokenIntrospector
public class JwtOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
private OpaqueTokenIntrospector delegate =
new NimbusOpaqueTokenIntrospector(
"introspect-url",
"client-id",
"client-secret"
);
#Override
public OAuth2AuthenticatedPrincipal introspect(String token) {
OAuth2AuthenticatedPrincipal introspected = this.delegate.introspect(token);
// SOME LOGIC
}
}
and I added it as a #Bean
#Bean
public OpaqueTokenIntrospector tokenIntrospector() {
return new JwtOpaqueTokenIntrospector();
}

Spring security: avoid authorization and authentication for certain paths

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...

Spring Security Configuration: Basic Auth + Spring Cloud Gateway

I've got a Reactive Spring Boot application, which is responsible for routing requests to downstream services, using Spring Cloud Gateway (i.e. it's an API gateway). The app has some actuator endpoints, that need to be secured, hence I want to use just a simple security for this like basic auth.
I'd like to configure the app, to require requests to /actuator/refresh to be authorized using basic auth (with a configured Spring security user and password). All requests to other endpoints, even if they include basic auth, only need to be passed to the downstream service.
My current Spring security configuration:
#Bean
#Order(1)
SecurityWebFilterChain securityWebFilterChain(final ServerHttpSecurity http) {
http.authorizeExchange(exchanges -> {
exchanges.matchers(EndpointRequest.toAnyEndpoint().excluding(HealthEndpoint.class, InfoEndpoint.class)).hasRole("ACTUATOR"); // requires Http Basic Auth
});
http.httpBasic(withDefaults()); // if not enabled, you cannot get the ACTUATOR role
return http.build();
}
#Bean
#Order(2)
SecurityWebFilterChain permitAllWebFilterChain(final ServerHttpSecurity http) {
http.authorizeExchange(exchanges -> exchanges.anyExchange().permitAll()); // allow unauthenticated access to any endpoint (other than secured actuator endpoints?)
http.httpBasic(ServerHttpSecurity.HttpBasicSpec::disable); // disable Http Basic Auth for all other endpoints
return http.build();
}
The request meant for the downstream service is not propagated by the API gateway. The spring boot service returns a 401 in this setup, while a 200 is expected / required.
Any ideas why this configuration is not working / how it should be configured otherwise?
Im not sure what is broken, but have you tried combining them and just have one filter?
#EnableWebFluxSecurity
public class MyExplicitSecurityConfiguration {
#Bean
public MapReactiveUserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("user")
.roles("ACTUATOR")
.build();
return new MapReactiveUserDetailsService(user);
}
#Bean
SecurityWebFilterChain securityWebFilterChain(final ServerHttpSecurity http) {
http.authorizeExchange(exchanges -> {
exchanges.matchers(EndpointRequest.toAnyEndpoint()
.excluding(HealthEndpoint.class, InfoEndpoint.class))
.hasRole("ACTUATOR");
exchanges.anyExchange().permitAll();
}).httpBasic(withDefaults());
return http.build();
}
}
another good thing could be to enable debug logging and see what fails.
this is done by defining in application.properties
logging.level.org.springframework.security=DEBUG

Spring Webflux -Security: How to let Spring return 401 (UNAUTHORIZED) exception when jwt token expired or wrong

Below is code which authorise JWT token (Keyclock) but in case of exception , server never returns 401
#EnableWebFluxSecurity
public class SecurityConfig {
#Bean
public SecurityWebFilterChain securityWebFilterChain(final ServerHttpSecurity http) {
// the matcher for all paths that need to be secured (require a logged-in user)
http.authorizeExchange(exchanges -> exchanges.pathMatchers("/actuator/**").permitAll()
.pathMatchers("/abcde/auth").permitAll()
.pathMatchers("/abcde/auth/refresh").permitAll()
.anyExchange().authenticated())
.csrf().disable()
.oauth2ResourceServer(oauth2ResourceServer ->
oauth2ResourceServer
.jwt(withDefaults())
).exceptionHandling(exception-> exception.authenticationEntryPoint((swe, e) -> Mono.fromRunnable(() ->
{
swe.getResponse()
.setStatusCode(HttpStatus.UNAUTHORIZED);
}
)
)
);
return http.build();
}
Another question :
Will this piece of code only validate expiry of JWT token or also other validation? What exactly happens is what i am interested to know.
In nutshell is this code sufficient enough for keyclock JWT validation through issuer URL?

Spring Boot 2.0 web flux custom authentication -- how to?

There are plenty of examples of minimal configurations of Spring Boot 2.0 security which compile or don't depending on which milestone or release candidate you try.
What is a minimal configuration that is not HTTP Basic, that will (1) let me access the HTTP request (headers, cookies, etc.) and also call my own authentication manager?
I would like to look at the headers and cookies, and decide from those who the user is, and whether or not the user is authenticated. How I do that should not matter to this answer -- the question is, what is the minimal Spring security config in order to allow me to hook in to the security infrastructure, so that my authentication is there in the reactive endpoints?
EDIT:
This works with Spring Boot 2.0.0.RC2, so my question could be, is this a correct way to introduce custom authentication into Spring Security?
#Configuration
#EnableWebFluxSecurity
public class SecurityConfiguration {
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter(authentication -> {
authentication.setAuthenticated(true);
return Mono.just(authentication);
});
authenticationFilter.setAuthenticationConverter(serverWebExchange ->
Mono.just(new AbstractAuthenticationToken(new ArrayList<>()) {
#Override
public Object getCredentials() {
return null;
}
#Override
public Object getPrincipal() {
return "jim";
}
}));
return http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.FORM_LOGIN)
.authorizeExchange()
.anyExchange()
.authenticated()
.and()
.build();
}
}
You can imagine that in the converter, I am free to look into the request by way of serverWebExchange and inspect any headers or cookies I wish, and that later in the upper lambda (standing in for ReactiveAuthenticationManager) I can actually decide whether or not it should be authenticated.

Resources