1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.security.api;
23
24 import static org.opencastproject.security.api.SecurityConstants.GLOBAL_ADMIN_ROLE;
25 import static org.opencastproject.security.util.SecurityUtil.getEpisodeRoleId;
26 import static org.opencastproject.util.EqualsUtil.bothNotNull;
27 import static org.opencastproject.util.EqualsUtil.eqListUnsorted;
28 import static org.opencastproject.util.data.Either.left;
29 import static org.opencastproject.util.data.Either.right;
30
31 import org.opencastproject.util.Checksum;
32 import org.opencastproject.util.data.Either;
33 import org.opencastproject.util.data.Tuple;
34
35 import org.apache.commons.lang3.StringUtils;
36
37 import java.nio.charset.StandardCharsets;
38 import java.security.MessageDigest;
39 import java.security.NoSuchAlgorithmException;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Comparator;
43 import java.util.List;
44 import java.util.Set;
45 import java.util.function.Predicate;
46 import java.util.stream.Collectors;
47
48
49
50
51 public final class AccessControlUtil {
52
53
54 private AccessControlUtil() {
55 }
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 public static boolean isAuthorized(AccessControlList acl, User user, Organization org, Object action) {
83 return isAuthorized(acl, user, org, action, null);
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 public static boolean isAuthorized(AccessControlList acl, User user, Organization org, Object action,
114 String mediaPackageId) {
115 if (action == null || user == null || acl == null || org == null) {
116 throw new IllegalArgumentException();
117 }
118
119
120 if (user.hasRole(GLOBAL_ADMIN_ROLE) || user.hasRole(org.getAdminRole())) {
121 return true;
122 }
123
124
125 if (mediaPackageId != null && user.hasRole(getEpisodeRoleId(mediaPackageId, action.toString()))) {
126 return true;
127 }
128
129 Set<Role> userRoles = user.getRoles();
130 for (AccessControlEntry entry : acl.getEntries()) {
131 if (action.toString().equals(entry.getAction())) {
132 for (Role role : userRoles) {
133 if (role.getName().equals(entry.getRole())) {
134 return entry.isAllow();
135 }
136 }
137 }
138 }
139
140 return false;
141 }
142
143
144
145
146
147
148 private static Predicate<Object> isAuthorizedFn(final AccessControlList acl, final User user,
149 final Organization org) {
150 return action -> isAuthorized(acl, user, org, action);
151 }
152
153
154
155
156
157
158 public static boolean isAuthorizedAll(AccessControlList acl, User user, Organization org, Object... actions) {
159 Predicate<Object> isAuthorized = isAuthorizedFn(acl, user, org);
160 return Arrays.stream(actions).allMatch(isAuthorized);
161 }
162
163
164
165
166
167
168 public static boolean isAuthorizedOne(AccessControlList acl, User user, Organization org, Object... actions) {
169 Predicate<Object> isAuthorized = isAuthorizedFn(acl, user, org);
170 return Arrays.stream(actions).anyMatch(isAuthorized);
171 }
172
173
174
175
176
177
178 public static boolean isProhibitedAll(AccessControlList acl, User user, Organization org, Object... actions) {
179 Predicate<Object> isAuthorized = isAuthorizedFn(acl, user, org);
180 return Arrays.stream(actions).noneMatch(isAuthorized);
181 }
182
183
184
185
186
187
188 public static boolean isProhibitedOne(AccessControlList acl, User user, Organization org, Object... actions) {
189 Predicate<Object> isAuthorized = isAuthorizedFn(acl, user, org);
190 return Arrays.stream(actions).anyMatch(isAuthorized.negate());
191 }
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 public static AccessControlList extendAcl(AccessControlList acl, String role, String action, boolean allow) {
207 AccessControlList newAcl = new AccessControlList();
208 boolean foundAce = false;
209 for (AccessControlEntry ace : acl.getEntries()) {
210 if (ace.getAction().equalsIgnoreCase(action) && ace.getRole().equalsIgnoreCase(role)) {
211 if (ace.isAllow() == allow) {
212
213 return acl;
214 } else {
215
216 foundAce = true;
217 newAcl.getEntries().add(new AccessControlEntry(role, action, allow));
218 }
219 } else {
220 newAcl.getEntries().add(ace);
221 }
222 }
223 if (!foundAce) {
224 newAcl.getEntries().add(new AccessControlEntry(role, action, allow));
225 }
226
227 return newAcl;
228 }
229
230
231
232
233
234
235
236
237
238
239
240
241 public static AccessControlList reduceAcl(AccessControlList acl, String role, String action) {
242 AccessControlList newAcl = new AccessControlList();
243 for (AccessControlEntry ace : acl.getEntries()) {
244 if (!ace.getAction().equalsIgnoreCase(action) || !ace.getRole().equalsIgnoreCase(role)) {
245 newAcl.getEntries().add(ace);
246 }
247 }
248 return newAcl;
249 }
250
251
252
253
254
255
256
257 public static AccessControlList acl(Either<AccessControlEntry, List<AccessControlEntry>>... entries) {
258
259 List<AccessControlEntry> seq = new ArrayList<>();
260 for (Either<AccessControlEntry, List<AccessControlEntry>> current : entries) {
261 if (current.isLeft()) {
262 seq.add(current.left().value());
263 } else {
264 seq.addAll(current.right().value());
265 }
266 }
267 return new AccessControlList(seq);
268 }
269
270
271
272 public static Either<AccessControlEntry, List<AccessControlEntry>> entry(String role, String action, boolean allow) {
273 return left(new AccessControlEntry(role, action, allow));
274 }
275
276
277 public static Either<AccessControlEntry, List<AccessControlEntry>> entries(final String role,
278 Tuple<String, Boolean>... actions) {
279 List<AccessControlEntry> entries = Arrays.stream(actions)
280 .map(action -> new AccessControlEntry(role, action.getA(), action.getB()))
281 .toList();
282 return right(entries);
283 }
284
285
286
287
288
289
290
291
292 public static boolean equals(AccessControlList a, AccessControlList b) {
293 return bothNotNull(a, b) && eqListUnsorted(a.getEntries(), b.getEntries());
294 }
295
296
297 public static Checksum calculateChecksum(AccessControlList acl) {
298
299
300 final byte[] sep = new byte[] { 0 };
301
302
303 List<AccessControlEntry> sortedEntries = acl.getEntries().stream()
304 .sorted(sortAcl)
305 .collect(Collectors.toList());
306
307 MessageDigest digest = mkMd5MessageDigest();
308
309 for (AccessControlEntry entry : sortedEntries) {
310 String[] fields = {
311 entry.getRole(),
312 entry.getAction(),
313 Boolean.toString(entry.isAllow())
314 };
315 for (String field : fields) {
316 digest.update(field.getBytes(StandardCharsets.UTF_8));
317
318 digest.update(sep);
319 }
320 }
321
322 try {
323 return Checksum.create("md5", Checksum.convertToHex(digest.digest()));
324 } catch (NoSuchAlgorithmException e) {
325 throw new RuntimeException(e);
326 }
327 }
328
329 private static MessageDigest mkMd5MessageDigest() {
330 try {
331 return MessageDigest.getInstance("MD5");
332 } catch (NoSuchAlgorithmException e) {
333 throw new RuntimeException(e);
334 }
335 }
336
337 private static Comparator<AccessControlEntry> sortAcl = new Comparator<AccessControlEntry>() {
338 @Override
339 public int compare(AccessControlEntry o1, AccessControlEntry o2) {
340
341 int compareTo = StringUtils.trimToEmpty(o1.getRole()).compareTo(StringUtils.trimToEmpty(o2.getRole()));
342 if (compareTo != 0) {
343 return compareTo;
344 }
345
346
347 compareTo = StringUtils.trimToEmpty(o1.getAction()).compareTo(StringUtils.trimToEmpty(o2.getAction()));
348 if (compareTo != 0) {
349 return compareTo;
350 }
351
352
353 return Boolean.valueOf(o1.isAllow()).compareTo(o2.isAllow());
354 }
355 };
356
357 }