1616
1717package org .springframework .security .authorization ;
1818
19+ import java .util .ArrayList ;
20+ import java .util .List ;
21+
1922import org .jspecify .annotations .Nullable ;
2023
2124import org .springframework .security .access .hierarchicalroles .NullRoleHierarchy ;
2225import org .springframework .security .access .hierarchicalroles .RoleHierarchy ;
2326import org .springframework .security .authentication .AuthenticationTrustResolver ;
2427import org .springframework .security .authentication .AuthenticationTrustResolverImpl ;
2528import 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
3236 * @author Andrey Litvitski
37+ * @author Rob Winch
3338 * @since 7.0
3439 */
3540public final class DefaultAuthorizationManagerFactory <T extends @ Nullable Object >
@@ -41,7 +46,7 @@ public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object
4146
4247 private String rolePrefix = "ROLE_" ;
4348
44- private String [] requiredAuthorities = new String [ 0 ] ;
49+ private @ Nullable AuthorizationManager < T > additionalAuthorization ;
4550
4651 /**
4752 * Sets the {@link AuthenticationTrustResolver} used to check the user's
@@ -73,32 +78,29 @@ public void setRolePrefix(String rolePrefix) {
7378 }
7479
7580 /**
76- * Sets authorities required for authorization managers that apply to authenticated
77- * users.
78- * <p>
79- * Does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}.
80- * <p>
81- * Evaluated with the configured {@link RoleHierarchy}.
82- * @param requiredAuthorities the required authorities (must not be {@code null})
83- */
84- public void setRequiredAuthorities (String [] requiredAuthorities ) {
85- Assert .notNull (requiredAuthorities , "requiredAuthorities cannot be null" );
86- this .requiredAuthorities = requiredAuthorities ;
87- }
88-
89- /**
90- * Creates a factory that requires the given authorities for authorization managers
91- * that apply to authenticated users.
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+ *
9296 * <p>
93- * Does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}.
94- * @param authorities the required authorities
95- * @param <T> the secured object type
96- * @return a factory configured with the required authorities
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).
97101 */
98- public static <T > AuthorizationManagerFactory <T > withAuthorities (String ... authorities ) {
99- DefaultAuthorizationManagerFactory <T > factory = new DefaultAuthorizationManagerFactory <>();
100- factory .setRequiredAuthorities (authorities );
101- return factory ;
102+ public void setAdditionalAuthorization (@ Nullable AuthorizationManager <T > additionalAuthorization ) {
103+ this .additionalAuthorization = additionalAuthorization ;
102104 }
103105
104106 @ Override
@@ -108,76 +110,140 @@ public AuthorizationManager<T> hasRole(String role) {
108110
109111 @ Override
110112 public AuthorizationManager <T > hasAnyRole (String ... roles ) {
111- return withRequiredAuthorities (
112- withRoleHierarchy (AuthorityAuthorizationManager .hasAnyRole (this .rolePrefix , roles )));
113+ return createManager (AuthorityAuthorizationManager .hasAnyRole (this .rolePrefix , roles ));
113114 }
114115
115116 @ Override
116117 public AuthorizationManager <T > hasAllRoles (String ... roles ) {
117- return withRequiredAuthorities (withRoleHierarchy (
118- AllAuthoritiesAuthorizationManager .hasAllPrefixedAuthorities (this .rolePrefix , roles )));
118+ return createManager (AllAuthoritiesAuthorizationManager .hasAllPrefixedAuthorities (this .rolePrefix , roles ));
119119 }
120120
121121 @ Override
122122 public AuthorizationManager <T > hasAuthority (String authority ) {
123- return withRequiredAuthorities ( withRoleHierarchy ( AuthorityAuthorizationManager .hasAuthority (authority ) ));
123+ return createManager ( AuthorityAuthorizationManager .hasAuthority (authority ));
124124 }
125125
126126 @ Override
127127 public AuthorizationManager <T > hasAnyAuthority (String ... authorities ) {
128- return withRequiredAuthorities ( withRoleHierarchy ( AuthorityAuthorizationManager .hasAnyAuthority (authorities ) ));
128+ return createManager ( AuthorityAuthorizationManager .hasAnyAuthority (authorities ));
129129 }
130130
131131 @ Override
132132 public AuthorizationManager <T > hasAllAuthorities (String ... authorities ) {
133- return withRequiredAuthorities (
134- withRoleHierarchy (AllAuthoritiesAuthorizationManager .hasAllAuthorities (authorities )));
133+ return createManager (AllAuthoritiesAuthorizationManager .hasAllAuthorities (authorities ));
135134 }
136135
137136 @ Override
138137 public AuthorizationManager <T > authenticated () {
139- return withRequiredAuthorities ( withTrustResolver ( AuthenticatedAuthorizationManager .authenticated () ));
138+ return createManager ( AuthenticatedAuthorizationManager .authenticated ());
140139 }
141140
142141 @ Override
143142 public AuthorizationManager <T > fullyAuthenticated () {
144- return withRequiredAuthorities ( withTrustResolver ( AuthenticatedAuthorizationManager .fullyAuthenticated () ));
143+ return createManager ( AuthenticatedAuthorizationManager .fullyAuthenticated ());
145144 }
146145
147146 @ Override
148147 public AuthorizationManager <T > rememberMe () {
149- return withRequiredAuthorities ( withTrustResolver ( AuthenticatedAuthorizationManager .rememberMe () ));
148+ return createManager ( AuthenticatedAuthorizationManager .rememberMe ());
150149 }
151150
152151 @ Override
153152 public AuthorizationManager <T > anonymous () {
154- return withTrustResolver (AuthenticatedAuthorizationManager .anonymous ());
153+ return createManager (AuthenticatedAuthorizationManager .anonymous ());
155154 }
156155
157- 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 ) {
158169 authorizationManager .setRoleHierarchy (this .roleHierarchy );
159- return authorizationManager ;
170+ return withAdditionalAuthorization ( authorizationManager ) ;
160171 }
161172
162- private AllAuthoritiesAuthorizationManager <T > withRoleHierarchy (
163- AllAuthoritiesAuthorizationManager <T > authorizationManager ) {
173+ private AuthorizationManager <T > createManager (AllAuthoritiesAuthorizationManager <T > authorizationManager ) {
164174 authorizationManager .setRoleHierarchy (this .roleHierarchy );
165- return authorizationManager ;
175+ return withAdditionalAuthorization ( authorizationManager ) ;
166176 }
167177
168- private AuthenticatedAuthorizationManager <T > withTrustResolver (
169- AuthenticatedAuthorizationManager <T > authorizationManager ) {
178+ private AuthorizationManager <T > createManager (AuthenticatedAuthorizationManager <T > authorizationManager ) {
170179 authorizationManager .setTrustResolver (this .trustResolver );
171- return authorizationManager ;
180+ return withAdditionalAuthorization ( authorizationManager ) ;
172181 }
173182
174- private AuthorizationManager <T > withRequiredAuthorities (AuthorizationManager <T > manager ) {
175- if (this .requiredAuthorities == null || this . requiredAuthorities . length == 0 ) {
183+ private AuthorizationManager <T > withAdditionalAuthorization (AuthorizationManager <T > manager ) {
184+ if (this .additionalAuthorization == null ) {
176185 return manager ;
177186 }
178- AuthorizationManager <T > required = withRoleHierarchy (
179- AllAuthoritiesAuthorizationManager .hasAllAuthorities (this .requiredAuthorities ));
180- return AuthorizationManagers .allOf (new AuthorizationDecision (false ), manager , required );
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+
181247 }
182248
183249}
0 commit comments