Skip to content

Commit cd08102

Browse files
mouelletrwinch
authored andcommitted
Add debug logging
Goal is to provide insight to devs on: - Authentication & Authorization success/failures - WebSession & SecurityContext - Request matchers, cache & authn/authz flow Fixes gh-5758
1 parent 8d44763 commit cd08102

14 files changed

+231
-50
lines changed

web/src/main/java/org/springframework/security/web/server/DefaultServerRedirectStrategy.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.security.web.server;
1818

19+
import org.apache.commons.logging.Log;
20+
import org.apache.commons.logging.LogFactory;
1921
import org.springframework.http.HttpStatus;
2022
import org.springframework.http.server.reactive.ServerHttpResponse;
2123
import org.springframework.util.Assert;
@@ -28,9 +30,11 @@
2830
* The default {@link ServerRedirectStrategy} to use.
2931
*
3032
* @author Rob Winch
33+
* @author Mathieu Ouellet
3134
* @since 5.0
3235
*/
3336
public class DefaultServerRedirectStrategy implements ServerRedirectStrategy {
37+
private static final Log logger = LogFactory.getLog(DefaultServerRedirectStrategy.class);
3438
private HttpStatus httpStatus = HttpStatus.FOUND;
3539

3640
private boolean contextRelative = true;
@@ -41,7 +45,11 @@ public Mono<Void> sendRedirect(ServerWebExchange exchange, URI location) {
4145
return Mono.fromRunnable(() -> {
4246
ServerHttpResponse response = exchange.getResponse();
4347
response.setStatusCode(this.httpStatus);
44-
response.getHeaders().setLocation(createLocation(exchange, location));
48+
URI newLocation = createLocation(exchange, location);
49+
if (logger.isDebugEnabled()) {
50+
logger.debug("Redirecting to '" + newLocation + "'");
51+
}
52+
response.getHeaders().setLocation(newLocation);
4553
});
4654
}
4755

web/src/main/java/org/springframework/security/web/server/DelegatingServerAuthenticationEntryPoint.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.security.web.server;
1818

19+
import org.apache.commons.logging.Log;
20+
import org.apache.commons.logging.LogFactory;
1921
import org.springframework.http.HttpStatus;
2022
import org.springframework.util.Assert;
2123
import reactor.core.publisher.Flux;
@@ -33,10 +35,13 @@
3335
* on a {@link ServerWebExchangeMatcher}
3436
*
3537
* @author Rob Winch
38+
* @author Mathieu Ouellet
3639
* @since 5.0
3740
*/
3841
public class DelegatingServerAuthenticationEntryPoint
3942
implements ServerAuthenticationEntryPoint {
43+
private static final Log logger = LogFactory.getLog(DelegatingServerAuthenticationEntryPoint.class);
44+
4045
private final List<DelegateEntry> entryPoints;
4146

4247
private ServerAuthenticationEntryPoint defaultEntryPoint = (exchange, e) -> {
@@ -61,12 +66,26 @@ public Mono<Void> commence(ServerWebExchange exchange,
6166
.filterWhen( entry -> isMatch(exchange, entry))
6267
.next()
6368
.map( entry -> entry.getEntryPoint())
64-
.defaultIfEmpty(this.defaultEntryPoint)
69+
.doOnNext(it -> {
70+
if (logger.isDebugEnabled()) {
71+
logger.debug("Match found! Executing " + it);
72+
}
73+
})
74+
.switchIfEmpty(Mono.just(this.defaultEntryPoint)
75+
.doOnNext(it -> {
76+
if (logger.isDebugEnabled()) {
77+
logger.debug("No match found. Using default entry point " + defaultEntryPoint);
78+
}
79+
})
80+
)
6581
.flatMap( entryPoint -> entryPoint.commence(exchange, e));
6682
}
6783

6884
private Mono<Boolean> isMatch(ServerWebExchange exchange, DelegateEntry entry) {
6985
ServerWebExchangeMatcher matcher = entry.getMatcher();
86+
if (logger.isDebugEnabled()) {
87+
logger.debug("Trying to match using " + matcher);
88+
}
7089
return matcher.matches(exchange)
7190
.map( result -> result.isMatch());
7291
}

web/src/main/java/org/springframework/security/web/server/authentication/AnonymousAuthenticationWebFilter.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@
1818

1919
import java.util.List;
2020

21+
import org.apache.commons.logging.Log;
22+
import org.apache.commons.logging.LogFactory;
2123
import reactor.core.publisher.Mono;
2224

2325
import org.springframework.security.authentication.AnonymousAuthenticationToken;
@@ -37,12 +39,11 @@
3739
* {@code ReactiveSecurityContextHolder}, and populates it with one if needed.
3840
*
3941
* @author Ankur Pathak
42+
* @author Mathieu Ouellet
4043
* @since 5.2.0
4144
*/
4245
public class AnonymousAuthenticationWebFilter implements WebFilter {
43-
// ~ Instance fields
44-
// ================================================================================================
45-
46+
private static final Log logger = LogFactory.getLog(AnonymousAuthenticationWebFilter.class);
4647
private String key;
4748
private Object principal;
4849
private List<GrantedAuthority> authorities;
@@ -72,18 +73,25 @@ public AnonymousAuthenticationWebFilter(String key, Object principal,
7273
this.authorities = authorities;
7374
}
7475

75-
7676
@Override
7777
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
7878
return ReactiveSecurityContextHolder.getContext()
7979
.switchIfEmpty(Mono.defer(() -> {
80-
SecurityContext securityContext = new SecurityContextImpl();
81-
securityContext.setAuthentication(createAuthentication(exchange));
80+
Authentication authentication = createAuthentication(exchange);
81+
SecurityContext securityContext = new SecurityContextImpl(authentication);
82+
if (logger.isDebugEnabled()) {
83+
logger.debug("Populated SecurityContext with anonymous token: '" + authentication + "'");
84+
}
8285
return chain.filter(exchange)
8386
.subscriberContext(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(securityContext)))
8487
.then(Mono.empty());
85-
})).flatMap(securityContext -> chain.filter(exchange));
86-
88+
}))
89+
.flatMap(securityContext -> {
90+
if (logger.isDebugEnabled()) {
91+
logger.debug("SecurityContext contains anonymous token: '" + securityContext.getAuthentication() + "'");
92+
}
93+
return chain.filter(exchange);
94+
});
8795
}
8896

8997
protected Authentication createAuthentication(ServerWebExchange exchange) {

web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@
1717

1818
import java.util.function.Function;
1919

20+
import org.apache.commons.logging.Log;
21+
import org.apache.commons.logging.LogFactory;
2022
import reactor.core.publisher.Mono;
2123

2224
import org.springframework.security.authentication.ReactiveAuthenticationManager;
@@ -65,9 +67,11 @@
6567
*
6668
* @author Rob Winch
6769
* @author Rafiullah Hamedy
70+
* @author Mathieu Ouellet
6871
* @since 5.0
6972
*/
7073
public class AuthenticationWebFilter implements WebFilter {
74+
private static final Log logger = LogFactory.getLog(AuthenticationWebFilter.class);
7175
private final ReactiveAuthenticationManagerResolver<ServerWebExchange> authenticationManagerResolver;
7276

7377
private ServerAuthenticationSuccessHandler authenticationSuccessHandler = new WebFilterChainServerAuthenticationSuccessHandler();
@@ -116,6 +120,11 @@ private Mono<Void> authenticate(ServerWebExchange exchange,
116120
.flatMap(authenticationManager -> authenticationManager.authenticate(token))
117121
.switchIfEmpty(Mono.defer(() -> Mono.error(new IllegalStateException("No provider found for " + token.getClass()))))
118122
.flatMap(authentication -> onAuthenticationSuccess(authentication, webFilterExchange))
123+
.doOnError(AuthenticationException.class, e -> {
124+
if (logger.isDebugEnabled()) {
125+
logger.debug("Authentication failed: " + e.getMessage());
126+
}
127+
})
119128
.onErrorResume(AuthenticationException.class, e -> this.authenticationFailureHandler
120129
.onAuthenticationFailure(webFilterExchange, e));
121130
}

web/src/main/java/org/springframework/security/web/server/authentication/logout/LogoutWebFilter.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.security.web.server.authentication.logout;
1818

19+
import org.apache.commons.logging.Log;
20+
import org.apache.commons.logging.LogFactory;
1921
import reactor.core.publisher.Mono;
2022

2123
import org.springframework.http.HttpMethod;
@@ -36,9 +38,12 @@
3638
* {@link ServerLogoutHandler}.
3739
*
3840
* @author Rob Winch
41+
* @author Mathieu Ouellet
3942
* @since 5.0
4043
*/
4144
public class LogoutWebFilter implements WebFilter {
45+
private static final Log logger = LogFactory.getLog(LogoutWebFilter.class);
46+
4247
private AnonymousAuthenticationToken anonymousAuthenticationToken = new AnonymousAuthenticationToken("key", "anonymous",
4348
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
4449

@@ -69,6 +74,10 @@ private Mono<Authentication> flatMapAuthentication(ServerWebExchange exchange) {
6974
}
7075

7176
private Mono<Void> logout(WebFilterExchange webFilterExchange, Authentication authentication) {
77+
if (logger.isDebugEnabled()) {
78+
logger.debug("Logging out user '" + authentication
79+
+ "' and transferring to logout destination");
80+
}
7281
return this.logoutHandler.logout(webFilterExchange, authentication)
7382
.then(this.logoutSuccessHandler
7483
.onLogoutSuccess(webFilterExchange, authentication))

web/src/main/java/org/springframework/security/web/server/authorization/AuthorizationWebFilter.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,7 +15,9 @@
1515
*/
1616
package org.springframework.security.web.server.authorization;
1717

18-
18+
import org.apache.commons.logging.Log;
19+
import org.apache.commons.logging.LogFactory;
20+
import org.springframework.security.access.AccessDeniedException;
1921
import org.springframework.security.authorization.ReactiveAuthorizationManager;
2022
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
2123
import org.springframework.security.core.context.SecurityContext;
@@ -28,21 +30,33 @@
2830
/**
2931
*
3032
* @author Rob Winch
33+
* @author Mathieu Ouellet
3134
* @since 5.0
3235
*/
3336
public class AuthorizationWebFilter implements WebFilter {
34-
private ReactiveAuthorizationManager<? super ServerWebExchange> accessDecisionManager;
37+
private static final Log logger = LogFactory.getLog(AuthorizationWebFilter.class);
38+
private ReactiveAuthorizationManager<? super ServerWebExchange> authorizationManager;
3539

36-
public AuthorizationWebFilter(ReactiveAuthorizationManager<? super ServerWebExchange> accessDecisionManager) {
37-
this.accessDecisionManager = accessDecisionManager;
40+
public AuthorizationWebFilter(ReactiveAuthorizationManager<? super ServerWebExchange> authorizationManager) {
41+
this.authorizationManager = authorizationManager;
3842
}
3943

4044
@Override
4145
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
4246
return ReactiveSecurityContextHolder.getContext()
4347
.filter(c -> c.getAuthentication() != null)
4448
.map(SecurityContext::getAuthentication)
45-
.as(authentication -> this.accessDecisionManager.verify(authentication, exchange))
49+
.as(authentication -> this.authorizationManager.verify(authentication, exchange))
50+
.doOnSuccess(it -> {
51+
if (logger.isDebugEnabled()) {
52+
logger.debug("Authorization successful");
53+
}
54+
})
55+
.doOnError(AccessDeniedException.class, e -> {
56+
if (logger.isDebugEnabled()) {
57+
logger.debug("Authorization failed: " + e.getMessage());
58+
}
59+
})
4660
.switchIfEmpty(chain.filter(exchange));
4761
}
4862
}

web/src/main/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManager.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,11 +15,13 @@
1515
*/
1616
package org.springframework.security.web.server.authorization;
1717

18+
import org.apache.commons.logging.Log;
19+
import org.apache.commons.logging.LogFactory;
1820
import org.springframework.security.authorization.AuthorizationDecision;
1921
import org.springframework.security.authorization.ReactiveAuthorizationManager;
2022
import org.springframework.security.core.Authentication;
23+
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult;
2124
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcherEntry;
22-
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
2325
import org.springframework.web.server.ServerWebExchange;
2426

2527
import reactor.core.publisher.Flux;
@@ -30,9 +32,11 @@
3032

3133
/**
3234
* @author Rob Winch
35+
* @author Mathieu Ouellet
3336
* @since 5.0
3437
*/
3538
public class DelegatingReactiveAuthorizationManager implements ReactiveAuthorizationManager<ServerWebExchange> {
39+
private static final Log logger = LogFactory.getLog(DelegatingReactiveAuthorizationManager.class);
3640
private final List<ServerWebExchangeMatcherEntry<ReactiveAuthorizationManager<AuthorizationContext>>> mappings;
3741

3842
private DelegatingReactiveAuthorizationManager(List<ServerWebExchangeMatcherEntry<ReactiveAuthorizationManager<AuthorizationContext>>> mappings) {
@@ -43,11 +47,17 @@ private DelegatingReactiveAuthorizationManager(List<ServerWebExchangeMatcherEntr
4347
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, ServerWebExchange exchange) {
4448
return Flux.fromIterable(mappings)
4549
.concatMap(mapping -> mapping.getMatcher().matches(exchange)
46-
.filter(ServerWebExchangeMatcher.MatchResult::isMatch)
47-
.map(r -> r.getVariables())
48-
.flatMap(variables -> mapping.getEntry()
49-
.check(authentication, new AuthorizationContext(exchange, variables))
50-
)
50+
.filter(MatchResult::isMatch)
51+
.map(MatchResult::getVariables)
52+
.flatMap(variables -> {
53+
if (logger.isDebugEnabled()) {
54+
logger.debug("Checking authorization on '"
55+
+ exchange.getRequest().getPath().pathWithinApplication()
56+
+ "' using " + mapping.getEntry());
57+
}
58+
return mapping.getEntry()
59+
.check(authentication, new AuthorizationContext(exchange, variables));
60+
})
5161
)
5262
.next()
5363
.defaultIfEmpty(new AuthorizationDecision(false));

0 commit comments

Comments
 (0)