parent
c3d28a72a2
commit
7b2cb59dab
|
@ -22,8 +22,12 @@ 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 org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.context.MessageSourceAware;
|
||||||
|
import org.springframework.context.support.MessageSourceAccessor;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +36,7 @@ import org.springframework.util.Assert;
|
||||||
* @author Josh Cummings
|
* @author Josh Cummings
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
public final class ObservationAuthorizationManager<T> implements AuthorizationManager<T> {
|
public final class ObservationAuthorizationManager<T> implements AuthorizationManager<T>, MessageSourceAware {
|
||||||
|
|
||||||
private final ObservationRegistry registry;
|
private final ObservationRegistry registry;
|
||||||
|
|
||||||
|
@ -40,6 +44,8 @@ public final class ObservationAuthorizationManager<T> implements AuthorizationMa
|
||||||
|
|
||||||
private ObservationConvention<AuthorizationObservationContext<?>> convention = new AuthorizationObservationConvention();
|
private ObservationConvention<AuthorizationObservationContext<?>> convention = new AuthorizationObservationConvention();
|
||||||
|
|
||||||
|
private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||||
|
|
||||||
public ObservationAuthorizationManager(ObservationRegistry registry, AuthorizationManager<T> delegate) {
|
public ObservationAuthorizationManager(ObservationRegistry registry, AuthorizationManager<T> delegate) {
|
||||||
this.registry = registry;
|
this.registry = registry;
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
|
@ -57,7 +63,8 @@ public final class ObservationAuthorizationManager<T> implements AuthorizationMa
|
||||||
AuthorizationDecision decision = this.delegate.check(wrapped, object);
|
AuthorizationDecision decision = this.delegate.check(wrapped, object);
|
||||||
context.setDecision(decision);
|
context.setDecision(decision);
|
||||||
if (decision != null && !decision.isGranted()) {
|
if (decision != null && !decision.isGranted()) {
|
||||||
observation.error(new AccessDeniedException("Access Denied"));
|
observation.error(new AccessDeniedException(
|
||||||
|
this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access Denied")));
|
||||||
}
|
}
|
||||||
return decision;
|
return decision;
|
||||||
}
|
}
|
||||||
|
@ -81,4 +88,14 @@ public final class ObservationAuthorizationManager<T> implements AuthorizationMa
|
||||||
this.convention = convention;
|
this.convention = convention;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the MessageSource that this object runs in.
|
||||||
|
* @param messageSource The message source to be used by this object
|
||||||
|
* @since 6.2
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setMessageSource(final MessageSource messageSource) {
|
||||||
|
this.messages = new MessageSourceAccessor(messageSource);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.security.authorization;
|
package org.springframework.security.authorization;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.micrometer.observation.Observation;
|
import io.micrometer.observation.Observation;
|
||||||
|
@ -25,6 +26,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
@ -32,6 +34,7 @@ import org.springframework.security.core.Authentication;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
@ -85,14 +88,20 @@ public class ObservationAuthorizationManagerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void verifyWhenErrorsThenObserves() {
|
void verifyWhenErrorsThenObserves() {
|
||||||
|
MessageSource source = mock(MessageSource.class);
|
||||||
|
this.tested.setMessageSource(source);
|
||||||
given(this.handler.supportsContext(any())).willReturn(true);
|
given(this.handler.supportsContext(any())).willReturn(true);
|
||||||
given(this.authorizationManager.check(any(), any())).willReturn(this.deny);
|
given(this.authorizationManager.check(any(), any())).willReturn(this.deny);
|
||||||
|
given(source.getMessage(eq("AbstractAccessDecisionManager.accessDenied"), any(), any(), any()))
|
||||||
|
.willReturn("accessDenied");
|
||||||
assertThatExceptionOfType(AccessDeniedException.class)
|
assertThatExceptionOfType(AccessDeniedException.class)
|
||||||
.isThrownBy(() -> this.tested.verify(this.token, this.object));
|
.isThrownBy(() -> this.tested.verify(this.token, this.object));
|
||||||
ArgumentCaptor<Observation.Context> captor = ArgumentCaptor.forClass(Observation.Context.class);
|
ArgumentCaptor<Observation.Context> captor = ArgumentCaptor.forClass(Observation.Context.class);
|
||||||
verify(this.handler).onStart(captor.capture());
|
verify(this.handler).onStart(captor.capture());
|
||||||
assertThat(captor.getValue().getName()).isEqualTo(AuthorizationObservationConvention.OBSERVATION_NAME);
|
assertThat(captor.getValue().getName()).isEqualTo(AuthorizationObservationConvention.OBSERVATION_NAME);
|
||||||
assertThat(captor.getValue().getError()).isInstanceOf(AccessDeniedException.class);
|
assertThat(captor.getValue().getError()).isInstanceOf(AccessDeniedException.class);
|
||||||
|
assertThat(Optional.ofNullable(captor.getValue().getError()).map(Throwable::getMessage).orElse(""))
|
||||||
|
.isEqualTo("accessDenied");
|
||||||
assertThat(captor.getValue()).isInstanceOf(AuthorizationObservationContext.class);
|
assertThat(captor.getValue()).isInstanceOf(AuthorizationObservationContext.class);
|
||||||
AuthorizationObservationContext<?> context = (AuthorizationObservationContext<?>) captor.getValue();
|
AuthorizationObservationContext<?> context = (AuthorizationObservationContext<?>) captor.getValue();
|
||||||
assertThat(context.getAuthentication()).isNull();
|
assertThat(context.getAuthentication()).isNull();
|
||||||
|
|
Loading…
Reference in New Issue