Spring Security Webflux. How to make ServerWebExch

2020-06-28 09:01发布

问题:

I cannot access the java.security.Principal authenticated by my CAS authentication system. serverWebExchange.getPrincipal() is allways empty.

In fact this is the implementation of DefaultServerWebExchange :

@Override
public <T extends Principal> Mono<T> getPrincipal() {
    return Mono.empty();
}

Another implementation of ServerWebExchange is ServerWebExchangeDecorator and its documentation says:

Note: if the purpose for using a decorator is to override properties like getPrincipal(), consider using ServerWebExchange.mutate() instead.

So my first question is: If that is what I am supposed to do, at what point in my WebFlux Security configuration (below) am I supposed to use ServerWebExchange.mutate().getPrincipal() to override ServerWebExchange.getPrincipal()?

My second question is: How am I supposed to get the pre-authenticated non-reactive request Principal?

So far, the only way I have found to retrieve the request Principal from ServerWebExchange is using reflection. But obviously that is not what I am supposed to do.

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Slf4j
public class SecurityConfig {
@Bean
    public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
        return http
                .csrf().disable()
                .httpBasic().disable()
                .formLogin().disable()
                .logout().disable()

                .authenticationManager(this.authenticationManager())
                .securityContextRepository(this.securityContextRepository())
                .authorizeExchange().pathMatchers("/public/**").permitAll()
                .and().authorizeExchange().anyExchange().authenticated()
                .and().build();
    }

    @Bean
    ReactiveAuthenticationManager authenticationManager() {
        return authentication -> {
            log.debug("Autentication: " + authentication.toString());
            if (authentication instanceof CustomPreAuthenticationToken) {
                authentication.setAuthenticated(true);
            }

            return Mono.just(authentication);
        };
    }

    @Bean
    ServerSecurityContextRepository securityContextRepository() {
        return new ServerSecurityContextRepository() {
            @Override
            public Mono<Void> save(ServerWebExchange serverWebExchange, SecurityContext securityContext) {
                return null;
            }

            @Override
            public Mono<SecurityContext> load(ServerWebExchange serverWebExchange) {
                Principal nonReactivePrincipal = getPrincipalFromExchangeUsingReflection(serverWebExchange);

            return Mono.just(new SecurityContextImpl(new CustomPreAuthenticationToken(nonReactivePrincipal.getName(), nonReactivePrincipal,  AuthorityUtils.createAuthorityList("ROLE_USER") )));
            }
        };
    }


    private Principal getPrincipalFromExchangeUsingReflection(ServerWebExchange serverWebExchange) {
        Principal principal = null;

        try {
            Field ServletServerHttpRequestField = serverWebExchange.getClass().getDeclaredField("request");
            ServletServerHttpRequestField.setAccessible(true);
            Object servletServerHttpRequest = ServletServerHttpRequestField.get(serverWebExchange);
            Field httpServletRequestField = servletServerHttpRequest.getClass().getDeclaredField("request");
            httpServletRequestField.setAccessible(true);
            HttpServletRequest httpServletRequest = (HttpServletRequest) httpServletRequestField.get(servletServerHttpRequest);

            principal = httpServletRequest.getUserPrincipal();

        } catch (IllegalAccessException | NoSuchFieldException e) {
            log.error(e.getMessage(), e);
        }

        return principal;
    }
}



public class CustomPreAuthenticationToken extends UsernamePasswordAuthenticationToken {        
    public CustomPreAuthenticationToken(String key, Object principal, Collection<? extends GrantedAuthority> authorities) {
        super(key, principal, authorities);
    }
}