question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Incorrect Location For Setting SecurityContext in Reactive Web Flux Security

See original GitHub issue

Currently we are creating SecurityContext in AuthenticationWebFilter. And SecurityContext is null in all filters wrapping AuthenticationFilter. Its interfering with the usecase of using custom SecurityContext implementation and not allowing us to set DomainContext on it and not allowing us to use DomainContext information in Authentication.

public class ExtendedSecurityContextImpl extends SecurityContextImpl {
    private DomainContext domainContext;
    public DomainContext getDomainContext() {
        return domainContext;
    }

    public void setDomainContext(DomainContext domainContext) {
        this.domainContext = domainContext;
    }
}
public class DomainContext implements Serializable {

    private final ServerWebExchange exchange;

    public DomainContext(final ServerWebExchange exchange) {
        this.exchange = exchange;
    }


    public Mono<String> getRemoteAddress(){
        return Mono.just(exchange.getRequest())
                .map(ServerHttpRequest::getRemoteAddress)
                .map(InetSocketAddress::getAddress)
                .map(InetAddress::getHostAddress);
    }


}
public class SecurityContextCompositeWebFilter implements WebFilter {


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return ReactiveSecurityContextHolder.getContext()
                .log()
                .filter(ExtendedSecurityContextImpl.class::isInstance)
                .log()
                .cast(ExtendedSecurityContextImpl.class)
                .log()
                .doOnSuccess(context -> context.setDomainContext(new DomainContext(exchange)))
                .then(chain.filter(exchange)).log();
    }
}

@Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
                .authorizeExchange()
                .pathMatchers(HttpMethod.GET, RequestMappingPaths.PATH_ROOT).hasAuthority(Role.ROLE_ADMIN)
                .pathMatchers(HttpMethod.GET, RequestMappingPaths.PATH_FAVICON).permitAll()
                .pathMatchers(HttpMethod.GET, apiPath(PATH_GET_ME)).hasAuthority(Role.ROLE_ADMIN)
                .pathMatchers(HttpMethod.GET, apiPath(PATH_GET_USERS)).hasAuthority(Role.ROLE_ADMIN)
                .anyExchange().denyAll()
                .and()
                .csrf().disable()
                .addFilterAt(filterConfig.securityContextCompositeWebFilter(), SecurityWebFiltersOrder.HTTP_BASIC)
                .addFilterAt(filterConfig.authenticationWebFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler)
                .and()
        ;
        return http.build();

    }

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
ankurpathakcommented, Dec 1, 2018

@rwinch Great Idea of creating custom context for request. Solved all my problems. Here is what I did:

final public class DomainContext implements Serializable {

    private final Mono<String> ip;

    public DomainContext(final ServerWebExchange exchange) {
        ip = Mono.just(exchange)
                .map(ServerWebExchange::getRequest)
                .map(ServerHttpRequest::getRemoteAddress)
                .map(InetSocketAddress::getAddress)
                .map(InetAddress::getHostAddress);
    }

    public Mono<String> getIp(){
        return ip;
    }
}

public class ReactiveDomainContextHolder {

    private static final Class<?> DOMAIN_CONTEXT_KEY = DomainContext.class;


    public static Mono<DomainContext> getContext() {
        return Mono.subscriberContext()
                .filter( c -> c.hasKey(SECURITY_CONTEXT_KEY))
                .flatMap( c-> c.<Mono<DomainContext>>get(DOMAIN_CONTEXT_KEY));
    }

    
    public static Function<Context, Context> clearContext() {
        return context -> context.delete(SECURITY_CONTEXT_KEY);
    }

    
    public static Context withDomainContext(Mono<? extends DomainContext> domainContext) {
        return Context.of(SECURITY_CONTEXT_KEY, domainContext);
    }

}

public class DomainContextWebFilter implements WebFilter {


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        DomainContext context = new DomainContext(exchange);
        return chain.filter(exchange)
                .subscriberContext(ReactiveDomainContextHolder.withDomainContext(Mono.just(context)));
    }
}
protected DomainContextWebFilter domainContextWebFilter(){
        return new DomainContextWebFilter();
    }

               http .addFilterAt(filterConfig.domainContextWebFilter(), SecurityWebFiltersOrder.REACTOR_CONTEXT)

1reaction
ankurpathakcommented, Nov 30, 2018

@rwinch Ok got your point. Even I agree I can do that with details object placed in Authentication token send and returned .Lets take look at these Mongo Collections(Spring Data MongoDb) we use in our project:

@Document(collection = Product.COLLECTION)
public class Product extends ExtendedDomain<String> implements Serializable {
   
    public static final String COLLECTION = "#{'products' +  T(co.indexify.util.SecurityUtil).getOrganization()}";
}

@Document(collection = UserVisitor.COLLECTION)
public final class UserVisitor extends ExtendedDomain<String> {
    public static final String COLLECTION = "#{'userVisitors' + T(co.indexify.util.SecurityUtil).getUser()}";
}

These mongo collections are using requestedUser and requestedOrganization store in DomainContext by SPEL in their names. So this information will be required always and this won’t be possible to do this with Authentication. So for this use I thing DomainContext on Custom SecurityContext is best place to do. What do you think??

Read more comments on GitHub >

github_iconTop Results From Across the Web

Reactive spring security context - java - Stack Overflow
In reactive application authentication information is stored in the Reactive flow and accessible from Mono / Flux .
Read more >
Persisting Authentication :: Spring Security
Upon authenticating the user, the user is associated to a new session id to prevent session fixation attacks. Authenticated User is Associated to...
Read more >
Spring Security Context Propagation with @Async - Baeldung
In this tutorial, we are going to focus on the propagation of the Spring Security principal with @Async. By default, the Spring Security...
Read more >
JWT Authentication in Spring Boot Webflux | by Jaiden Ashmore
Spring Security has always been a hurdle for me to maintain my interest in my personal projects. Once I have to figure out...
Read more >
Reactive Spring Security 5 Hands-On Workshop
Spring 5 WebFlux on Netty. Spring Data MongoDB with reactive driver. In-memory Mongodb to have an easier setup for the workshop ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found