Lookup Parent Observation

Closes gh-12524
This commit is contained in:
Josh Cummings 2023-01-11 10:13:33 -07:00
parent 21ceb333a8
commit 4d2dab9b6b
No known key found for this signature in database
GPG Key ID: A306A51F43B8E5A5
3 changed files with 44 additions and 28 deletions

View File

@ -18,6 +18,7 @@ package org.springframework.security.authentication;
import io.micrometer.observation.Observation; import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@ -48,13 +49,16 @@ public class ObservationReactiveAuthenticationManager implements ReactiveAuthent
AuthenticationObservationContext context = new AuthenticationObservationContext(); AuthenticationObservationContext context = new AuthenticationObservationContext();
context.setAuthenticationRequest(authentication); context.setAuthenticationRequest(authentication);
context.setAuthenticationManagerClass(this.delegate.getClass()); context.setAuthenticationManagerClass(this.delegate.getClass());
Observation observation = Observation.createNotStarted(this.convention, () -> context, this.registry).start(); return Mono.deferContextual((contextView) -> {
return this.delegate.authenticate(authentication).doOnSuccess((result) -> { Observation observation = Observation.createNotStarted(this.convention, () -> context, this.registry)
context.setAuthenticationResult(result); .parentObservation(contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null)).start();
observation.stop(); return this.delegate.authenticate(authentication).doOnSuccess((result) -> {
}).doOnCancel(observation::stop).doOnError((t) -> { context.setAuthenticationResult(result);
observation.error(t); observation.stop();
observation.stop(); }).doOnCancel(observation::stop).doOnError((t) -> {
observation.error(t);
observation.stop();
});
}); });
} }

View File

@ -18,6 +18,7 @@ package org.springframework.security.authorization;
import io.micrometer.observation.Observation; import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.AccessDeniedException;
@ -50,16 +51,19 @@ public final class ObservationReactiveAuthorizationManager<T> implements Reactiv
context.setAuthentication(auth); context.setAuthentication(auth);
return context.getAuthentication(); return context.getAuthentication();
}); });
Observation observation = Observation.createNotStarted(this.convention, () -> context, this.registry).start(); return Mono.deferContextual((contextView) -> {
return this.delegate.check(wrapped, object).doOnSuccess((decision) -> { Observation observation = Observation.createNotStarted(this.convention, () -> context, this.registry)
context.setDecision(decision); .parentObservation(contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null)).start();
if (decision == null || !decision.isGranted()) { return this.delegate.check(wrapped, object).doOnSuccess((decision) -> {
observation.error(new AccessDeniedException("Access Denied")); context.setDecision(decision);
} if (decision == null || !decision.isGranted()) {
observation.stop(); observation.error(new AccessDeniedException("Access Denied"));
}).doOnCancel(observation::stop).doOnError((t) -> { }
observation.error(t); observation.stop();
observation.stop(); }).doOnCancel(observation::stop).doOnError((t) -> {
observation.error(t);
observation.stop();
});
}); });
} }

View File

@ -27,6 +27,7 @@ import io.micrometer.common.KeyValues;
import io.micrometer.observation.Observation; import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationConvention; import io.micrometer.observation.ObservationConvention;
import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -73,20 +74,22 @@ public final class ObservationWebFilterChainDecorator implements WebFilterChainP
} }
private WebFilterChain wrapSecured(WebFilterChain original) { private WebFilterChain wrapSecured(WebFilterChain original) {
return (exchange) -> { return (exchange) -> Mono.deferContextual((contextView) -> {
AroundWebFilterObservation parent = observation(exchange); AroundWebFilterObservation parent = observation(exchange);
Observation parentObservation = contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null);
Observation observation = Observation.createNotStarted(SECURED_OBSERVATION_NAME, this.registry) Observation observation = Observation.createNotStarted(SECURED_OBSERVATION_NAME, this.registry)
.contextualName("secured request"); .contextualName("secured request").parentObservation(parentObservation);
return parent.wrap(WebFilterObservation.create(observation).wrap(original)).filter(exchange); return parent.wrap(WebFilterObservation.create(observation).wrap(original)).filter(exchange);
}; });
} }
private WebFilterChain wrapUnsecured(WebFilterChain original) { private WebFilterChain wrapUnsecured(WebFilterChain original) {
return (exchange) -> { return (exchange) -> Mono.deferContextual((contextView) -> {
Observation parentObservation = contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null);
Observation observation = Observation.createNotStarted(UNSECURED_OBSERVATION_NAME, this.registry) Observation observation = Observation.createNotStarted(UNSECURED_OBSERVATION_NAME, this.registry)
.contextualName("unsecured request"); .contextualName("unsecured request").parentObservation(parentObservation);
return WebFilterObservation.create(observation).wrap(original).filter(exchange); return WebFilterObservation.create(observation).wrap(original).filter(exchange);
}; });
} }
private List<ObservationWebFilter> wrap(List<WebFilter> filters) { private List<ObservationWebFilter> wrap(List<WebFilter> filters) {
@ -186,8 +189,11 @@ public final class ObservationWebFilterChainDecorator implements WebFilterChainP
@Override @Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
if (this.position == 1) { if (this.position == 1) {
AroundWebFilterObservation parent = parent(exchange); return Mono.deferContextual((contextView) -> {
return parent.wrap(this::wrapFilter).filter(exchange, chain); Observation parentObservation = contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null);
AroundWebFilterObservation parent = parent(exchange, parentObservation);
return parent.wrap(this::wrapFilter).filter(exchange, chain);
});
} }
else { else {
return wrapFilter(exchange, chain); return wrapFilter(exchange, chain);
@ -211,11 +217,13 @@ public final class ObservationWebFilterChainDecorator implements WebFilterChainP
}); });
} }
private AroundWebFilterObservation parent(ServerWebExchange exchange) { private AroundWebFilterObservation parent(ServerWebExchange exchange, Observation parentObservation) {
WebFilterChainObservationContext beforeContext = WebFilterChainObservationContext.before(); WebFilterChainObservationContext beforeContext = WebFilterChainObservationContext.before();
WebFilterChainObservationContext afterContext = WebFilterChainObservationContext.after(); WebFilterChainObservationContext afterContext = WebFilterChainObservationContext.after();
Observation before = Observation.createNotStarted(this.convention, () -> beforeContext, this.registry); Observation before = Observation.createNotStarted(this.convention, () -> beforeContext, this.registry)
Observation after = Observation.createNotStarted(this.convention, () -> afterContext, this.registry); .parentObservation(parentObservation);
Observation after = Observation.createNotStarted(this.convention, () -> afterContext, this.registry)
.parentObservation(parentObservation);
AroundWebFilterObservation parent = AroundWebFilterObservation.create(before, after); AroundWebFilterObservation parent = AroundWebFilterObservation.create(before, after);
exchange.getAttributes().put(ATTRIBUTE, parent); exchange.getAttributes().put(ATTRIBUTE, parent);
return parent; return parent;