Commit faa9910e authored by Stephane Nicoll's avatar Stephane Nicoll

Enable cache when a SecurityContext parameter is used

This commit restores caching for the main read operation when the
SecurityContext does not expose a principal (i.e. guest access).

Closes gh-13238
parent 1ce22aa5
...@@ -19,8 +19,10 @@ package org.springframework.boot.actuate.endpoint.invoker.cache; ...@@ -19,8 +19,10 @@ package org.springframework.boot.actuate.endpoint.invoker.cache;
import java.util.function.Function; import java.util.function.Function;
import org.springframework.boot.actuate.endpoint.OperationType; 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.OperationInvoker;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor; import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;
import org.springframework.boot.actuate.endpoint.invoke.OperationParameter;
import org.springframework.boot.actuate.endpoint.invoke.OperationParameters; import org.springframework.boot.actuate.endpoint.invoke.OperationParameters;
/** /**
...@@ -40,7 +42,7 @@ public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor { ...@@ -40,7 +42,7 @@ public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor {
@Override @Override
public OperationInvoker apply(String endpointId, OperationType operationType, public OperationInvoker apply(String endpointId, OperationType operationType,
OperationParameters parameters, OperationInvoker invoker) { OperationParameters parameters, OperationInvoker invoker) {
if (operationType == OperationType.READ && !parameters.hasMandatoryParameter()) { if (operationType == OperationType.READ && !hasMandatoryParameter(parameters)) {
Long timeToLive = this.endpointIdTimeToLive.apply(endpointId); Long timeToLive = this.endpointIdTimeToLive.apply(endpointId);
if (timeToLive != null && timeToLive > 0) { if (timeToLive != null && timeToLive > 0) {
return new CachingOperationInvoker(invoker, timeToLive); return new CachingOperationInvoker(invoker, timeToLive);
...@@ -49,4 +51,14 @@ public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor { ...@@ -49,4 +51,14 @@ public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor {
return invoker; return invoker;
} }
private boolean hasMandatoryParameter(OperationParameters parameters) {
for (OperationParameter parameter : parameters) {
if (parameter.isMandatory()
&& !SecurityContext.class.isAssignableFrom(parameter.getType())) {
return true;
}
}
return false;
}
} }
...@@ -25,6 +25,7 @@ import org.mockito.Mock; ...@@ -25,6 +25,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.springframework.boot.actuate.endpoint.OperationType; 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.OperationInvoker;
import org.springframework.boot.actuate.endpoint.invoke.OperationParameters; import org.springframework.boot.actuate.endpoint.invoke.OperationParameters;
import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod; import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;
...@@ -111,6 +112,14 @@ public class CachingOperationInvokerAdvisorTests { ...@@ -111,6 +112,14 @@ public class CachingOperationInvokerAdvisorTests {
assertAdviseIsApplied(parameters); 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) { private void assertAdviseIsApplied(OperationParameters parameters) {
OperationInvoker advised = this.advisor.apply("foo", OperationType.READ, OperationInvoker advised = this.advisor.apply("foo", OperationType.READ,
parameters, this.invoker); parameters, this.invoker);
...@@ -147,6 +156,11 @@ public class CachingOperationInvokerAdvisorTests { ...@@ -147,6 +156,11 @@ public class CachingOperationInvokerAdvisorTests {
return ""; return "";
} }
public String getWithSecurityContext(SecurityContext securityContext,
@Nullable String bar) {
return "";
}
} }
} }
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package org.springframework.boot.actuate.endpoint.invoker.cache; package org.springframework.boot.actuate.endpoint.invoker.cache;
import java.security.Principal;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -96,6 +97,21 @@ public class CachingOperationInvokerTests { ...@@ -96,6 +97,21 @@ public class CachingOperationInvokerTests {
verify(target, times(3)).invoke(context); verify(target, times(3)).invoke(context);
} }
@Test
public void targetAlwaysInvokedWithPrincipal() {
OperationInvoker target = mock(OperationInvoker.class);
Map<String, Object> 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 @Test
public void targetInvokedWhenCacheExpires() throws InterruptedException { public void targetInvokedWhenCacheExpires() throws InterruptedException {
OperationInvoker target = mock(OperationInvoker.class); OperationInvoker target = mock(OperationInvoker.class);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment