1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.access.mcrimpl;
20
21 import java.net.UnknownHostException;
22 import java.util.Collection;
23 import java.util.Date;
24 import java.util.HashMap;
25 import java.util.Hashtable;
26
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29 import org.jdom2.Attribute;
30 import org.jdom2.Element;
31 import org.mycore.access.MCRAccessBaseImpl;
32 import org.mycore.access.MCRRuleAccessInterface;
33 import org.mycore.common.MCRException;
34 import org.mycore.common.MCRSession;
35 import org.mycore.common.MCRSessionMgr;
36 import org.mycore.common.MCRSystemUserInformation;
37 import org.mycore.common.MCRUserInformation;
38 import org.mycore.common.config.MCRConfiguration2;
39
40
41
42
43
44
45
46 public class MCRAccessControlSystem extends MCRAccessBaseImpl {
47
48 public static final String SYSTEM_RULE_PREFIX = "SYSTEMRULE";
49
50 public static final String POOL_PRIVILEGE_ID = "POOLPRIVILEGE";
51
52 public static final String LEXICOGRAPHICAL_PATTERN = "0000000000";
53
54 MCRAccessStore accessStore;
55
56 MCRRuleStore ruleStore;
57
58 MCRAccessRule dummyRule;
59
60 boolean disabled = false;
61
62 static Hashtable<String, String> ruleIDTable = new Hashtable<>();
63
64 private static final Logger LOGGER = LogManager.getLogger(MCRAccessControlSystem.class);
65
66 private MCRAccessControlSystem() {
67 String pools = MCRConfiguration2.getString("MCR.Access.AccessPermissions").orElse("read,write,delete");
68
69 if (pools.trim().length() == 0) {
70 disabled = true;
71 }
72
73 accessStore = MCRAccessStore.getInstance();
74 ruleStore = MCRRuleStore.getInstance();
75
76 nextFreeRuleID = new HashMap<>();
77
78 dummyRule = new MCRAccessRule(null, null, null, null, "dummy rule, always true");
79 }
80
81 private static MCRAccessControlSystem singleton;
82
83 private static HashMap<String, Integer> nextFreeRuleID;
84
85
86 public static synchronized MCRRuleAccessInterface instance() {
87 if (singleton == null) {
88 singleton = new MCRAccessControlSystem();
89 }
90 return singleton;
91 }
92
93 @Override
94 public void createRule(String ruleString, String creator, String description) {
95 String ruleID = getNextFreeRuleID(SYSTEM_RULE_PREFIX);
96 MCRAccessRule accessRule = new MCRAccessRule(ruleID, creator, new Date(), ruleString, description);
97 ruleStore.createRule(accessRule);
98 }
99
100 @Override
101 public void createRule(Element rule, String creator, String description) {
102 createRule(getNormalizedRuleString(rule), creator, description);
103 }
104
105 @Override
106 public void addRule(String id, String pool, Element rule, String description) throws MCRException {
107 MCRRuleMapping ruleMapping = getAutoGeneratedRuleMapping(rule, "System", pool, id, description);
108 String oldRuleID = accessStore.getRuleID(id, pool);
109 if (oldRuleID == null || oldRuleID.equals("")) {
110 accessStore.createAccessDefinition(ruleMapping);
111 } else {
112 accessStore.updateAccessDefinition(ruleMapping);
113 }
114 }
115
116 @Override
117 public void addRule(String permission, Element rule, String description) {
118 addRule(POOL_PRIVILEGE_ID, permission, rule, description);
119 }
120
121 @Override
122 public void removeRule(String id, String pool) throws MCRException {
123 MCRRuleMapping ruleMapping = accessStore.getAccessDefinition(pool, id);
124 accessStore.deleteAccessDefinition(ruleMapping);
125 }
126
127 @Override
128 public void removeRule(String permission) throws MCRException {
129 removeRule(POOL_PRIVILEGE_ID, permission);
130 }
131
132 @Override
133 public void removeAllRules(String id) throws MCRException {
134 for (String pool : accessStore.getPoolsForObject(id)) {
135 removeRule(id, pool);
136 }
137 }
138
139 @Override
140 public void updateRule(String id, String pool, Element rule, String description) throws MCRException {
141 MCRRuleMapping ruleMapping = getAutoGeneratedRuleMapping(rule, "System", pool, id, description);
142 String oldRuleID = accessStore.getRuleID(id, pool);
143 if (oldRuleID == null || oldRuleID.equals("")) {
144 LOGGER.debug(
145 "updateRule called for id <{}> and pool <{}>, but no rule is existing, so new rule was created", id,
146 pool);
147 accessStore.createAccessDefinition(ruleMapping);
148 } else {
149 accessStore.updateAccessDefinition(ruleMapping);
150 }
151 }
152
153 @Override
154 public void updateRule(String permission, Element rule, String description) throws MCRException {
155 updateRule(POOL_PRIVILEGE_ID, permission, rule, description);
156 }
157
158 @Override
159 public boolean checkPermission(String id, String permission, MCRUserInformation userInfo) {
160 return checkAccess(id, permission, userInfo, null);
161 }
162
163 @Override
164 public boolean checkPermission(String permission) {
165 LOGGER.debug("Execute MCRAccessControlSystem checkPermission for permission {}", permission);
166 boolean ret = checkPermission(POOL_PRIVILEGE_ID, permission);
167 LOGGER.debug("Execute MCRAccessControlSystem checkPermission result: {}", String.valueOf(ret));
168 return ret;
169 }
170
171 @Override
172 @Deprecated
173 public boolean checkPermissionForUser(String permission, String userID) {
174 return checkAccess(POOL_PRIVILEGE_ID, permission, userID, null);
175 }
176
177 @Override
178 public boolean checkPermissionForUser(String permission, MCRUserInformation userInfo) {
179 return checkAccess(POOL_PRIVILEGE_ID, permission, userInfo, null);
180 }
181
182 @Override
183 public boolean checkPermission(Element rule) {
184 MCRSession session = MCRSessionMgr.getCurrentSession();
185 String ruleStr = getNormalizedRuleString(rule);
186 MCRAccessRule accessRule = new MCRAccessRule(null, "System", new Date(), ruleStr, "");
187 try {
188 return accessRule.checkAccess(session.getUserInformation(), new Date(), new MCRIPAddress(
189 session.getCurrentIP()));
190 } catch (MCRException | UnknownHostException e) {
191
192 LOGGER.debug("Error while checking rule.", e);
193 return false;
194 }
195 }
196
197 @Override
198 public Element getRule(String objID, String permission) {
199 MCRAccessRule accessRule = getAccessRule(objID, permission);
200 MCRRuleParser parser = new MCRRuleParser();
201 Element rule = parser.parse(accessRule.rule).toXML();
202 Element condition = new Element("condition");
203 condition.setAttribute("format", "xml");
204 if (rule != null) {
205 condition.addContent(rule);
206 }
207 return condition;
208 }
209
210 @Override
211 public Element getRule(String permission) {
212 return getRule(POOL_PRIVILEGE_ID, permission);
213 }
214
215 @Override
216 public String getRuleDescription(String permission) {
217 return getRuleDescription(POOL_PRIVILEGE_ID, permission);
218 }
219
220 @Override
221 public String getRuleDescription(String objID, String permission) {
222 MCRAccessRule accessRule = getAccessRule(objID, permission);
223 if (accessRule != null && accessRule.getDescription() != null) {
224 return accessRule.getDescription();
225 }
226 return "";
227 }
228
229 @Override
230 public Collection<String> getPermissionsForID(String objid) {
231 return accessStore.getPoolsForObject(objid);
232 }
233
234 @Override
235 public Collection<String> getPermissions() {
236 return accessStore.getPoolsForObject(POOL_PRIVILEGE_ID);
237 }
238
239 @Override
240 public boolean hasRule(String id, String permission) {
241 return accessStore.existsRule(id, permission);
242 }
243
244 @Override
245 public boolean hasRule(String id) {
246 return hasRule(id, null);
247 }
248
249 @Override
250 public Collection<String> getAllControlledIDs() {
251 return accessStore.getDistinctStringIDs();
252 }
253
254
255
256 public boolean isDisabled() {
257 return disabled;
258 }
259
260 @Override
261 public MCRAccessRule getAccessRule(String objID, String pool) {
262 if (disabled) {
263 return dummyRule;
264 }
265 LOGGER.debug("accessStore.getRuleID()");
266 String ruleID = accessStore.getRuleID(objID, pool);
267 if (ruleID == null) {
268 LOGGER.debug("accessStore.getRuleID() done with null");
269 return null;
270 } else {
271 LOGGER.debug("accessStore.getRuleID() done with {}", ruleID);
272 }
273 return ruleStore.getRule(ruleID);
274 }
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289 @Deprecated
290 public boolean checkAccess(String objID, String permission, String userID, MCRIPAddress ip) {
291 Date date = new Date();
292 LOGGER.debug("getAccess()");
293 MCRAccessRule rule = getAccessRule(objID, permission);
294 LOGGER.debug("getAccess() is done");
295 if (rule == null) {
296 return userID.equals(MCRSystemUserInformation.getSuperUserInstance().getUserID());
297 }
298 return rule.checkAccess(userID, date, ip);
299 }
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314 public boolean checkAccess(String objID, String permission, MCRUserInformation userInfo, MCRIPAddress ip) {
315 Date date = new Date();
316 LOGGER.debug("getAccess()");
317 MCRAccessRule rule = getAccessRule(objID, permission);
318 LOGGER.debug("getAccess() is done");
319 if (rule == null) {
320 return userInfo.getUserID().equals(MCRSystemUserInformation.getSuperUserInstance().getUserID());
321 }
322 return rule.checkAccess(userInfo, date, ip);
323 }
324
325
326
327
328
329
330
331
332 public synchronized String getNextFreeRuleID(String prefix) {
333 int nextFreeID;
334 String sNextFreeID;
335 if (nextFreeRuleID.containsKey(prefix)) {
336 nextFreeID = nextFreeRuleID.get(prefix);
337 } else {
338 nextFreeID = ruleStore.getNextFreeRuleID(prefix);
339 }
340 sNextFreeID = LEXICOGRAPHICAL_PATTERN + nextFreeID;
341 sNextFreeID = sNextFreeID.substring(sNextFreeID.length() - LEXICOGRAPHICAL_PATTERN.length());
342 nextFreeRuleID.put(prefix, nextFreeID + 1);
343 return prefix + sNextFreeID;
344 }
345
346
347
348
349
350
351
352
353 @Override
354 public String getNormalizedRuleString(Element rule) {
355 if (rule.getChildren() == null || rule.getChildren().size() == 0) {
356 return "false";
357 }
358 Element normalizedRule = normalize(rule.getChildren().get(0));
359 MCRRuleParser parser = new MCRRuleParser();
360 return parser.parse(normalizedRule).toString();
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376 public MCRRuleMapping getAutoGeneratedRuleMapping(Element rule, String creator, String pool, String id,
377 String description) {
378 String ruleString = getNormalizedRuleString(rule);
379 String ruleID = ruleIDTable.get(ruleString);
380 if (ruleID == null || ruleID.length() == 0) {
381 Collection<String> existingIDs = ruleStore.retrieveRuleIDs(ruleString, description);
382 if (existingIDs != null && existingIDs.size() > 0) {
383
384 ruleID = existingIDs.iterator().next();
385 } else {
386 ruleID = getNextFreeRuleID(SYSTEM_RULE_PREFIX);
387 MCRAccessRule accessRule = new MCRAccessRule(ruleID, creator, new Date(), ruleString, description);
388 ruleStore.createRule(accessRule);
389 }
390 ruleIDTable.put(ruleString, ruleID);
391 }
392 MCRRuleMapping ruleMapping = new MCRRuleMapping();
393 ruleMapping.setCreator(creator);
394 ruleMapping.setCreationdate(new Date());
395 ruleMapping.setPool(pool);
396 ruleMapping.setRuleId(ruleID);
397 ruleMapping.setObjId(id);
398 return ruleMapping;
399 }
400
401
402
403
404
405
406
407
408 public Element normalize(Element rule) {
409 Element newRule = new Element(rule.getName());
410 rule.getAttributes()
411 .stream()
412 .map(Attribute::clone)
413 .forEach(newRule::setAttribute);
414 rule.getChildren()
415 .stream()
416 .map(Element::clone)
417 .map(this::normalize)
418 .sorted(MCRAccessControlSystem::compareAccessConditions)
419 .forEachOrdered(newRule::addContent);
420 return newRule;
421 }
422
423
424
425
426 private static int compareAccessConditions(Element el0, Element el1) {
427 String nameEl0 = el0.getName();
428 String nameEl1 = el1.getName();
429 int nameCompare = nameEl0.compareTo(nameEl1);
430
431 if (nameCompare != 0) {
432 return nameCompare;
433 }
434 if (nameEl0.equals("boolean")) {
435 String opEl0 = el0.getAttributeValue("operator");
436 String opEl1 = el0.getAttributeValue("operator");
437 return opEl0.compareToIgnoreCase(opEl1);
438 } else if (nameEl0.equals("condition")) {
439 String fieldEl0 = el0.getAttributeValue("field");
440 String fieldEl1 = el1.getAttributeValue("field");
441 int fieldCompare = fieldEl0.compareToIgnoreCase(fieldEl1);
442 if (fieldCompare != 0) {
443 return fieldCompare;
444 }
445 String valueEl0 = el0.getAttributeValue("value");
446 String valueEl1 = el1.getAttributeValue("value");
447 return valueEl0.compareTo(valueEl1);
448 }
449 return 0;
450 }
451
452 }