Skip to content

Commit 857ca9c

Browse files
committed
Merge remote-tracking branch 'origin/6.4.x' into 6.5.x
2 parents 8a1e2a2 + 894105a commit 857ca9c

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

web/src/main/java/org/springframework/security/web/ObservationFilterChainDecorator.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,14 @@
4646
* wraps the chain in before and after observations
4747
*
4848
* @author Josh Cummings
49+
* @author Nikita Konev
4950
* @since 6.0
5051
*/
5152
public final class ObservationFilterChainDecorator implements FilterChainProxy.FilterChainDecorator {
5253

5354
private static final Log logger = LogFactory.getLog(FilterChainProxy.class);
5455

55-
private static final String ATTRIBUTE = ObservationFilterChainDecorator.class + ".observation";
56+
static final String ATTRIBUTE = ObservationFilterChainDecorator.class + ".observation";
5657

5758
static final String UNSECURED_OBSERVATION_NAME = "spring.security.http.unsecured.requests";
5859

@@ -250,6 +251,16 @@ private void wrapFilter(ServletRequest request, ServletResponse response, Filter
250251
private AroundFilterObservation parent(HttpServletRequest request) {
251252
FilterChainObservationContext beforeContext = FilterChainObservationContext.before();
252253
FilterChainObservationContext afterContext = FilterChainObservationContext.after();
254+
255+
AroundFilterObservation existingParentObservation = (AroundFilterObservation) request
256+
.getAttribute(ATTRIBUTE);
257+
if (existingParentObservation != null) {
258+
beforeContext
259+
.setParentObservation(existingParentObservation.before().getContext().getParentObservation());
260+
afterContext
261+
.setParentObservation(existingParentObservation.after().getContext().getParentObservation());
262+
}
263+
253264
Observation before = Observation.createNotStarted(this.convention, () -> beforeContext, this.registry);
254265
Observation after = Observation.createNotStarted(this.convention, () -> afterContext, this.registry);
255266
AroundFilterObservation parent = AroundFilterObservation.create(before, after);

web/src/test/java/org/springframework/security/web/FilterChainProxyTests.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,65 @@ public void doFilterWhenMatchesThenObservationRegistryObserves() throws Exceptio
314314
assertFilterChainObservation(contexts.next(), "after", 1);
315315
}
316316

317+
// gh-12610
318+
@Test
319+
void parentObservationIsTakenIntoAccountDuringDispatchError() throws Exception {
320+
ObservationHandler<Observation.Context> handler = mock(ObservationHandler.class);
321+
given(handler.supportsContext(any())).willReturn(true);
322+
ObservationRegistry registry = ObservationRegistry.create();
323+
registry.observationConfig().observationHandler(handler);
324+
325+
given(this.matcher.matches(any())).willReturn(true);
326+
SecurityFilterChain sec = new DefaultSecurityFilterChain(this.matcher, Arrays.asList(this.filter));
327+
FilterChainProxy fcp = new FilterChainProxy(sec);
328+
fcp.setFilterChainDecorator(new ObservationFilterChainDecorator(registry));
329+
Filter initialFilter = ObservationFilterChainDecorator.FilterObservation
330+
.create(Observation.createNotStarted("wrap", registry))
331+
.wrap(fcp);
332+
333+
ServletRequest initialRequest = new MockHttpServletRequest("GET", "/");
334+
initialFilter.doFilter(initialRequest, new MockHttpServletResponse(), this.chain);
335+
336+
// simulate request attribute copying in case dispatching to ERROR
337+
ObservationFilterChainDecorator.AroundFilterObservation parentObservation = (ObservationFilterChainDecorator.AroundFilterObservation) initialRequest
338+
.getAttribute(ObservationFilterChainDecorator.ATTRIBUTE);
339+
assertThat(parentObservation).isNotNull();
340+
341+
// simulate dispatching error-related request
342+
Filter errorRelatedFilter = ObservationFilterChainDecorator.FilterObservation
343+
.create(Observation.createNotStarted("wrap", registry))
344+
.wrap(fcp);
345+
ServletRequest errorRelatedRequest = new MockHttpServletRequest("GET", "/error");
346+
errorRelatedRequest.setAttribute(ObservationFilterChainDecorator.ATTRIBUTE, parentObservation);
347+
errorRelatedFilter.doFilter(errorRelatedRequest, new MockHttpServletResponse(), this.chain);
348+
349+
ArgumentCaptor<Observation.Context> captor = ArgumentCaptor.forClass(Observation.Context.class);
350+
verify(handler, times(8)).onStart(captor.capture());
351+
verify(handler, times(8)).onStop(any());
352+
List<Observation.Context> contexts = captor.getAllValues();
353+
354+
Observation.Context initialRequestObservationContextBefore = contexts.get(1);
355+
Observation.Context initialRequestObservationContextAfter = contexts.get(3);
356+
assertFilterChainObservation(initialRequestObservationContextBefore, "before", 1);
357+
assertFilterChainObservation(initialRequestObservationContextAfter, "after", 1);
358+
359+
assertThat(initialRequestObservationContextBefore.getParentObservation()).isNotNull();
360+
assertThat(initialRequestObservationContextBefore.getParentObservation())
361+
.isSameAs(initialRequestObservationContextAfter.getParentObservation());
362+
363+
Observation.Context errorRelatedRequestObservationContextBefore = contexts.get(5);
364+
Observation.Context errorRelatedRequestObservationContextAfter = contexts.get(7);
365+
assertFilterChainObservation(errorRelatedRequestObservationContextBefore, "before", 1);
366+
assertFilterChainObservation(errorRelatedRequestObservationContextAfter, "after", 1);
367+
368+
assertThat(errorRelatedRequestObservationContextBefore.getParentObservation()).isNotNull();
369+
assertThat(errorRelatedRequestObservationContextBefore.getParentObservation())
370+
.isSameAs(initialRequestObservationContextBefore.getParentObservation());
371+
assertThat(errorRelatedRequestObservationContextAfter.getParentObservation()).isNotNull();
372+
assertThat(errorRelatedRequestObservationContextAfter.getParentObservation())
373+
.isSameAs(initialRequestObservationContextBefore.getParentObservation());
374+
}
375+
317376
@Test
318377
public void doFilterWhenMultipleFiltersThenObservationRegistryObserves() throws Exception {
319378
ObservationHandler<Observation.Context> handler = mock(ObservationHandler.class);

0 commit comments

Comments
 (0)