Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.springframework.security.authorization.method;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
Expand All @@ -32,6 +33,7 @@
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;

/**
* An {@link AuthorizationManager} which can determine if an {@link Authentication} may
Expand All @@ -43,10 +45,23 @@
*/
public final class SecuredAuthorizationManager implements AuthorizationManager<MethodInvocation> {

private final AuthoritiesAuthorizationManager delegate = new AuthoritiesAuthorizationManager();
private AuthorizationManager<Collection<String>> authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();

private final Map<MethodClassKey, Set<String>> cachedAuthorities = new ConcurrentHashMap<>();

/**
* Sets an {@link AuthorizationManager} that accepts a collection of authority
* strings.
* @param authoritiesAuthorizationManager the {@link AuthorizationManager} that
* accepts a collection of authority strings to use
* @since 6.1
*/
public void setAuthoritiesAuthorizationManager(
AuthorizationManager<Collection<String>> authoritiesAuthorizationManager) {
Assert.notNull(authoritiesAuthorizationManager, "authoritiesAuthorizationManager cannot be null");
this.authoritiesAuthorizationManager = authoritiesAuthorizationManager;
}

/**
* Determine if an {@link Authentication} has access to a method by evaluating the
* {@link Secured} annotation that {@link MethodInvocation} specifies.
Expand All @@ -58,7 +73,7 @@ public final class SecuredAuthorizationManager implements AuthorizationManager<M
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
Set<String> authorities = getAuthorities(mi);
return authorities.isEmpty() ? null : this.delegate.check(authentication, authorities);
return authorities.isEmpty() ? null : this.authoritiesAuthorizationManager.check(authentication, authorities);
}

private Set<String> getAuthorities(MethodInvocation methodInvocation) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,6 +18,8 @@

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
import java.util.Set;
import java.util.function.Supplier;

import org.junit.jupiter.api.Test;
Expand All @@ -29,10 +31,14 @@
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

/**
* Tests for {@link SecuredAuthorizationManager}.
Expand All @@ -41,6 +47,26 @@
*/
public class SecuredAuthorizationManagerTests {

@Test
public void setAuthoritiesAuthorizationManagerWhenNullThenException() {
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
assertThatIllegalArgumentException().isThrownBy(() -> manager.setAuthoritiesAuthorizationManager(null))
.withMessage("authoritiesAuthorizationManager cannot be null");
}

@Test
public void setAuthoritiesAuthorizationManagerWhenNotNullThenVerifyUsage() throws Exception {
AuthorizationManager<Collection<String>> authoritiesAuthorizationManager = mock(AuthorizationManager.class);
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
manager.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"securedUserOrAdmin");
Supplier<Authentication> authentication = TestAuthentication::authenticatedUser;
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
assertThat(decision).isNull();
verify(authoritiesAuthorizationManager).check(authentication, Set.of("ROLE_USER", "ROLE_ADMIN"));
}

@Test
public void checkDoSomethingWhenNoSecuredAnnotationThenNullDecision() throws Exception {
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
Expand Down