Add hasAnyAuthority() and hasAnyRole() in AuthorizeExchangeSpec

Fixes gh-6306
This commit is contained in:
Robbie Martinus 2018-12-19 22:36:30 +11:00 committed by Rob Winch
parent a919b4e916
commit e60ae4984a
3 changed files with 114 additions and 7 deletions

View File

@ -1563,6 +1563,15 @@ public class ServerHttpSecurity {
return access(AuthorityReactiveAuthorizationManager.hasRole(role)); return access(AuthorityReactiveAuthorizationManager.hasRole(role));
} }
/**
* Require any specific role. This is a shortcut for {@link #hasAnyAuthority(String...)}
* @param roles the roles (i.e. "USER" would require "ROLE_USER")
* @return the {@link AuthorizeExchangeSpec} to configure
*/
public AuthorizeExchangeSpec hasAnyRole(String... roles) {
return access(AuthorityReactiveAuthorizationManager.hasAnyRole(roles));
}
/** /**
* Require a specific authority. * Require a specific authority.
* @param authority the authority to require (i.e. "USER" woudl require authority of "USER"). * @param authority the authority to require (i.e. "USER" woudl require authority of "USER").
@ -1572,6 +1581,15 @@ public class ServerHttpSecurity {
return access(AuthorityReactiveAuthorizationManager.hasAuthority(authority)); return access(AuthorityReactiveAuthorizationManager.hasAuthority(authority));
} }
/**
* Require any authority
* @param authorities the authorities to require (i.e. "USER" would require authority of "USER").
* @return the {@link AuthorizeExchangeSpec} to configure
*/
public AuthorizeExchangeSpec hasAnyAuthority(String... authorities) {
return access(AuthorityReactiveAuthorizationManager.hasAnyAuthority(authorities));
}
/** /**
* Require an authenticated user * Require an authenticated user
* @return the {@link AuthorizeExchangeSpec} to configure * @return the {@link AuthorizeExchangeSpec} to configure

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,6 +20,10 @@ import org.springframework.security.core.Authentication;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/** /**
* A {@link ReactiveAuthorizationManager} that determines if the current user is * A {@link ReactiveAuthorizationManager} that determines if the current user is
* authorized by evaluating if the {@link Authentication} contains a specified authority. * authorized by evaluating if the {@link Authentication} contains a specified authority.
@ -29,10 +33,10 @@ import reactor.core.publisher.Mono;
* @param <T> the type of object being authorized * @param <T> the type of object being authorized
*/ */
public class AuthorityReactiveAuthorizationManager<T> implements ReactiveAuthorizationManager<T> { public class AuthorityReactiveAuthorizationManager<T> implements ReactiveAuthorizationManager<T> {
private final String authority; private final List<String> authorities;
private AuthorityReactiveAuthorizationManager(String authority) { private AuthorityReactiveAuthorizationManager(String... authorities) {
this.authority = authority; this.authorities = Arrays.asList(authorities);
} }
@Override @Override
@ -40,8 +44,8 @@ public class AuthorityReactiveAuthorizationManager<T> implements ReactiveAuthori
return authentication return authentication
.filter(a -> a.isAuthenticated()) .filter(a -> a.isAuthenticated())
.flatMapIterable( a -> a.getAuthorities()) .flatMapIterable( a -> a.getAuthorities())
.map( g-> g.getAuthority()) .map(g -> g.getAuthority())
.hasElement(this.authority) .any(a -> this.authorities.contains(a))
.map( hasAuthority -> new AuthorizationDecision(hasAuthority)) .map( hasAuthority -> new AuthorizationDecision(hasAuthority))
.defaultIfEmpty(new AuthorizationDecision(false)); .defaultIfEmpty(new AuthorizationDecision(false));
} }
@ -59,6 +63,24 @@ public class AuthorityReactiveAuthorizationManager<T> implements ReactiveAuthori
return new AuthorityReactiveAuthorizationManager<>(authority); return new AuthorityReactiveAuthorizationManager<>(authority);
} }
/**
* Creates an instance of {@link AuthorityReactiveAuthorizationManager} with the
* provided authorities.
*
* @author Robbie Martinus
* @param authorities the authorities to check for
* @param <T> the type of object being authorized
* @return the new instance
*/
public static <T> AuthorityReactiveAuthorizationManager<T> hasAnyAuthority(String... authorities) {
Assert.notNull(authorities, "authorities cannot be null");
for (String authority : authorities) {
Assert.notNull(authority, "authority cannot be null");
}
return new AuthorityReactiveAuthorizationManager<>(authorities);
}
/** /**
* Creates an instance of {@link AuthorityReactiveAuthorizationManager} with the * Creates an instance of {@link AuthorityReactiveAuthorizationManager} with the
* provided authority. * provided authority.
@ -71,4 +93,25 @@ public class AuthorityReactiveAuthorizationManager<T> implements ReactiveAuthori
Assert.notNull(role, "role cannot be null"); Assert.notNull(role, "role cannot be null");
return hasAuthority("ROLE_" + role); return hasAuthority("ROLE_" + role);
} }
/**
* Creates an instance of {@link AuthorityReactiveAuthorizationManager} with the
* provided authorities.
*
* @author Robbie Martinus
* @param roles the authorities to check for prefixed with "ROLE_"
* @param <T> the type of object being authorized
* @return the new instance
*/
public static <T> AuthorityReactiveAuthorizationManager<T> hasAnyRole(String... roles) {
Assert.notNull(roles, "roles cannot be null");
for (String role : roles) {
Assert.notNull(role, "role cannot be null");
}
return hasAnyAuthority(Stream.of(roles)
.map(r -> "ROLE_" + r)
.toArray(String[]::new)
);
}
} }

View File

@ -105,7 +105,7 @@ public class AuthorityReactiveAuthorizationManagerTests {
} }
@Test @Test
public void checkWhenHasRoleAndNotAuthorizedThenReturnTrue() { public void checkWhenHasRoleAndNotAuthorizedThenReturnFalse() {
manager = AuthorityReactiveAuthorizationManager.hasRole("ADMIN"); manager = AuthorityReactiveAuthorizationManager.hasRole("ADMIN");
authentication = new TestingAuthenticationToken("rob", "secret", "ADMIN"); authentication = new TestingAuthenticationToken("rob", "secret", "ADMIN");
@ -114,6 +114,26 @@ public class AuthorityReactiveAuthorizationManagerTests {
assertThat(granted).isFalse(); assertThat(granted).isFalse();
} }
@Test
public void checkWhenHasAnyRoleAndAuthorizedThenReturnTrue() {
manager = AuthorityReactiveAuthorizationManager.hasAnyRole("GENERAL", "USER", "TEST");
authentication = new TestingAuthenticationToken("rob", "secret", "ROLE_USER", "ROLE_AUDITING", "ROLE_ADMIN");
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
assertThat(granted).isTrue();
}
@Test
public void checkWhenHasAnyRoleAndNotAuthorizedThenReturnFalse() {
manager = AuthorityReactiveAuthorizationManager.hasAnyRole("GENERAL", "USER", "TEST");
authentication = new TestingAuthenticationToken("rob", "secret", "USER", "AUDITING", "ADMIN");
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
assertThat(granted).isFalse();
}
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void hasRoleWhenNullThenException() { public void hasRoleWhenNullThenException() {
String role = null; String role = null;
@ -125,4 +145,30 @@ public class AuthorityReactiveAuthorizationManagerTests {
String authority = null; String authority = null;
AuthorityReactiveAuthorizationManager.hasAuthority(authority); AuthorityReactiveAuthorizationManager.hasAuthority(authority);
} }
@Test(expected = IllegalArgumentException.class)
public void hasAnyRoleWhenNullThenException() {
String role = null;
AuthorityReactiveAuthorizationManager.hasAnyRole(role);
}
@Test(expected = IllegalArgumentException.class)
public void hasAnyAuthorityWhenNullThenException() {
String authority = null;
AuthorityReactiveAuthorizationManager.hasAnyAuthority(authority);
}
@Test(expected = IllegalArgumentException.class)
public void hasAnyRoleWhenOneIsNullThenException() {
String role1 = "ROLE_ADMIN";
String role2 = null;
AuthorityReactiveAuthorizationManager.hasAnyRole(role1, role2);
}
@Test(expected = IllegalArgumentException.class)
public void hasAnyAuthorityWhenOneIsNullThenException() {
String authority1 = "ADMIN";
String authority2 = null;
AuthorityReactiveAuthorizationManager.hasAnyAuthority(authority1, authority2);
}
} }