2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.policy.elk.converter;
24 import io.searchbox.core.Update;
27 import java.io.FileInputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.OutputStream;
31 import java.io.StringReader;
32 import java.io.StringWriter;
33 import java.net.MalformedURLException;
35 import java.net.URLConnection;
36 import java.nio.file.FileSystems;
37 import java.nio.file.Files;
38 import java.nio.file.Path;
39 import java.nio.file.Paths;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.Enumeration;
43 import java.util.HashMap;
44 import java.util.List;
46 import java.util.Properties;
48 import javax.xml.bind.JAXBContext;
49 import javax.xml.bind.JAXBElement;
50 import javax.xml.bind.JAXBException;
51 import javax.xml.bind.Marshaller;
52 import javax.xml.bind.Unmarshaller;
53 import javax.xml.transform.Result;
54 import javax.xml.transform.stream.StreamResult;
56 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType;
57 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
58 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
59 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
60 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
61 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
63 import org.apache.commons.io.IOUtils;
64 import org.eclipse.persistence.jaxb.JAXBContextFactory;
65 import org.eclipse.persistence.jaxb.MarshallerProperties;
66 import org.eclipse.persistence.jaxb.json.JsonSchemaOutputResolver;
68 import com.att.research.xacml.api.Advice;
69 import com.att.research.xacml.api.AttributeAssignment;
70 import com.att.research.xacml.api.Identifier;
71 import com.att.research.xacml.api.Obligation;
72 import org.openecomp.policy.xacml.api.XACMLErrorConstants;
73 import com.att.research.xacml.util.XACMLPolicyScanner;
74 import com.att.research.xacml.util.XACMLProperties;
75 import com.att.research.xacml.util.XACMLPolicyScanner.CallbackResult;
76 import com.att.research.xacml.util.XACMLPolicyScanner.SimpleCallback;
77 import com.fasterxml.jackson.core.JsonProcessingException;
78 import com.fasterxml.jackson.databind.JsonNode;
79 import com.fasterxml.jackson.databind.ObjectMapper;
80 import com.fasterxml.jackson.databind.SerializationFeature;
81 import com.fasterxml.jackson.databind.node.ObjectNode;
82 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
83 import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
84 import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
85 import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper;
87 import org.kohsuke.args4j.CmdLineException;
88 import org.kohsuke.args4j.CmdLineParser;
89 import org.kohsuke.args4j.Option;
90 import org.openecomp.policy.elk.client.ElkConnector;
91 import org.openecomp.policy.elk.client.ElkConnector.PolicyBodyType;
92 import org.openecomp.policy.rest.XACMLRestProperties;
93 import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
94 import org.openecomp.policy.common.logging.flexlogger.Logger;
97 @SuppressWarnings("unused")
98 public class Xacml2Elk {
99 public static final String URLID_ATTRIBUTE = "URLID";
100 public static final String BODY_ATTRIBUTE = "body";
102 protected static final Logger logger = FlexLogger.getLogger(Xacml2Elk.class);
103 protected static JAXBContext jaxbContext = jaxbContext();
105 protected static String toConfigsWebDirectory(String policyType)
106 throws IllegalArgumentException {
107 if (policyType == null || policyType.isEmpty())
108 throw new IllegalArgumentException("Unexpected policy type: " + policyType);
110 ElkConnector.PolicyType type = ElkConnector.PolicyType.valueOf(policyType);
122 return ElkConnector.PolicyType.Config.name();
124 throw new IllegalArgumentException("Unexpected policy type: " + policyType);
128 protected synchronized static JAXBContext jaxbContext() {
129 if (jaxbContext != null) {
134 jaxbContext = JAXBContextFactory.createContext(new Class[] {PolicyType.class}, null);
135 } catch (JAXBException e) {
136 logger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + ":" +
137 "JAXB Context cannot be created");
144 protected static class CLIOptions {
145 @Option(name="-t", usage="policy type", aliases={"-type", "--type"}, required=true)
146 protected String type;
148 @Option(name="-n", usage="policy name", aliases={"-name", "--name"}, required=true)
149 protected String name;
151 @Option(name="-o", usage="git repository owner", aliases={"-owner", "--owner"}, required=true)
152 protected String owner;
154 @Option(name="-s", usage="enclosing scope", aliases={"-scope", "--scope"}, required=true)
155 protected String scope;
157 @Option(name="-x", usage="xacml input file", aliases={"-xacml", "--xacml"}, required=true, metaVar="<xacml input file>")
158 protected File xacmlFile;
160 @Option(name="-p", usage="payload body type", aliases={"-payloadType", "--payloadType"}, required=false, metaVar="<bayload body type>", depends={"-b"})
161 protected PolicyBodyType bodyType;
163 @Option(name="-b", usage="payload body", aliases={"-body", "--body"}, required=false, metaVar="<bayload body type>", depends={"-p"})
164 protected String body;
166 @Option(name="-d", usage="elk record output directory", aliases={"-d", "--directory"}, required=true, metaVar="<elk directory>")
167 protected File elkDirectory;
169 @Option(name = "-h", aliases = {"-help", "--help"}, usage = "print this message")
170 private boolean help = false;
173 class AttributeAssignmentFinderProcessor extends SimpleCallback {
174 protected final String attributeId;
175 protected String attributeValue = null;
177 public AttributeAssignmentFinderProcessor(String attributeId) {
178 this.attributeId = attributeId;
181 public String getAttributeValue() {
182 return attributeValue;
185 public boolean isAttributeValue() {
186 return (this.attributeValue != null && !this.attributeValue.isEmpty());
189 private boolean processAssignments(
190 List<AttributeAssignmentExpressionType> assignments) {
191 if (logger.isTraceEnabled())
192 logger.trace("ENTER");
194 for (AttributeAssignmentExpressionType assignment : assignments) {
195 if (!assignment.getAttributeId().equals(attributeId)) {
196 if (logger.isDebugEnabled())
197 logger.debug("Ignoring: " + assignment.getAttributeId());
201 if (logger.isDebugEnabled())
202 logger.debug("Found Attribute ID: " + assignment.getAttributeId());
204 JAXBElement<?> jaxbExp = assignment.getExpression();
205 Object assignmentObject = jaxbExp.getValue();
206 if (assignmentObject instanceof AttributeValueType) {
207 AttributeValueType avt = (AttributeValueType) assignmentObject;
208 if (avt.getContent().size() <= 0) {
209 logger.warn("Ignoring: " + assignment.getAttributeId() + ": No values");
213 this.attributeValue = avt.getContent().get(0).toString();
214 if (logger.isInfoEnabled())
215 logger.info("Found: " + this.attributeValue);
224 public CallbackResult onAdvice(Object parent, AdviceExpressionType expression, Advice advice) {
225 if (logger.isTraceEnabled())
226 logger.trace("ENTER");
228 List<AttributeAssignmentExpressionType> assignments =
229 expression.getAttributeAssignmentExpression();
231 if (assignments != null) {
232 boolean found = processAssignments(assignments);
234 return CallbackResult.STOP;
237 return super.onAdvice(parent, expression, advice);
241 public CallbackResult onObligation(Object parent, ObligationExpressionType expression, Obligation obligation) {
242 if (logger.isTraceEnabled())
243 logger.trace("ENTER");
245 List<AttributeAssignmentExpressionType> assignments =
246 expression.getAttributeAssignmentExpression();
248 if (assignments != null) {
249 boolean found = processAssignments(assignments);
251 return CallbackResult.STOP;
254 return super.onObligation(parent, expression, obligation);
259 final protected String type;
260 final protected String name;
261 final protected String owner;
262 final protected String scope;
263 final protected File xacmlFile;
264 final protected File elkDirectory;
266 final protected JAXBElement<PolicyType> policy;
268 protected PolicyBodyType bodyType;
269 protected String body;
272 public Xacml2Elk(String type, String name,
273 String owner, String scope,
274 File xacmlFile, File elkDirectory)
275 throws IllegalArgumentException {
281 this.xacmlFile = xacmlFile;
282 this.elkDirectory = elkDirectory;
284 this.policy = jaxbXacml(xacmlFile);
287 this.bodyType = PolicyBodyType.none;
291 public Xacml2Elk(CLIOptions args) throws IllegalArgumentException {
292 this.type = args.type;
293 this.name = args.name;
294 this.owner = args.owner;
295 this.scope = args.scope;
296 this.xacmlFile = args.xacmlFile;
297 this.elkDirectory = args.elkDirectory;
299 this.policy = jaxbXacml(xacmlFile);
301 if (args.body == null || args.body.isEmpty()) {
303 this.bodyType = PolicyBodyType.none;
306 this.body = args.body;
307 this.bodyType = args.bodyType;
311 public Xacml2Elk(String type, String name, String owner,
312 String scope, File xacmlFile, PolicyBodyType bodyType,
313 String body, File destinationDir)
314 throws IllegalArgumentException {
319 this.xacmlFile = xacmlFile;
320 this.bodyType = bodyType;
322 this.elkDirectory = destinationDir;
324 this.policy = jaxbXacml(xacmlFile);
327 public Xacml2Elk(File xacmlFile, boolean skipBody)
328 throws IllegalArgumentException {
329 this.policy = jaxbXacml(xacmlFile);
330 PolicyType jPolicy = this.policy.getValue();
332 this.xacmlFile = xacmlFile;
334 this.type = ElkConnector.toPolicyType(xacmlFile.getName()).name();
335 String fileName = xacmlFile.getName().replaceFirst(this.type + "_", "");
336 if (fileName.indexOf(".") > 0)
337 this.name = fileName.substring(0, fileName.lastIndexOf("."));
339 this.name = fileName;
341 this.owner = "admin";
342 this.scope = getScope(xacmlFile.getParent());
343 this.elkDirectory = null;
346 this.bodyType = PolicyBodyType.none;
352 @SuppressWarnings("unchecked")
353 protected JAXBElement<PolicyType> jaxbXacml(File xacmlFile) throws IllegalArgumentException {
354 Path xacmlPath = xacmlFile.toPath();
355 if (!Files.isReadable(xacmlPath) || !Files.isRegularFile(xacmlPath)) {
356 if (logger.isWarnEnabled()) {
357 logger.warn("Error: " + xacmlPath + " is invalid.");
359 throw new IllegalArgumentException("Error: " + xacmlPath + " is invalid.");
363 Unmarshaller u = jaxbContext.createUnmarshaller();
364 return (JAXBElement<PolicyType>) u.unmarshal(xacmlFile);
365 } catch (Exception e) {
366 if (logger.isWarnEnabled()) {
367 logger.warn(XACMLErrorConstants.ERROR_DATA_ISSUE + " - error: " + xacmlPath + " is invalid.");
369 throw new IllegalArgumentException(xacmlFile.getAbsolutePath() + " does not contain valid XACML");
373 public JAXBElement<PolicyType> getPolicy() {
377 protected String getScope(String xacmlDirPath) {
378 if (logger.isTraceEnabled()) logger.trace("ENTER");
380 xacmlDirPath = xacmlDirPath.replaceAll("//", "/");
381 xacmlDirPath = xacmlDirPath.replaceAll("\\\\", "/");
382 xacmlDirPath = xacmlDirPath.replace('\\', '/');
384 String ws = XACMLProperties.getProperty(XACMLRestProperties.PROP_ADMIN_WORKSPACE);
385 String adminRepo = XACMLProperties.getProperty(XACMLRestProperties.PROP_ADMIN_REPOSITORY);
386 Path wsPath = Paths.get(ws, "admin", adminRepo);
387 File repoDir = wsPath.toFile();
388 String repoPath = repoDir.getPath();
389 repoPath = repoPath.replaceAll("//", "/");
390 repoPath = repoPath.replaceAll("\\\\", "/");
391 repoPath = repoPath.replace('\\', '/');
393 int startIndex = xacmlDirPath.indexOf(repoPath.toString()) + repoPath.toString().length() + 1;
394 String scope = xacmlDirPath.substring(startIndex, xacmlDirPath.length());
396 if (logger.isInfoEnabled())
397 logger.info("xacml-policy-path=" + xacmlDirPath + "|" +
398 "repository-path=" + repoPath + "|" +
404 @SuppressWarnings("deprecation")
405 private boolean bodyFromXacml() {
406 if (logger.isTraceEnabled())
407 logger.trace("ENTER");
409 String urlAttribute = URLID_ATTRIBUTE;
411 switch (ElkConnector.toPolicyType(this.type)) {
413 urlAttribute = BODY_ATTRIBUTE;
417 /* no body attached to decision policies */
418 if (logger.isInfoEnabled())
419 logger.info("No body attached for this type of policy: " + this.xacmlFile.getAbsolutePath());
422 /* a flavour of a config policy - default is fine */
425 } catch (IllegalArgumentException iae) {
426 if (logger.isWarnEnabled()) {
427 logger.warn(this.type + " cannot be converted to a valid type: " + iae.getMessage(), iae);
432 AttributeAssignmentFinderProcessor
433 processor = new AttributeAssignmentFinderProcessor(urlAttribute);
434 XACMLPolicyScanner xacmlScanner =
435 new XACMLPolicyScanner(this.policy.getValue(), processor);
437 if (!processor.isAttributeValue()) {
438 if (logger.isInfoEnabled())
439 logger.info(urlAttribute + " not found in " + this.xacmlFile.getAbsolutePath());
443 String configsUrl = XACMLProperties.getProperty(XACMLRestProperties.PROP_CONFIG_URL);
444 if (configsUrl == null || configsUrl.isEmpty() || !configsUrl.startsWith("http")) {
445 if (logger.isWarnEnabled()) {
446 logger.warn(XACMLRestProperties.PROP_CONFIG_URL + " property is not set.");
448 configsUrl = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL);
449 if (configsUrl == null || configsUrl.isEmpty() || !configsUrl.startsWith("http")) {
450 if (logger.isWarnEnabled()) {
451 logger.warn(XACMLRestProperties.PROP_PAP_URL + " property is not set.");
455 configsUrl = configsUrl.replaceFirst("/pap", "");
459 if (!configsUrl.endsWith("/")) {
463 String urlXacml = processor.getAttributeValue();
464 if (logger.isDebugEnabled()) {
465 logger.debug("configs url is " + configsUrl + "and url in xacml is " + urlXacml);
468 if (urlXacml.startsWith("http")) {
469 // assuming this an unescaped url
470 } else if (urlXacml.startsWith("$URLConfig/")) {
471 urlXacml = urlXacml.replace("$URLConfig/", configsUrl);
472 } else if (urlXacml.startsWith("$URL/")) {
473 urlXacml = urlXacml.replace("$URL/", configsUrl);
475 if (logger.isWarnEnabled()) {
476 logger.warn("XACML url is not in the expected format: " + urlXacml);
481 if (urlXacml.endsWith(".properties")) {
482 this.bodyType = PolicyBodyType.properties;
483 } else if (urlXacml.endsWith(".json")) {
484 this.bodyType = PolicyBodyType.json;
485 } else if (urlXacml.endsWith(".xml")) {
486 this.bodyType = PolicyBodyType.xml;
487 } else if (urlXacml.endsWith(".txt")) {
488 this.bodyType = PolicyBodyType.txt;
491 if (logger.isDebugEnabled()) {
492 logger.debug("converted url from xacml is " + urlXacml + ", body-type is " + this.bodyType);
495 InputStream inConfigs = null;
497 URL url = new URL(urlXacml);
498 URLConnection connection = url.openConnection();
499 inConfigs = connection.getInputStream();
500 String encoding = connection.getContentEncoding();
501 encoding = (encoding == null ? "UTF-8" : encoding);
502 this.body = IOUtils.toString(inConfigs, encoding);
503 if (logger.isInfoEnabled()) {
504 logger.info("The following document of type " + this.bodyType.toString() +
505 " has been fetched from " + urlXacml + System.lineSeparator() +
510 } catch (IOException e) {
512 logger.warn("Unexpected error closing stream to " + urlXacml, e);
515 } catch (Exception e) {
516 if (logger.isWarnEnabled()) {
517 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
518 "- XACML url is not in the expected format: " + e.getMessage() +
523 if (inConfigs != null) {
526 } catch (IOException e) {
528 logger.warn("Unexpected error closing stream to " + urlXacml, e);
533 // if retrieval through PAP url was not possible, try to retrieve it from
534 // filesystem instead.
536 if (this.body == null || this.body.isEmpty()) {
537 Path webappsPath = Paths.get(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_WEBAPPS));
538 if (webappsPath == null) {
539 logger.error("Invalid Webapps Path Location property : " +
540 XACMLRestProperties.PROP_PAP_WEBAPPS);
543 String waPath = webappsPath.toFile().getAbsolutePath();
545 String typeDir = null;
547 typeDir = Xacml2Elk.toConfigsWebDirectory(this.type);
548 } catch (IllegalArgumentException iae) {
549 if (logger.isWarnEnabled()) {
550 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
552 " cannot be converted to body-directory: " + iae.getMessage(),
555 this.bodyType = PolicyBodyType.none;
559 String scopePrefix = this.scope.replace('/', '.');
560 Path bodyPath = Paths.get(waPath,
562 scopePrefix + "." + this.type + "_" +
563 this.name + "." + this.bodyType.name());
564 File bodyFile = bodyPath.toFile();
565 if (Files.notExists(bodyPath)) {
566 if (logger.isWarnEnabled()) {
567 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
568 "The following document of type " + this.bodyType.toString() +
569 " does not exist at filesystem location " + bodyFile.getAbsolutePath());
571 this.bodyType = PolicyBodyType.none;
574 if (logger.isInfoEnabled()) {
575 logger.info("The following document of type " + this.bodyType.toString() +
576 " will be fetched from filesystem location " + bodyFile.getAbsolutePath());
581 inConfigs = new FileInputStream(bodyFile);
582 this.body = IOUtils.toString(inConfigs);
584 if (logger.isInfoEnabled()) {
585 logger.info("The document of type " + this.bodyType.toString() +
586 " has been found at filesystem location " + bodyFile.getAbsolutePath());
588 } catch (Exception e) {
589 if (logger.isWarnEnabled()) {
590 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
591 "- XACML Body File cannot be read: " + bodyFile.getAbsolutePath(), e);
593 this.bodyType = PolicyBodyType.none;
596 if (inConfigs != null) {
599 } catch (IOException e) {
601 logger.warn("Unexpected error closing stream to " + urlXacml, e);
611 public boolean attachJsonBody(JsonNode jPolicy) {
612 if (this.body == null) {
613 if (logger.isWarnEnabled()) {
614 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
615 "- JSON Body expected but none provided from " +
616 this.scope + ":" + this.type + ":" + this.name);
621 ObjectNode jPolicyRoot = (ObjectNode) jPolicy;
623 // verify the json is valid
624 final ObjectMapper mapper = new ObjectMapper();
625 JsonNode jBodyContent;
627 jBodyContent = mapper.readTree(this.body);
628 } catch (IOException e) {
629 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
630 "- JSON Body is invalid in " +
631 this.scope + ":" + this.type + ":" + this.name + ":" +
632 e.getMessage() + System.lineSeparator() + this.body, e);
636 String jBodyName = this.type + "_" + "Body";
637 ObjectNode jBodyContainer = mapper.createObjectNode();
638 jBodyContainer.set(jBodyName, jBodyContent);
640 jPolicyRoot.set("Body", jBodyContainer);
642 if (logger.isDebugEnabled())
643 logger.debug("Attaching JSON to " +
645 this.type + ":" + this.name + ":" +
646 jBodyName + System.lineSeparator() +
652 @SuppressWarnings("unchecked")
653 public boolean attachXmlBody(JsonNode jPolicy) {
654 if (this.body == null) {
655 if (logger.isWarnEnabled()) {
656 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
657 "- JSON Body expected but none provided from " +
658 this.scope + ":" + this.type + ":" + this.name);
663 XmlMapper xmlMapper = new XmlMapper();
664 xmlMapper.setConfig(xmlMapper.getSerializationConfig().withRootName(""));
665 Map<Object, Object> map;
667 map = xmlMapper.readValue(this.body, Map.class);
668 } catch (IOException e) {
669 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
670 "- XML Body is invalid in " +
671 this.scope + ":" + this.type + ":" + this.name + ":" +
672 e.getMessage() + System.lineSeparator() + this.body, e);
676 final ObjectMapper mapper = new ObjectMapper();
679 jXmlBody = mapper.writeValueAsString(map);
680 } catch (JsonProcessingException e) {
681 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
682 "- Cannot convert XML Body to JSON in " +
683 this.scope + ":" + this.type + ":" + this.name + ":" +
684 e.getMessage() + System.lineSeparator() + this.body, e);
688 if (logger.isDebugEnabled())
689 logger.debug("XML-to-JSON Body conversion: " + this.scope + ":" +
690 this.type + ":" + this.name +jXmlBody);
692 JsonNode jBodyContent;
694 jBodyContent = mapper.readTree(jXmlBody);
695 } catch (IOException e) {
696 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
697 "- JSON Body (converted from XML) is invalid in " +
698 this.scope + ":" + this.type + ":" + this.name + ":" +
699 e.getMessage() + System.lineSeparator() + jXmlBody, e);
703 ObjectNode jPolicyRoot = (ObjectNode) jPolicy;
705 String jBodyName = this.type + "_" + "Body";
706 ObjectNode jBodyContainer = mapper.createObjectNode();
707 jBodyContainer.set(jBodyName, jBodyContent);
709 jPolicyRoot.set("Body", jBodyContainer);
712 if (logger.isDebugEnabled())
713 logger.debug("Attaching JSON to " +
715 this.type + ":" + this.name + ":" +
716 jBodyName + System.lineSeparator() +
722 protected boolean attachPropertiesBody(JsonNode jPolicy) {
723 if (this.body == null) {
724 if (logger.isWarnEnabled()) {
725 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
726 "- JSON Body expected but none provided from " +
727 this.scope + ":" + this.type + ":" + this.name);
732 final Properties propBody = new Properties();
734 propBody.load(new StringReader(this.body));
735 } catch (IOException e) {
736 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
737 "- JSON Body is invalid in " +
738 this.scope + ":" + this.type + ":" + this.name + ":" +
739 e.getMessage() + System.lineSeparator() + this.body, e);
743 if (propBody.isEmpty()) {
744 if (logger.isInfoEnabled()) {
745 logger.info("Empty set of properties: " +
746 this.scope + ":" + this.type + ":" + this.name +
747 System.lineSeparator() + this.body);
753 final ObjectMapper mapper = new ObjectMapper();
755 ObjectNode jPolicyRoot = (ObjectNode) jPolicy;
756 ObjectNode jBody = jPolicyRoot.putObject("Body");
757 String jBodyName = this.type + "_" + "Body";
758 ObjectNode jBodyContainer = jBody.putObject(jBodyName);
760 // ObjectNode jBodyContainer = mapper.createObjectNode();
762 for(String key : propBody.stringPropertyNames()) {
763 String value = propBody.getProperty(key);
764 if (logger.isDebugEnabled()) {
765 logger.debug("Attaching JSON field to " + jBodyName + " for " +
766 this.type.toString() + ":" +
767 this.scope + ":" + this.name + ":" + jBodyName + ":" +
768 " <" + key +"," + value + ">");
770 jBodyContainer.put(key, propBody.getProperty(key));
776 public boolean attachTextBody(JsonNode jPolicy) {
777 if (this.body == null) {
778 if (logger.isWarnEnabled()) {
779 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
780 "- JSON Body expected but none provided from " +
781 this.scope + ":" + this.type + ":" + this.name);
786 final ObjectMapper mapper = new ObjectMapper();
787 StringWriter jsonEscapedTextWriter = new StringWriter();
789 mapper.writer().writeValue(jsonEscapedTextWriter, this.body);
790 } catch (IOException e) {
791 if (logger.isWarnEnabled()) {
792 logger.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR +
793 "- Text Body cannot be converted from " +
794 this.scope + ":" + this.type + ":" + this.name + ":" +
795 e.getMessage() + ":" + jsonEscapedTextWriter , e);
799 String jTextBody = jsonEscapedTextWriter.toString();
801 if (logger.isDebugEnabled())
802 logger.debug("XML 2JSON Body conversion: " + this.scope + ":" +
803 this.type + ":" + this.name + ":" + jTextBody);
805 ObjectNode jPolicyRoot = (ObjectNode) jPolicy;
807 String jBodyName = this.type + "_" + "Body";
808 ObjectNode jBodyContainer = mapper.createObjectNode();
809 jBodyContainer.put(jBodyName, jTextBody);
811 jPolicyRoot.set("Body", jBodyContainer);
813 if (logger.isDebugEnabled())
814 logger.debug("Attaching JSON to " +
816 this.type + ":" + this.name + ":" +
823 protected boolean attachBody(JsonNode jPolicy) {
824 if (logger.isTraceEnabled()) logger.trace("ENTER");
826 if (this.bodyType == PolicyBodyType.none) {
827 if (logger.isInfoEnabled())
828 logger.info("No body to attach for policy " +
829 this.scope + "/" + this.type + "_" + this.name);
834 if (this.body == null || this.body.isEmpty()) {
835 if (logger.isWarnEnabled())
836 logger.warn("No body to attach for policy " +
837 this.bodyType + this.type + this.scope + this.name);
842 switch (this.bodyType) {
844 return attachJsonBody(jPolicy);
846 return attachPropertiesBody(jPolicy);
848 return attachXmlBody(jPolicy);
850 return attachTextBody(jPolicy);
853 if (logger.isWarnEnabled())
854 logger.warn("Unexpected body type: " + this.bodyType +
855 this.bodyType + this.type + this.scope + this.name);
860 public ElkRecord record() throws JAXBException, JsonProcessingException,
861 IOException, IllegalArgumentException {
862 if (logger.isTraceEnabled()) logger.trace("ENTER");
864 Marshaller m = jaxbContext.createMarshaller();
865 m.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
866 m.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true);
867 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
868 m.setProperty(MarshallerProperties.JSON_REDUCE_ANY_ARRAYS, true);
869 m.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false);
871 StringWriter policyStringWriter = new StringWriter();
872 m.marshal(policy, policyStringWriter);
874 // add metadata to elk record
876 final ObjectMapper mapper = new ObjectMapper();
877 JsonNode jRoot = mapper.readTree(policyStringWriter.toString());
878 JsonNode jPolicy = jRoot.path("Policy");
879 if (jPolicy.isMissingNode()) {
880 logger.warn("Aborting: Policy root node is missing.");
881 throw new IllegalArgumentException("Missing policy root node");
884 ((ObjectNode) jPolicy).put("PolicyType", this.type.toString());
885 ((ObjectNode) jPolicy).put("PolicyName", this.name);
886 ((ObjectNode) jPolicy).put("Owner", this.owner);
887 ((ObjectNode) jPolicy).put("Scope", this.scope);
889 JsonNode jPolicyId = jPolicy.path("PolicyId");
890 if (jPolicyId.isMissingNode()) {
891 logger.warn("Aborting: Policy ID node is missing.");
892 throw new IllegalArgumentException("Missing policy id");
895 if (!jPolicyId.isTextual() || !jPolicyId.isValueNode()) {
896 logger.warn("Aborting: Policy ID invalid.");
897 throw new IllegalArgumentException("Invalid policy id");
900 String xacmlPolicyId = jPolicyId.asText();
901 String policyId = xacmlPolicyId.substring(xacmlPolicyId.lastIndexOf(":")+1);
903 boolean success = attachBody(jPolicy);
905 mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
906 mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
907 mapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false);
908 mapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, true);
910 String recordText = mapper.writeValueAsString(jRoot);
911 if (logger.isDebugEnabled()) {
912 logger.debug("ELK Record: " + System.lineSeparator() + recordText);
915 ElkRecord elkRecord = new ElkRecord(policyId, recordText, jRoot, success);
919 public void store(String policyId, String record) throws IOException {
920 if (logger.isTraceEnabled()) logger.trace("ENTER");
922 if (this.elkDirectory != null) {
923 Files.createDirectories(this.elkDirectory.toPath());;
924 Path elkPolicyFile = Paths.get(this.elkDirectory.getPath(), policyId + ".json");
926 if (logger.isDebugEnabled()) {
927 logger.info("Output: " + elkPolicyFile.toAbsolutePath().toString());
928 logger.info("---------------------------------------------------");
931 Files.write(elkPolicyFile, record.getBytes());
935 public static void main(String args[])
936 throws JAXBException, IOException, CmdLineException, IllegalStateException {
938 CLIOptions cliOptions = new CLIOptions();
939 CmdLineParser cliParser= new CmdLineParser(cliOptions);
942 cliParser.parseArgument(args);
943 } catch (CmdLineException e) {
944 System.err.println("Usage: Xacml2elk");
945 cliParser.printUsage(System.err);
949 System.out.println("---------------------------------------------------");
950 System.out.println("Converting " + cliOptions.xacmlFile.getName() + " to ELK format");
951 System.out.println("Metadata=" + "[type:" + cliOptions.type +
952 "|name:" + cliOptions.name +
953 "|owner:" + cliOptions.owner +
954 "|scope:" + cliOptions.scope + "]");
956 // generate json from jaxb input file
958 Path xacmlPath = cliOptions.xacmlFile.toPath();
959 if (!Files.isReadable(xacmlPath) || !Files.isRegularFile(xacmlPath)) {
960 System.out.println("Error: " + xacmlPath + " is invalid.");
961 throw new IllegalArgumentException("Error: " + xacmlPath + " is invalid.");
965 Xacml2Elk convertor = new Xacml2Elk(cliOptions);
966 ElkRecord elkRecord = convertor.record();
967 System.out.println(elkRecord.record);
969 Path elkOutDir = cliOptions.elkDirectory.toPath();
970 if (!Files.isReadable(elkOutDir) || !Files.isDirectory(elkOutDir) ||
971 !Files.isWritable(elkOutDir) || !Files.isExecutable(elkOutDir)) {
972 System.out.println("Error: " + elkOutDir.getFileName() + " is invalid.");
973 throw new IllegalArgumentException("Error: " + elkOutDir.getFileName() + " is invalid.");
976 convertor.store(elkRecord.policyId, elkRecord.record);