Explorar o código

Add Authority String AuthorizationManager

Closes gh-12231
Evgeniy Cheban %!s(int64=2) %!d(string=hai) anos
pai
achega
855282ac3b

+ 81 - 0
core/src/main/java/org/springframework/security/authorization/AuthoritiesAuthorizationManager.java

@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002-2022 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.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.authorization;
+
+import java.util.Collection;
+import java.util.function.Supplier;
+
+import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.util.Assert;
+
+/**
+ * An {@link AuthorizationManager} that determines if the current user is authorized by
+ * evaluating if the {@link Authentication} contains any of the specified authorities.
+ *
+ * @author Evgeniy Cheban
+ * @since 6.1
+ */
+public final class AuthoritiesAuthorizationManager implements AuthorizationManager<Collection<String>> {
+
+	private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
+
+	/**
+	 * Sets the {@link RoleHierarchy} to be used. Default is {@link NullRoleHierarchy}.
+	 * Cannot be null.
+	 * @param roleHierarchy the {@link RoleHierarchy} to use
+	 */
+	public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
+		Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
+		this.roleHierarchy = roleHierarchy;
+	}
+
+	/**
+	 * Determines if the current user is authorized by evaluating if the
+	 * {@link Authentication} contains any of specified authorities.
+	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
+	 * @param authorities the collection of authority strings to check
+	 * @return an {@link AuthorityAuthorizationDecision}
+	 */
+	@Override
+	public AuthorityAuthorizationDecision check(Supplier<Authentication> authentication,
+			Collection<String> authorities) {
+		boolean granted = isGranted(authentication.get(), authorities);
+		return new AuthorityAuthorizationDecision(granted, AuthorityUtils.createAuthorityList(authorities));
+	}
+
+	private boolean isGranted(Authentication authentication, Collection<String> authorities) {
+		return authentication != null && isAuthorized(authentication, authorities);
+	}
+
+	private boolean isAuthorized(Authentication authentication, Collection<String> authorities) {
+		for (GrantedAuthority grantedAuthority : getGrantedAuthorities(authentication)) {
+			if (authorities.contains(grantedAuthority.getAuthority())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private Collection<? extends GrantedAuthority> getGrantedAuthorities(Authentication authentication) {
+		return this.roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
+	}
+
+}

+ 7 - 29
core/src/main/java/org/springframework/security/authorization/AuthorityAuthorizationManager.java

@@ -16,16 +16,14 @@
 
 package org.springframework.security.authorization;
 
-import java.util.Collection;
-import java.util.List;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Set;
 import java.util.function.Supplier;
 
 import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
 import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.util.Assert;
 
 /**
@@ -40,12 +38,12 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
 
 	private static final String ROLE_PREFIX = "ROLE_";
 
-	private final List<GrantedAuthority> authorities;
+	private final AuthoritiesAuthorizationManager delegate = new AuthoritiesAuthorizationManager();
 
-	private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
+	private final Set<String> authorities;
 
 	private AuthorityAuthorizationManager(String... authorities) {
-		this.authorities = AuthorityUtils.createAuthorityList(authorities);
+		this.authorities = new HashSet<>(Arrays.asList(authorities));
 	}
 
 	/**
@@ -55,8 +53,7 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
 	 * @since 5.8
 	 */
 	public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
-		Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
-		this.roleHierarchy = roleHierarchy;
+		this.delegate.setRoleHierarchy(roleHierarchy);
 	}
 
 	/**
@@ -139,26 +136,7 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
 	 */
 	@Override
 	public AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
-		boolean granted = isGranted(authentication.get());
-		return new AuthorityAuthorizationDecision(granted, this.authorities);
-	}
-
-	private boolean isGranted(Authentication authentication) {
-		return authentication != null && authentication.isAuthenticated() && isAuthorized(authentication);
-	}
-
-	private boolean isAuthorized(Authentication authentication) {
-		Set<String> authorities = AuthorityUtils.authorityListToSet(this.authorities);
-		for (GrantedAuthority grantedAuthority : getGrantedAuthorities(authentication)) {
-			if (authorities.contains(grantedAuthority.getAuthority())) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	private Collection<? extends GrantedAuthority> getGrantedAuthorities(Authentication authentication) {
-		return this.roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
+		return this.delegate.check(authentication, this.authorities);
 	}
 
 	@Override

+ 16 - 1
core/src/main/java/org/springframework/security/core/authority/AuthorityUtils.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2022 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.
@@ -33,6 +33,7 @@ import org.springframework.util.StringUtils;
  * Mainly intended for internal use.
  *
  * @author Luke Taylor
+ * @author Evgeniy Cheban
  */
 public final class AuthorityUtils {
 
@@ -78,4 +79,18 @@ public final class AuthorityUtils {
 		return grantedAuthorities;
 	}
 
+	/**
+	 * Converts authorities into a List of GrantedAuthority objects.
+	 * @param authorities the authorities to convert
+	 * @return a List of GrantedAuthority objects
+	 * @since 6.1
+	 */
+	public static List<GrantedAuthority> createAuthorityList(Collection<String> authorities) {
+		List<GrantedAuthority> grantedAuthorities = new ArrayList<>(authorities.size());
+		for (String authority : authorities) {
+			grantedAuthorities.add(new SimpleGrantedAuthority(authority));
+		}
+		return grantedAuthorities;
+	}
+
 }

+ 87 - 0
core/src/test/java/org/springframework/security/authorization/AuthoritiesAuthorizationManagerTests.java

@@ -0,0 +1,87 @@
+/*
+ * Copyright 2002-2022 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.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.authorization;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.function.Supplier;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
+import org.springframework.security.authentication.TestingAuthenticationToken;
+import org.springframework.security.core.Authentication;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+
+/**
+ * Tests for {@link AuthoritiesAuthorizationManager}.
+ *
+ * @author Evgeniy Cheban
+ */
+class AuthoritiesAuthorizationManagerTests {
+
+	@Test
+	void setRoleHierarchyWhenNullThenIllegalArgumentException() {
+		AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
+		assertThatIllegalArgumentException().isThrownBy(() -> manager.setRoleHierarchy(null))
+				.withMessage("roleHierarchy cannot be null");
+	}
+
+	@Test
+	void setRoleHierarchyWhenNotNullThenVerifyRoleHierarchy() {
+		AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
+		RoleHierarchy roleHierarchy = new RoleHierarchyImpl();
+		manager.setRoleHierarchy(roleHierarchy);
+		assertThat(manager).extracting("roleHierarchy").isEqualTo(roleHierarchy);
+	}
+
+	@Test
+	void getRoleHierarchyWhenNotSetThenDefaultsToNullRoleHierarchy() {
+		AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
+		assertThat(manager).extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class);
+	}
+
+	@Test
+	void checkWhenUserHasAnyAuthorityThenGrantedDecision() {
+		AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
+		Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "USER");
+		assertThat(manager.check(authentication, Arrays.asList("ADMIN", "USER")).isGranted()).isTrue();
+	}
+
+	@Test
+	void checkWhenUserHasNotAnyAuthorityThenDeniedDecision() {
+		AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
+		Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ANONYMOUS");
+		assertThat(manager.check(authentication, Arrays.asList("ADMIN", "USER")).isGranted()).isFalse();
+	}
+
+	@Test
+	void hasRoleWhenRoleHierarchySetThenGreaterRoleTakesPrecedence() {
+		AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
+		RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
+		roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
+		manager.setRoleHierarchy(roleHierarchy);
+		Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
+				"ROLE_ADMIN");
+		assertThat(manager.check(authentication, Collections.singleton("ROLE_ADMIN")).isGranted()).isTrue();
+	}
+
+}

+ 2 - 2
core/src/test/java/org/springframework/security/authorization/AuthorityAuthorizationManagerTests.java

@@ -226,13 +226,13 @@ public class AuthorityAuthorizationManagerTests {
 		AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasRole("USER");
 		RoleHierarchy roleHierarchy = new RoleHierarchyImpl();
 		manager.setRoleHierarchy(roleHierarchy);
-		assertThat(manager).extracting("roleHierarchy").isEqualTo(roleHierarchy);
+		assertThat(manager).extracting("delegate").extracting("roleHierarchy").isEqualTo(roleHierarchy);
 	}
 
 	@Test
 	public void getRoleHierarchyWhenNotSetThenDefaultsToNullRoleHierarchy() {
 		AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasRole("USER");
-		assertThat(manager).extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class);
+		assertThat(manager).extracting("delegate").extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class);
 	}
 
 	@Test

+ 13 - 1
core/src/test/java/org/springframework/security/core/authority/AuthorityUtilsTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2022 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.
@@ -16,6 +16,7 @@
 
 package org.springframework.security.core.authority;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
 
@@ -27,6 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 /**
  * @author Luke Taylor
+ * @author Evgeniy Cheban
  */
 public class AuthorityUtilsTests {
 
@@ -42,4 +44,14 @@ public class AuthorityUtilsTests {
 		assertThat(authorities.contains("ROLE_D")).isTrue();
 	}
 
+	@Test
+	public void createAuthorityList() {
+		List<GrantedAuthority> authorities = AuthorityUtils
+				.createAuthorityList(Arrays.asList("ROLE_A", "ROLE_B", "ROLE_C"));
+		assertThat(authorities).hasSize(3);
+		assertThat(authorities).element(0).extracting(GrantedAuthority::getAuthority).isEqualTo("ROLE_A");
+		assertThat(authorities).element(1).extracting(GrantedAuthority::getAuthority).isEqualTo("ROLE_B");
+		assertThat(authorities).element(2).extracting(GrantedAuthority::getAuthority).isEqualTo("ROLE_C");
+	}
+
 }