Skip to content

Commit 549569e

Browse files
authored
Add DefaultAuthorizationManagerFactory.additionalAuthorization
2 parents 459b872 + 1608465 commit 549569e

File tree

3 files changed

+380
-17
lines changed

3 files changed

+380
-17
lines changed

core/src/main/java/org/springframework/security/authorization/AllAuthoritiesAuthorizationManager.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,19 @@ public static <T> AllAuthoritiesAuthorizationManager<T> hasAllAuthorities(String
134134
return new AllAuthoritiesAuthorizationManager<>(authorities);
135135
}
136136

137+
/**
138+
* Creates an instance of {@link AllAuthoritiesAuthorizationManager} with the provided
139+
* authorities.
140+
* @param authorities the authorities to check for
141+
* @param <T> the type of object being authorized
142+
* @return the new instance
143+
*/
144+
public static <T> AllAuthoritiesAuthorizationManager<T> hasAllAuthorities(List<String> authorities) {
145+
Assert.notEmpty(authorities, "authorities cannot be empty");
146+
Assert.noNullElements(authorities, "authorities cannot contain null values");
147+
return new AllAuthoritiesAuthorizationManager<>(authorities.toArray(new String[0]));
148+
}
149+
137150
private static String[] toNamedRolesArray(String rolePrefix, String[] roles) {
138151
String[] result = new String[roles.length];
139152
for (int i = 0; i < roles.length; i++) {

core/src/main/java/org/springframework/security/authorization/DefaultAuthorizationManagerFactory.java

Lines changed: 127 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,25 @@
1616

1717
package org.springframework.security.authorization;
1818

19+
import java.util.ArrayList;
20+
import java.util.List;
21+
1922
import org.jspecify.annotations.Nullable;
2023

2124
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
2225
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
2326
import org.springframework.security.authentication.AuthenticationTrustResolver;
2427
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
2528
import org.springframework.util.Assert;
29+
import org.springframework.util.CollectionUtils;
2630

2731
/**
2832
* A factory for creating different kinds of {@link AuthorizationManager} instances.
2933
*
3034
* @param <T> the type of object that the authorization check is being done on
3135
* @author Steve Riesenberg
36+
* @author Andrey Litvitski
37+
* @author Rob Winch
3238
* @since 7.0
3339
*/
3440
public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object>
@@ -40,6 +46,8 @@ public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object
4046

4147
private String rolePrefix = "ROLE_";
4248

49+
private @Nullable AuthorizationManager<T> additionalAuthorization;
50+
4351
/**
4452
* Sets the {@link AuthenticationTrustResolver} used to check the user's
4553
* authentication.
@@ -69,71 +77,173 @@ public void setRolePrefix(String rolePrefix) {
6977
this.rolePrefix = rolePrefix;
7078
}
7179

80+
/**
81+
* Sets additional authorization to be applied to the returned
82+
* {@link AuthorizationManager} for the following methods:
83+
*
84+
* <ul>
85+
* <li>{@link #hasRole(String)}</li>
86+
* <li>{@link #hasAnyRole(String...)}</li>
87+
* <li>{@link #hasAllRoles(String...)}</li>
88+
* <li>{@link #hasAuthority(String)}</li>
89+
* <li>{@link #hasAnyAuthority(String...)}</li>
90+
* <li>{@link #hasAllAuthorities(String...)}</li>
91+
* <li>{@link #authenticated()}</li>
92+
* <li>{@link #fullyAuthenticated()}</li>
93+
* <li>{@link #rememberMe()}</li>
94+
* </ul>
95+
*
96+
* <p>
97+
* This does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}.
98+
* </p>
99+
* @param additionalAuthorization the {@link AuthorizationManager} to be applied.
100+
* Default is null (no additional authorization).
101+
*/
102+
public void setAdditionalAuthorization(@Nullable AuthorizationManager<T> additionalAuthorization) {
103+
this.additionalAuthorization = additionalAuthorization;
104+
}
105+
72106
@Override
73107
public AuthorizationManager<T> hasRole(String role) {
74108
return hasAnyRole(role);
75109
}
76110

77111
@Override
78112
public AuthorizationManager<T> hasAnyRole(String... roles) {
79-
return withRoleHierarchy(AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, roles));
113+
return createManager(AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, roles));
80114
}
81115

82116
@Override
83117
public AuthorizationManager<T> hasAllRoles(String... roles) {
84-
return withRoleHierarchy(AllAuthoritiesAuthorizationManager.hasAllPrefixedAuthorities(this.rolePrefix, roles));
118+
return createManager(AllAuthoritiesAuthorizationManager.hasAllPrefixedAuthorities(this.rolePrefix, roles));
85119
}
86120

87121
@Override
88122
public AuthorizationManager<T> hasAuthority(String authority) {
89-
return withRoleHierarchy(AuthorityAuthorizationManager.hasAuthority(authority));
123+
return createManager(AuthorityAuthorizationManager.hasAuthority(authority));
90124
}
91125

92126
@Override
93127
public AuthorizationManager<T> hasAnyAuthority(String... authorities) {
94-
return withRoleHierarchy(AuthorityAuthorizationManager.hasAnyAuthority(authorities));
128+
return createManager(AuthorityAuthorizationManager.hasAnyAuthority(authorities));
95129
}
96130

97131
@Override
98132
public AuthorizationManager<T> hasAllAuthorities(String... authorities) {
99-
return withRoleHierarchy(AllAuthoritiesAuthorizationManager.hasAllAuthorities(authorities));
133+
return createManager(AllAuthoritiesAuthorizationManager.hasAllAuthorities(authorities));
100134
}
101135

102136
@Override
103137
public AuthorizationManager<T> authenticated() {
104-
return withTrustResolver(AuthenticatedAuthorizationManager.authenticated());
138+
return createManager(AuthenticatedAuthorizationManager.authenticated());
105139
}
106140

107141
@Override
108142
public AuthorizationManager<T> fullyAuthenticated() {
109-
return withTrustResolver(AuthenticatedAuthorizationManager.fullyAuthenticated());
143+
return createManager(AuthenticatedAuthorizationManager.fullyAuthenticated());
110144
}
111145

112146
@Override
113147
public AuthorizationManager<T> rememberMe() {
114-
return withTrustResolver(AuthenticatedAuthorizationManager.rememberMe());
148+
return createManager(AuthenticatedAuthorizationManager.rememberMe());
115149
}
116150

117151
@Override
118152
public AuthorizationManager<T> anonymous() {
119-
return withTrustResolver(AuthenticatedAuthorizationManager.anonymous());
153+
return createManager(AuthenticatedAuthorizationManager.anonymous());
120154
}
121155

122-
private AuthorityAuthorizationManager<T> withRoleHierarchy(AuthorityAuthorizationManager<T> authorizationManager) {
156+
/**
157+
* Creates a {@link Builder} that helps build an {@link AuthorizationManager} to set
158+
* on {@link #setAdditionalAuthorization(AuthorizationManager)} for common scenarios.
159+
* <p>
160+
* Does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}.
161+
* @param <T> the secured object type
162+
* @return a factory configured with the required authorities
163+
*/
164+
public static <T> Builder<T> builder() {
165+
return new Builder<>();
166+
}
167+
168+
private AuthorizationManager<T> createManager(AuthorityAuthorizationManager<T> authorizationManager) {
123169
authorizationManager.setRoleHierarchy(this.roleHierarchy);
124-
return authorizationManager;
170+
return withAdditionalAuthorization(authorizationManager);
125171
}
126172

127-
private AllAuthoritiesAuthorizationManager<T> withRoleHierarchy(
128-
AllAuthoritiesAuthorizationManager<T> authorizationManager) {
173+
private AuthorizationManager<T> createManager(AllAuthoritiesAuthorizationManager<T> authorizationManager) {
129174
authorizationManager.setRoleHierarchy(this.roleHierarchy);
130-
return authorizationManager;
175+
return withAdditionalAuthorization(authorizationManager);
131176
}
132177

133-
private AuthenticatedAuthorizationManager<T> withTrustResolver(
134-
AuthenticatedAuthorizationManager<T> authorizationManager) {
178+
private AuthorizationManager<T> createManager(AuthenticatedAuthorizationManager<T> authorizationManager) {
135179
authorizationManager.setTrustResolver(this.trustResolver);
136-
return authorizationManager;
180+
return withAdditionalAuthorization(authorizationManager);
181+
}
182+
183+
private AuthorizationManager<T> withAdditionalAuthorization(AuthorizationManager<T> manager) {
184+
if (this.additionalAuthorization == null) {
185+
return manager;
186+
}
187+
return AuthorizationManagers.allOf(new AuthorizationDecision(false), this.additionalAuthorization, manager);
188+
}
189+
190+
/**
191+
* A builder that allows creating {@link DefaultAuthorizationManagerFactory} with
192+
* additional authorization for common scenarios.
193+
*
194+
* @param <T> the type for the {@link DefaultAuthorizationManagerFactory}
195+
* @author Rob Winch
196+
*/
197+
public static final class Builder<T> {
198+
199+
private final List<String> additionalAuthorities = new ArrayList<>();
200+
201+
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
202+
203+
/**
204+
* Add additional authorities that will be required.
205+
* @param additionalAuthorities the additional authorities.
206+
* @return the {@link Builder} to further customize.
207+
*/
208+
public Builder<T> requireAdditionalAuthorities(String... additionalAuthorities) {
209+
Assert.notEmpty(additionalAuthorities, "additionalAuthorities cannot be empty");
210+
for (String additionalAuthority : additionalAuthorities) {
211+
this.additionalAuthorities.add(additionalAuthority);
212+
}
213+
return this;
214+
}
215+
216+
/**
217+
* The {@link RoleHierarchy} to use.
218+
* @param roleHierarchy the non-null {@link RoleHierarchy} to use. Default is
219+
* {@link NullRoleHierarchy}.
220+
* @return the Builder to further customize.
221+
*/
222+
public Builder<T> roleHierarchy(RoleHierarchy roleHierarchy) {
223+
Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
224+
this.roleHierarchy = roleHierarchy;
225+
return this;
226+
}
227+
228+
/**
229+
* Builds a {@link DefaultAuthorizationManagerFactory} that has the
230+
* {@link #setAdditionalAuthorization(AuthorizationManager)} set.
231+
* @return the {@link DefaultAuthorizationManagerFactory}.
232+
*/
233+
public DefaultAuthorizationManagerFactory<T> build() {
234+
Assert.state(!CollectionUtils.isEmpty(this.additionalAuthorities), "additionalAuthorities cannot be empty");
235+
DefaultAuthorizationManagerFactory<T> result = new DefaultAuthorizationManagerFactory<>();
236+
AllAuthoritiesAuthorizationManager<T> additionalChecks = AllAuthoritiesAuthorizationManager
237+
.hasAllAuthorities(this.additionalAuthorities);
238+
result.setRoleHierarchy(this.roleHierarchy);
239+
additionalChecks.setRoleHierarchy(this.roleHierarchy);
240+
result.setAdditionalAuthorization(additionalChecks);
241+
return result;
242+
}
243+
244+
private Builder() {
245+
}
246+
137247
}
138248

139249
}

0 commit comments

Comments
 (0)