Skip to content

Add hasAnyAuthority() and hasAnyRole() in AuthorizeExchangeSpec #6310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 19, 2018
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 @@ -1563,6 +1563,15 @@ public AuthorizeExchangeSpec hasRole(String 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.
* @param authority the authority to require (i.e. "USER" woudl require authority of "USER").
Expand All @@ -1572,6 +1581,15 @@ public AuthorizeExchangeSpec hasAuthority(String 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
* @return the {@link AuthorizeExchangeSpec} to configure
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand All @@ -20,6 +20,10 @@
import org.springframework.util.Assert;
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
* authorized by evaluating if the {@link Authentication} contains a specified authority.
Expand All @@ -29,19 +33,19 @@
* @param <T> the type of object being authorized
*/
public class AuthorityReactiveAuthorizationManager<T> implements ReactiveAuthorizationManager<T> {
private final String authority;
private final List<String> authorities;

private AuthorityReactiveAuthorizationManager(String authority) {
this.authority = authority;
private AuthorityReactiveAuthorizationManager(String... authorities) {
this.authorities = Arrays.asList(authorities);
}

@Override
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, T object) {
return authentication
.filter(a -> a.isAuthenticated())
.flatMapIterable( a -> a.getAuthorities())
.map( g-> g.getAuthority())
.hasElement(this.authority)
.map(g -> g.getAuthority())
.any(a -> this.authorities.contains(a))
.map( hasAuthority -> new AuthorizationDecision(hasAuthority))
.defaultIfEmpty(new AuthorizationDecision(false));
}
Expand All @@ -59,6 +63,24 @@ public static <T> AuthorityReactiveAuthorizationManager<T> hasAuthority(String a
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
* provided authority.
Expand All @@ -71,4 +93,25 @@ public static <T> AuthorityReactiveAuthorizationManager<T> hasRole(String role)
Assert.notNull(role, "role cannot be null");
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)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public void checkWhenHasRoleAndAuthorizedThenReturnTrue() {
}

@Test
public void checkWhenHasRoleAndNotAuthorizedThenReturnTrue() {
public void checkWhenHasRoleAndNotAuthorizedThenReturnFalse() {
manager = AuthorityReactiveAuthorizationManager.hasRole("ADMIN");
authentication = new TestingAuthenticationToken("rob", "secret", "ADMIN");

Expand All @@ -114,6 +114,26 @@ public void checkWhenHasRoleAndNotAuthorizedThenReturnTrue() {
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)
public void hasRoleWhenNullThenException() {
String role = null;
Expand All @@ -125,4 +145,30 @@ public void hasAuthorityWhenNullThenException() {
String authority = null;
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);
}
}