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 private static Predicate<Object> isAuthorizedFn(final AccessControlList acl, final User user, final Organization org) {
148 return action -> isAuthorized(acl, user, org, action);
149 }
150
151
152
153
154
155
156 public static boolean isAuthorizedAll(AccessControlList acl, User user, Organization org, Object... actions) {
157 Predicate<Object> isAuthorized = isAuthorizedFn(acl, user, org);
158 return Arrays.stream(actions).allMatch(isAuthorized);
159 }
160
161
162
163
164
165
166 public static boolean isAuthorizedOne(AccessControlList acl, User user, Organization org, Object... actions) {
167 Predicate<Object> isAuthorized = isAuthorizedFn(acl, user, org);
168 return Arrays.stream(actions).anyMatch(isAuthorized);
169 }
170
171
172
173
174
175
176 public static boolean isProhibitedAll(AccessControlList acl, User user, Organization org, Object... actions) {
177 Predicate<Object> isAuthorized = isAuthorizedFn(acl, user, org);
178 return Arrays.stream(actions).noneMatch(isAuthorized);
179 }
180
181
182
183
184
185
186 public static boolean isProhibitedOne(AccessControlList acl, User user, Organization org, Object... actions) {
187 Predicate<Object> isAuthorized = isAuthorizedFn(acl, user, org);
188 return Arrays.stream(actions).anyMatch(isAuthorized.negate());
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 public static AccessControlList extendAcl(AccessControlList acl, String role, String action, boolean allow) {
205 AccessControlList newAcl = new AccessControlList();
206 boolean foundAce = false;
207 for (AccessControlEntry ace : acl.getEntries()) {
208 if (ace.getAction().equalsIgnoreCase(action) && ace.getRole().equalsIgnoreCase(role)) {
209 if (ace.isAllow() == allow) {
210
211 return acl;
212 } else {
213
214 foundAce = true;
215 newAcl.getEntries().add(new AccessControlEntry(role, action, allow));
216 }
217 } else {
218 newAcl.getEntries().add(ace);
219 }
220 }
221 if (!foundAce)
222 newAcl.getEntries().add(new AccessControlEntry(role, action, allow));
223
224 return newAcl;
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238 public static AccessControlList reduceAcl(AccessControlList acl, String role, String action) {
239 AccessControlList newAcl = new AccessControlList();
240 for (AccessControlEntry ace : acl.getEntries()) {
241 if (!ace.getAction().equalsIgnoreCase(action) || !ace.getRole().equalsIgnoreCase(role)) {
242 newAcl.getEntries().add(ace);
243 }
244 }
245 return newAcl;
246 }
247
248
249
250
251
252
253
254 public static AccessControlList acl(Either<AccessControlEntry, List<AccessControlEntry>>... entries) {
255
256 List<AccessControlEntry> seq = new ArrayList<>();
257 for (Either<AccessControlEntry, List<AccessControlEntry>> current : entries) {
258 if (current.isLeft()) {
259 seq.add(current.left().value());
260 } else {
261 seq.addAll(current.right().value());
262 }
263 }
264 return new AccessControlList(seq);
265 }
266
267
268
269 public static Either<AccessControlEntry, List<AccessControlEntry>> entry(String role, String action, boolean allow) {
270 return left(new AccessControlEntry(role, action, allow));
271 }
272
273
274 public static Either<AccessControlEntry, List<AccessControlEntry>> entries(final String role,
275 Tuple<String, Boolean>... actions) {
276 List<AccessControlEntry> entries = Arrays.stream(actions)
277 .map(action -> new AccessControlEntry(role, action.getA(), action.getB()))
278 .toList();
279 return right(entries);
280 }
281
282
283
284
285
286
287
288
289 public static boolean equals(AccessControlList a, AccessControlList b) {
290 return bothNotNull(a, b) && eqListUnsorted(a.getEntries(), b.getEntries());
291 }
292
293
294 public static Checksum calculateChecksum(AccessControlList acl) {
295
296
297 final byte[] sep = new byte[] { 0 };
298
299
300 List<AccessControlEntry> sortedEntries = acl.getEntries().stream()
301 .sorted(sortAcl)
302 .collect(Collectors.toList());
303
304 MessageDigest digest = mkMd5MessageDigest();
305
306 for (AccessControlEntry entry : sortedEntries) {
307 String[] fields = {
308 entry.getRole(),
309 entry.getAction(),
310 Boolean.toString(entry.isAllow())
311 };
312 for (String field : fields) {
313 digest.update(field.getBytes(StandardCharsets.UTF_8));
314
315 digest.update(sep);
316 }
317 }
318
319 try {
320 return Checksum.create("md5", Checksum.convertToHex(digest.digest()));
321 } catch (NoSuchAlgorithmException e) {
322 throw new RuntimeException(e);
323 }
324 }
325
326 private static MessageDigest mkMd5MessageDigest() {
327 try {
328 return MessageDigest.getInstance("MD5");
329 } catch (NoSuchAlgorithmException e) {
330 throw new RuntimeException(e);
331 }
332 }
333
334 private static Comparator<AccessControlEntry> sortAcl = new Comparator<AccessControlEntry>() {
335 @Override
336 public int compare(AccessControlEntry o1, AccessControlEntry o2) {
337
338 int compareTo = StringUtils.trimToEmpty(o1.getRole()).compareTo(StringUtils.trimToEmpty(o2.getRole()));
339 if (compareTo != 0)
340 return compareTo;
341
342
343 compareTo = StringUtils.trimToEmpty(o1.getAction()).compareTo(StringUtils.trimToEmpty(o2.getAction()));
344 if (compareTo != 0)
345 return compareTo;
346
347
348 return Boolean.valueOf(o1.isAllow()).compareTo(o2.isAllow());
349 }
350 };
351
352 }