16
16
17
17
package org .springframework .security .authorization ;
18
18
19
+ import java .util .ArrayList ;
20
+ import java .util .List ;
21
+
19
22
import org .jspecify .annotations .Nullable ;
20
23
21
24
import org .springframework .security .access .hierarchicalroles .NullRoleHierarchy ;
22
25
import org .springframework .security .access .hierarchicalroles .RoleHierarchy ;
23
26
import org .springframework .security .authentication .AuthenticationTrustResolver ;
24
27
import org .springframework .security .authentication .AuthenticationTrustResolverImpl ;
25
28
import org .springframework .util .Assert ;
29
+ import org .springframework .util .CollectionUtils ;
26
30
27
31
/**
28
32
* A factory for creating different kinds of {@link AuthorizationManager} instances.
29
33
*
30
34
* @param <T> the type of object that the authorization check is being done on
31
35
* @author Steve Riesenberg
36
+ * @author Andrey Litvitski
37
+ * @author Rob Winch
32
38
* @since 7.0
33
39
*/
34
40
public final class DefaultAuthorizationManagerFactory <T extends @ Nullable Object >
@@ -40,6 +46,8 @@ public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object
40
46
41
47
private String rolePrefix = "ROLE_" ;
42
48
49
+ private @ Nullable AuthorizationManager <T > additionalAuthorization ;
50
+
43
51
/**
44
52
* Sets the {@link AuthenticationTrustResolver} used to check the user's
45
53
* authentication.
@@ -69,71 +77,173 @@ public void setRolePrefix(String rolePrefix) {
69
77
this .rolePrefix = rolePrefix ;
70
78
}
71
79
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
+
72
106
@ Override
73
107
public AuthorizationManager <T > hasRole (String role ) {
74
108
return hasAnyRole (role );
75
109
}
76
110
77
111
@ Override
78
112
public AuthorizationManager <T > hasAnyRole (String ... roles ) {
79
- return withRoleHierarchy (AuthorityAuthorizationManager .hasAnyRole (this .rolePrefix , roles ));
113
+ return createManager (AuthorityAuthorizationManager .hasAnyRole (this .rolePrefix , roles ));
80
114
}
81
115
82
116
@ Override
83
117
public AuthorizationManager <T > hasAllRoles (String ... roles ) {
84
- return withRoleHierarchy (AllAuthoritiesAuthorizationManager .hasAllPrefixedAuthorities (this .rolePrefix , roles ));
118
+ return createManager (AllAuthoritiesAuthorizationManager .hasAllPrefixedAuthorities (this .rolePrefix , roles ));
85
119
}
86
120
87
121
@ Override
88
122
public AuthorizationManager <T > hasAuthority (String authority ) {
89
- return withRoleHierarchy (AuthorityAuthorizationManager .hasAuthority (authority ));
123
+ return createManager (AuthorityAuthorizationManager .hasAuthority (authority ));
90
124
}
91
125
92
126
@ Override
93
127
public AuthorizationManager <T > hasAnyAuthority (String ... authorities ) {
94
- return withRoleHierarchy (AuthorityAuthorizationManager .hasAnyAuthority (authorities ));
128
+ return createManager (AuthorityAuthorizationManager .hasAnyAuthority (authorities ));
95
129
}
96
130
97
131
@ Override
98
132
public AuthorizationManager <T > hasAllAuthorities (String ... authorities ) {
99
- return withRoleHierarchy (AllAuthoritiesAuthorizationManager .hasAllAuthorities (authorities ));
133
+ return createManager (AllAuthoritiesAuthorizationManager .hasAllAuthorities (authorities ));
100
134
}
101
135
102
136
@ Override
103
137
public AuthorizationManager <T > authenticated () {
104
- return withTrustResolver (AuthenticatedAuthorizationManager .authenticated ());
138
+ return createManager (AuthenticatedAuthorizationManager .authenticated ());
105
139
}
106
140
107
141
@ Override
108
142
public AuthorizationManager <T > fullyAuthenticated () {
109
- return withTrustResolver (AuthenticatedAuthorizationManager .fullyAuthenticated ());
143
+ return createManager (AuthenticatedAuthorizationManager .fullyAuthenticated ());
110
144
}
111
145
112
146
@ Override
113
147
public AuthorizationManager <T > rememberMe () {
114
- return withTrustResolver (AuthenticatedAuthorizationManager .rememberMe ());
148
+ return createManager (AuthenticatedAuthorizationManager .rememberMe ());
115
149
}
116
150
117
151
@ Override
118
152
public AuthorizationManager <T > anonymous () {
119
- return withTrustResolver (AuthenticatedAuthorizationManager .anonymous ());
153
+ return createManager (AuthenticatedAuthorizationManager .anonymous ());
120
154
}
121
155
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 ) {
123
169
authorizationManager .setRoleHierarchy (this .roleHierarchy );
124
- return authorizationManager ;
170
+ return withAdditionalAuthorization ( authorizationManager ) ;
125
171
}
126
172
127
- private AllAuthoritiesAuthorizationManager <T > withRoleHierarchy (
128
- AllAuthoritiesAuthorizationManager <T > authorizationManager ) {
173
+ private AuthorizationManager <T > createManager (AllAuthoritiesAuthorizationManager <T > authorizationManager ) {
129
174
authorizationManager .setRoleHierarchy (this .roleHierarchy );
130
- return authorizationManager ;
175
+ return withAdditionalAuthorization ( authorizationManager ) ;
131
176
}
132
177
133
- private AuthenticatedAuthorizationManager <T > withTrustResolver (
134
- AuthenticatedAuthorizationManager <T > authorizationManager ) {
178
+ private AuthorizationManager <T > createManager (AuthenticatedAuthorizationManager <T > authorizationManager ) {
135
179
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
+
137
247
}
138
248
139
249
}
0 commit comments