1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.mycore.access.facts;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.concurrent.TimeUnit;
29
30 import org.apache.logging.log4j.LogManager;
31 import org.apache.logging.log4j.Logger;
32 import org.jdom2.Element;
33 import org.jdom2.output.Format;
34 import org.jdom2.output.XMLOutputter;
35 import org.mycore.access.MCRAccessInterface;
36 import org.mycore.access.facts.fact.MCRObjectIDFact;
37 import org.mycore.access.facts.fact.MCRStringFact;
38 import org.mycore.access.facts.model.MCRCombinedCondition;
39 import org.mycore.access.facts.model.MCRCondition;
40 import org.mycore.access.facts.model.MCRFact;
41 import org.mycore.access.facts.model.MCRFactComputable;
42 import org.mycore.access.strategies.MCRAccessCheckStrategy;
43 import org.mycore.common.MCRSessionMgr;
44 import org.mycore.common.MCRUserInformation;
45 import org.mycore.common.config.MCRConfiguration2;
46 import org.mycore.common.config.MCRConfigurationDir;
47 import org.mycore.common.config.annotation.MCRPostConstruction;
48 import org.mycore.common.config.annotation.MCRProperty;
49 import org.mycore.common.content.MCRJDOMContent;
50 import org.mycore.common.xml.MCRURIResolver;
51 import org.mycore.datamodel.classifications2.MCRCategoryDAOFactory;
52 import org.mycore.datamodel.classifications2.MCRCategoryID;
53 import org.mycore.datamodel.metadata.MCRMetadataManager;
54 import org.mycore.datamodel.metadata.MCRObjectID;
55
56 import jakarta.inject.Singleton;
57
58
59
60
61
62
63
64
65
66 @Singleton
67 public class MCRFactsAccessSystem implements MCRAccessInterface, MCRAccessCheckStrategy {
68
69 private static String RESOLVED_RULES_FILE_NAME = "rules.resolved.xml";
70
71 protected static final Logger LOGGER = LogManager.getLogger();
72
73 private MCRCondition rules;
74
75 private Collection<MCRFactComputable<MCRFact<?>>> computers;
76
77
78
79
80
81 private String rulesURI = MCRConfiguration2.getString("MCR.Access.RulesURI").orElse("resource:rules.xml");
82
83 private Map<String, String> properties;
84
85 @MCRPostConstruction
86 public void init(String property) {
87 rules = buildRulesFromXML();
88 computers = buildComputersFromRules();
89 }
90
91 private Collection<MCRFactComputable<MCRFact<?>>> buildComputersFromRules() {
92 Map<String, MCRFactComputable<MCRFact<?>>> collectedComputers = new HashMap<>();
93 collectComputers(rules, collectedComputers);
94 return collectedComputers.values();
95 }
96
97 @SuppressWarnings("unchecked")
98 private void collectComputers(MCRCondition coll, Map<String, MCRFactComputable<MCRFact<?>>> computers) {
99 if (coll instanceof MCRFactComputable<?>
100 && !computers.containsKey(((MCRFactComputable<?>) coll).getFactName())) {
101 computers.put(((MCRFactComputable<?>) coll).getFactName(), (MCRFactComputable<MCRFact<?>>) coll);
102 }
103 if (coll instanceof MCRCombinedCondition) {
104 ((MCRCombinedCondition) coll).getChildConditions().forEach(c -> collectComputers(c, computers));
105 }
106 }
107
108 @MCRProperty(name = "RulesURI", required = false)
109 public void setRulesURI(String uri) {
110 rulesURI = uri;
111 }
112
113 public Map<String, String> getProperties() {
114 return properties;
115 }
116
117 @MCRProperty(name = "*")
118 public void setProperties(Map<String, String> properties) {
119 this.properties = properties;
120 }
121
122 private MCRCondition buildRulesFromXML() {
123 Element eRules = MCRURIResolver.instance().resolve(rulesURI);
124 Objects.requireNonNull(eRules, "The rulesURI " + rulesURI + " resolved to null!");
125 MCRJDOMContent content = new MCRJDOMContent(eRules);
126 try {
127 File configFile = MCRConfigurationDir.getConfigFile(RESOLVED_RULES_FILE_NAME);
128 if (configFile != null) {
129 content.sendTo(configFile);
130 } else {
131 throw new IOException("MCRConfigurationDir is not available!");
132 }
133 } catch (IOException e) {
134 LOGGER.error("Could not write file '" + RESOLVED_RULES_FILE_NAME + "' to config directory", e);
135 LOGGER.info("Rules file is: \n" + new XMLOutputter(Format.getPrettyFormat()).outputString(eRules));
136 }
137 return MCRFactsAccessSystemHelper.parse(eRules);
138 }
139
140 @Override
141 public boolean checkPermission(String id, String permission) {
142 return this.checkPermission(id, permission, MCRSessionMgr.getCurrentSession().getUserInformation());
143 }
144
145 @Override
146 public boolean checkPermissionForUser(String permission, MCRUserInformation userInfo) {
147 return false;
148 }
149
150 public boolean checkPermission(String checkID, String permission, List<MCRFact> baseFacts) {
151 String action = permission.replaceAll("db$", "");
152
153 String target;
154 String cacheKey;
155
156 MCRFactsHolder facts = new MCRFactsHolder(computers);
157
158 baseFacts.forEach(facts::add);
159
160 if (checkID == null) {
161 cacheKey = action;
162 } else {
163 if (MCRObjectID.isValid(checkID)) {
164 MCRObjectID mcrId = MCRObjectID.getInstance(checkID);
165 target = "derivate".equals(mcrId.getTypeId()) ? "files" : "metadata";
166
167 if (MCRMetadataManager.exists(mcrId)) {
168 if ("derivate".equals(mcrId.getTypeId())) {
169 facts.add(new MCRObjectIDFact("derid", checkID, mcrId));
170 MCRObjectID mcrobjID = MCRMetadataManager.getObjectId(mcrId, 10, TimeUnit.MINUTES);
171 if (mcrobjID != null) {
172 facts.add(new MCRObjectIDFact("objid", checkID, mcrobjID));
173 }
174 } else {
175 facts.add(new MCRObjectIDFact("objid", checkID, mcrId));
176 }
177 } else {
178 LOGGER.debug("There is no object or derivate with id " + mcrId.toString() + " in metadata store");
179 }
180 } else if (checkID.startsWith("webpage")) {
181 target = "webpage";
182 } else if (checkID.startsWith("solr")) {
183 target = "solr";
184 } else if (isCategory(checkID)) {
185 target = "category";
186 } else {
187 target = "unknown";
188 }
189 cacheKey = action + " " + checkID + " " + target;
190 facts.add(new MCRStringFact("id", checkID));
191 facts.add(new MCRStringFact("target", target));
192 }
193 facts.add(new MCRStringFact("action", action));
194
195 LOGGER.debug("Testing {} ", cacheKey);
196
197 boolean result;
198 if (LOGGER.isDebugEnabled()) {
199 MCRCondition rules = buildRulesFromXML();
200 result = rules.matches(facts);
201 LOGGER.debug("Facts are: {}", facts);
202
203 Element xmlTree = rules.getBoundElement();
204 String xmlString = new XMLOutputter(Format.getPrettyFormat()).outputString(xmlTree);
205 LOGGER.debug(xmlString);
206 } else {
207 result = rules.matches(facts);
208 }
209 LOGGER.info("Checked permission to {} := {}", cacheKey, result);
210
211 return result;
212 }
213
214 private boolean isCategory(String checkID) {
215 if (!MCRCategoryID.isValid(checkID)) {
216 return false;
217 }
218 try {
219 return MCRCategoryDAOFactory.getInstance().exist(MCRCategoryID.fromString(checkID));
220 } catch (IllegalArgumentException e) {
221 return false;
222 }
223 }
224
225 @Override
226 public boolean checkPermission(final String checkID, String permission, MCRUserInformation userInfo) {
227 return checkPermission(checkID, permission, Collections.emptyList());
228 }
229
230 @Override
231 public boolean checkPermission(String permission) {
232 return checkPermission(null, permission);
233 }
234
235 }