diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisor.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisor.java index d7ef9dd14b2..a1503249b35 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisor.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisor.java @@ -19,8 +19,10 @@ package org.springframework.boot.actuate.endpoint.invoker.cache; import java.util.function.Function; import org.springframework.boot.actuate.endpoint.OperationType; +import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor; +import org.springframework.boot.actuate.endpoint.invoke.OperationParameter; import org.springframework.boot.actuate.endpoint.invoke.OperationParameters; /** @@ -40,7 +42,7 @@ public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor { @Override public OperationInvoker apply(String endpointId, OperationType operationType, OperationParameters parameters, OperationInvoker invoker) { - if (operationType == OperationType.READ && !parameters.hasMandatoryParameter()) { + if (operationType == OperationType.READ && !hasMandatoryParameter(parameters)) { Long timeToLive = this.endpointIdTimeToLive.apply(endpointId); if (timeToLive != null && timeToLive > 0) { return new CachingOperationInvoker(invoker, timeToLive); @@ -49,4 +51,14 @@ public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor { return invoker; } + private boolean hasMandatoryParameter(OperationParameters parameters) { + for (OperationParameter parameter : parameters) { + if (parameter.isMandatory() + && !SecurityContext.class.isAssignableFrom(parameter.getType())) { + return true; + } + } + return false; + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisorTests.java index 31d641b484d..921de6b7240 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisorTests.java @@ -25,6 +25,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.boot.actuate.endpoint.OperationType; +import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationParameters; import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod; @@ -111,6 +112,14 @@ public class CachingOperationInvokerAdvisorTests { assertAdviseIsApplied(parameters); } + @Test + public void applyWithSecurityContextShouldAddAdvise() { + OperationParameters parameters = getParameters("getWithSecurityContext", + SecurityContext.class, String.class); + given(this.timeToLive.apply(any())).willReturn(100L); + assertAdviseIsApplied(parameters); + } + private void assertAdviseIsApplied(OperationParameters parameters) { OperationInvoker advised = this.advisor.apply("foo", OperationType.READ, parameters, this.invoker); @@ -147,6 +156,11 @@ public class CachingOperationInvokerAdvisorTests { return ""; } + public String getWithSecurityContext(SecurityContext securityContext, + @Nullable String bar) { + return ""; + } + } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerTests.java index f1c60e8f6dc..c83ffa4b950 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.endpoint.invoker.cache; +import java.security.Principal; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -96,6 +97,21 @@ public class CachingOperationInvokerTests { verify(target, times(3)).invoke(context); } + @Test + public void targetAlwaysInvokedWithPrincipal() { + OperationInvoker target = mock(OperationInvoker.class); + Map parameters = new HashMap<>(); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()).willReturn(mock(Principal.class)); + InvocationContext context = new InvocationContext(securityContext, parameters); + given(target.invoke(context)).willReturn(new Object()); + CachingOperationInvoker invoker = new CachingOperationInvoker(target, 500L); + invoker.invoke(context); + invoker.invoke(context); + invoker.invoke(context); + verify(target, times(3)).invoke(context); + } + @Test public void targetInvokedWhenCacheExpires() throws InterruptedException { OperationInvoker target = mock(OperationInvoker.class);