summaryrefslogtreecommitdiffstats
path: root/controlloop/common/guard
diff options
context:
space:
mode:
Diffstat (limited to 'controlloop/common/guard')
-rw-r--r--controlloop/common/guard/src/main/java/org/onap/policy/guard/CallGuardTask.java17
-rw-r--r--controlloop/common/guard/src/main/java/org/onap/policy/guard/PolicyGuardXacmlHelper.java446
-rw-r--r--controlloop/common/guard/src/main/java/org/onap/policy/guard/Util.java40
3 files changed, 386 insertions, 117 deletions
diff --git a/controlloop/common/guard/src/main/java/org/onap/policy/guard/CallGuardTask.java b/controlloop/common/guard/src/main/java/org/onap/policy/guard/CallGuardTask.java
index 87f43d701..d81aaa40c 100644
--- a/controlloop/common/guard/src/main/java/org/onap/policy/guard/CallGuardTask.java
+++ b/controlloop/common/guard/src/main/java/org/onap/policy/guard/CallGuardTask.java
@@ -42,9 +42,10 @@ public class CallGuardTask implements Runnable {
String target;
String requestId;
- public CallGuardTask(String guardUrl, WorkingMemory wm, String cl, String act, String rec, String tar, String reqId) {
-
- restfulPdpUrl = guardUrl;
+ /*
+ * Guard url is grabbed from PolicyEngine.manager properties
+ */
+ public CallGuardTask(WorkingMemory wm, String cl, String act, String rec, String tar, String reqId) {
workingMemory = wm;
clname = cl;
actor = act;
@@ -71,15 +72,13 @@ public class CallGuardTask implements Runnable {
logger.debug("{}", request);
logger.debug("********** XACML REQUEST END ********\n");
- String guardUrl = PolicyEngine.manager.getEnvironmentProperty("guard.url");
+ String guardUrl = PolicyEngine.manager.getEnvironmentProperty(Util.PROP_GUARD_URL);
String guardDecision = null;
//
- // Check if guard url property exists
+ // Make guard request
//
- if(guardUrl != null){
- guardDecision = PolicyGuardXacmlHelper.callPDP(guardUrl, xacmlReq);
- }
+ guardDecision = new PolicyGuardXacmlHelper().callPDP(xacmlReq);
logger.debug("\n********** XACML RESPONSE START ********");
logger.debug("{}", guardDecision);
@@ -90,7 +89,7 @@ public class CallGuardTask implements Runnable {
//
if(guardDecision == null){
logger.error("********** XACML FAILED TO CONNECT ********");
- guardDecision = "Indeterminate";
+ guardDecision = Util.INDETERMINATE;
}
PolicyGuardResponse guardResponse = new PolicyGuardResponse(guardDecision, UUID.fromString(this.requestId), this.recipe);
diff --git a/controlloop/common/guard/src/main/java/org/onap/policy/guard/PolicyGuardXacmlHelper.java b/controlloop/common/guard/src/main/java/org/onap/policy/guard/PolicyGuardXacmlHelper.java
index 826f05652..f5a93d8be 100644
--- a/controlloop/common/guard/src/main/java/org/onap/policy/guard/PolicyGuardXacmlHelper.java
+++ b/controlloop/common/guard/src/main/java/org/onap/policy/guard/PolicyGuardXacmlHelper.java
@@ -25,14 +25,19 @@ import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
+import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Base64;
import java.util.Iterator;
+import java.util.Properties;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.apache.http.entity.ContentType;
import org.json.JSONObject;
+import org.onap.policy.drools.system.PolicyEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,49 +48,86 @@ import com.att.research.xacml.api.Result;
public class PolicyGuardXacmlHelper {
-
- private static final Logger logger = LoggerFactory.getLogger(PolicyGuardXacmlHelper.class);
- public static String callPDP(String restfulPdpUrl, PolicyGuardXacmlRequestAttributes xacmlReq) {
+ private static final Logger logger = LoggerFactory
+ .getLogger(PolicyGuardXacmlHelper.class);
+
+ public PolicyGuardXacmlHelper() {
+ init(PolicyEngine.manager.getEnvironment());
+ }
+
+ // initialized from 'pdpx.url' property --
+ // Each entry in 'restUrls' contains a destination URL, and an optional
+ // 'Authorization' header entry. 'restUrlIndex' indicates the next
+ // entry to try -- after each failure, the index is advanced to the
+ // next entry (wrapping to the beginning, if needed).
+ static private class URLEntry implements Serializable {
+ URL restURL;
+ String authorization = null;
+ String clientAuth = null;
+ String environment = null;
+ };
+
+ private URLEntry[] restUrls = null;
+ private int restUrlIndex = 0;
+
+ // REST timeout, initialized from 'pdpx.timeout' property
+ private int timeout = 20000;
+
+
+ // initialized from 'guard.disabled', but may also be set to 'true' if
+ // there is an initialization error
+ private boolean disabled = false;
+
+ // errors that forced 'disabled' to be set to 'true'
+ private String errorMessage = null;
+
+ public String callPDP(PolicyGuardXacmlRequestAttributes xacmlReq) {
//
// Send it to the PDP
//
-// com.att.research.xacml.api.Response response = null;
String response = null;
-
+
+ //
+ // Build the json request
+ //
JSONObject attributes = new JSONObject();
attributes.put("actor", xacmlReq.getActor_id());
attributes.put("recipe", xacmlReq.getOperation_id());
attributes.put("target", xacmlReq.getTarget_id());
- if (xacmlReq.getClname_id() != null){
+ if (xacmlReq.getClname_id() != null) {
attributes.put("clname", xacmlReq.getClname_id());
}
JSONObject jsonReq = new JSONObject();
jsonReq.put("decisionAttributes", attributes);
jsonReq.put("onapName", "PDPD");
-
+
+ URLEntry urlEntry = restUrls[restUrlIndex];
+
try {
//
// Call RESTful PDP
//
- response = callRESTfulPDP(new ByteArrayInputStream(jsonReq.toString().getBytes()), new URL(restfulPdpUrl/*"https://localhost:8443/pdp/"*/));
+ response = callRESTfulPDP(new ByteArrayInputStream(jsonReq
+ .toString().getBytes()), urlEntry.restURL,
+ urlEntry.authorization, urlEntry.clientAuth,
+ urlEntry.environment);
} catch (Exception e) {
logger.error("Error in sending RESTful request: ", e);
}
-
-
+
return response;
}
-
-
+
/**
- * This makes an HTTP POST call to a running PDP RESTful servlet to get a decision.
+ * This makes an HTTP POST call to a running PDP RESTful servlet to get a
+ * decision.
*
* @param file
* @return response from guard which contains "Permit" or "Deny"
*/
- private static String callRESTfulPDP(InputStream is, URL restURL) {
-// com.att.research.xacml.api.Response response = null;
+ private String callRESTfulPDP(InputStream is, URL restURL,
+ String authorization, String clientauth, String environment) {
String response = null;
String rawDecision = null;
HttpURLConnection connection = null;
@@ -99,16 +141,28 @@ public class PolicyGuardXacmlHelper {
//
// Setup our method and headers
//
- connection.setRequestMethod("POST");
- connection.setUseCaches(false);
- //
- // Adding this in. It seems the HttpUrlConnection class does NOT
- // properly forward our headers for POST re-direction. It does so
- // for a GET re-direction.
- //
- // So we need to handle this ourselves.
- //
- connection.setInstanceFollowRedirects(false);
+ connection.setRequestProperty("Accept", "application/json");
+ if (authorization != null) {
+ connection.setRequestProperty("Authorization", authorization);
+ }
+ if (clientauth != null) {
+ connection.setRequestProperty("ClientAuth", clientauth);
+ }
+ if (environment != null) {
+ connection.setRequestProperty("Environment", environment);
+ }
+ connection.setConnectTimeout(timeout);
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod("POST");
+ connection.setUseCaches(false);
+ //
+ // Adding this in. It seems the HttpUrlConnection class does NOT
+ // properly forward our headers for POST re-direction. It does so
+ // for a GET re-direction.
+ //
+ // So we need to handle this ourselves.
+ //
+ connection.setInstanceFollowRedirects(false);
connection.setDoOutput(true);
connection.setDoInput(true);
//
@@ -117,115 +171,291 @@ public class PolicyGuardXacmlHelper {
try (OutputStream os = connection.getOutputStream()) {
IOUtils.copy(is, os);
}
- //
- // Do the connect
- //
- connection.connect();
- if (connection.getResponseCode() == 200) {
- //
- // Read the response
- //
- ContentType contentType = null;
- try {
- contentType = ContentType.parse(connection.getContentType());
-
- if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType())) {
- InputStream iStream = connection.getInputStream();
- int contentLength = connection.getContentLength();
-
- // if content length is -1, respose is chunked, and
- // TCP connection will be dropped at the end
- byte[] buf =
- new byte[contentLength < 0 ? 1024 : contentLength];
- int offset = 0;
- for ( ; ; )
- {
- if (offset == contentLength)
- {
- // all expected bytes have been read
- response = new String(buf);
- break;
+ //
+ // Do the connect
+ //
+ connection.connect();
+ if (connection.getResponseCode() == 200) {
+ //
+ // Read the response
+ //
+ ContentType contentType = null;
+ try {
+ contentType = ContentType
+ .parse(connection.getContentType());
+
+ if (contentType.getMimeType().equalsIgnoreCase(
+ ContentType.APPLICATION_JSON.getMimeType())) {
+ InputStream iStream = connection.getInputStream();
+ int contentLength = connection.getContentLength();
+
+ // if content length is -1, respose is chunked, and
+ // TCP connection will be dropped at the end
+ byte[] buf = new byte[contentLength < 0 ? 1024
+ : contentLength];
+ int offset = 0;
+ for (;;) {
+ if (offset == contentLength) {
+ // all expected bytes have been read
+ response = new String(buf);
+ break;
}
- int size = iStream.read(buf, offset,
- buf.length - offset);
- if (size < 0)
- {
- if (contentLength > 0)
- {
- logger.error("partial input stream");
- }
- else
- {
- // chunked response --
- // dropped connection is expected
- response = new String(buf, 0, offset);
+ int size = iStream.read(buf, offset, buf.length
+ - offset);
+ if (size < 0) {
+ if (contentLength > 0) {
+ logger.error("partial input stream");
+ } else {
+ // chunked response --
+ // dropped connection is expected
+ response = new String(buf, 0, offset);
}
- break;
+ break;
}
- offset += size;
+ offset += size;
}
- } else {
- logger.error("unknown content-type: " + contentType);
- }
+ } else {
+ logger.error("unknown content-type: " + contentType);
+ }
- } catch (Exception e) {
- String message = "Parsing Content-Type: " + connection.getContentType();
+ } catch (Exception e) {
+ String message = "Parsing Content-Type: "
+ + connection.getContentType();
logger.error(message, e);
- }
+ }
- } else {
- logger.error(connection.getResponseCode() + " " + connection.getResponseMessage());
- }
+ } else {
+ logger.error(connection.getResponseCode() + " "
+ + connection.getResponseMessage());
+ }
} catch (Exception e) {
- logger.error("Exception in 'PolicyGuardXacmlHelper.callRESTfulPDP'", e);
+ logger.error(
+ "Exception in 'PolicyGuardXacmlHelper.callRESTfulPDP'", e);
+ //
+ // Connection may have failed, return Indeterminate
+ //
+ if(response == null || "".equals(response)){
+ return Util.INDETERMINATE;
+ }
}
rawDecision = new JSONObject(response).getString("decision");
-
+
return rawDecision;
}
-
-
- public static PolicyGuardResponse ParseXacmlPdpResponse(com.att.research.xacml.api.Response xacmlResponse){
-
- if(xacmlResponse == null){
-
+
+ public static PolicyGuardResponse ParseXacmlPdpResponse(
+ com.att.research.xacml.api.Response xacmlResponse) {
+
+ if (xacmlResponse == null) {
+
//
- //In case the actual XACML response was null, create an empty response object with decision "Indeterminate"
+ // In case the actual XACML response was null, create an empty
+ // response object with decision "Indeterminate"
//
return new PolicyGuardResponse("Indeterminate", null, "");
}
-
+
Iterator<Result> it_res = xacmlResponse.getResults().iterator();
-
- Result res = it_res.next();
+
+ Result res = it_res.next();
String decision_from_xacml_response = res.getDecision().toString();
- Iterator<AttributeCategory> it_attr_cat = res.getAttributes().iterator();
+ Iterator<AttributeCategory> it_attr_cat = res.getAttributes()
+ .iterator();
UUID req_id_from_xacml_response = null;
String operation_from_xacml_response = "";
-
- while(it_attr_cat.hasNext()){
- Iterator<Attribute> it_attr = it_attr_cat.next().getAttributes().iterator();
- while(it_attr.hasNext()){
+
+ while (it_attr_cat.hasNext()) {
+ Iterator<Attribute> it_attr = it_attr_cat.next().getAttributes()
+ .iterator();
+ while (it_attr.hasNext()) {
Attribute current_attr = it_attr.next();
String s = current_attr.getAttributeId().stringValue();
- if(s.equals("urn:oasis:names:tc:xacml:1.0:request:request-id")){
- Iterator<AttributeValue<?>> it_values = current_attr.getValues().iterator();
- req_id_from_xacml_response = UUID.fromString(it_values.next().getValue().toString());
+ if ("urn:oasis:names:tc:xacml:1.0:request:request-id".equals(s)) {
+ Iterator<AttributeValue<?>> it_values = current_attr
+ .getValues().iterator();
+ req_id_from_xacml_response = UUID.fromString(it_values
+ .next().getValue().toString());
}
- if(s.equals("urn:oasis:names:tc:xacml:1.0:operation:operation-id")){
- Iterator<AttributeValue<?>> it_values = current_attr.getValues().iterator();
- operation_from_xacml_response = it_values.next().getValue().toString();
+ if ("urn:oasis:names:tc:xacml:1.0:operation:operation-id"
+ .equals(s)) {
+ Iterator<AttributeValue<?>> it_values = current_attr
+ .getValues().iterator();
+ operation_from_xacml_response = it_values.next().getValue()
+ .toString();
}
-
+
}
}
-
-
- return new PolicyGuardResponse(decision_from_xacml_response, req_id_from_xacml_response, operation_from_xacml_response);
-
+
+ return new PolicyGuardResponse(decision_from_xacml_response,
+ req_id_from_xacml_response, operation_from_xacml_response);
+
+ }
+
+ private void init(Properties properties) {
+ // used to store error messages
+ StringBuilder sb = new StringBuilder();
+
+ // fetch these parameters, if they exist
+ String timeoutString = properties.getProperty("pdpx.timeout");
+ String disabledString = properties.getProperty("guard.disabled");
+
+ if (disabledString != null) {
+ // decode optional 'guard.disabled' parameter
+ disabled = new Boolean(disabledString);
+ if (disabled) {
+ // skip everything else
+ return;
+ }
+ }
+
+ /*
+ * Decode 'pdpx.*' parameters
+ */
+
+ // first, the default parameters
+ String defaultUser = properties.getProperty("pdpx.username");
+ String defaultPassword = properties
+ .getProperty("pdpx.password");
+ String defaultClientUser = properties
+ .getProperty("pdpx.client.username");
+ String defaultClientPassword = properties
+ .getProperty("pdpx.client.password");
+ String defaultEnvironment = properties
+ .getProperty("pdpx.environment");
+
+ // now, see which numeric entries (1-9) exist
+ ArrayList<URLEntry> entries = new ArrayList<>();
+
+ for (int index = 0; index < 10; index += 1) {
+ String urlPrefix = "guard.";
+ String pdpxPrefix = "pdpx.";
+ if (index != 0) {
+ urlPrefix = urlPrefix + index + ".";
+ }
+
+ // see if the associated URL exists
+ String restURLlist = properties.getProperty(urlPrefix + "url");
+ if (nullOrEmpty(restURLlist)) {
+ // no entry for this index
+ continue;
+ }
+
+ // support a list of entries separated by semicolons. Each entry
+ // can be:
+ // URL
+ // URL,user
+ // URL,user,password
+ for (String restURL : restURLlist.split("\\s*;\\s*")) {
+ String[] segments = restURL.split("\\s*,\\s*");
+ String user = null;
+ String password = null;
+
+ if (segments.length >= 2) {
+ // user id is provided
+ restURL = segments[0];
+ user = segments[1];
+ if (segments.length >= 3) {
+ // password is also provided
+ password = segments[2];
+ }
+ }
+
+ // URL does exist -- create the entry
+ URLEntry urlEntry = new URLEntry();
+ try {
+ urlEntry.restURL = new URL(restURL);
+ } catch (java.net.MalformedURLException e) {
+ // if we don't have a URL,
+ // don't bother with the rest on this one
+ sb.append("'").append(urlPrefix).append("url' '")
+ .append(restURL).append("': ").append(e)
+ .append(",");
+ continue;
+ }
+
+ if (nullOrEmpty(user)) {
+ // user id was not provided on '*.url' line --
+ // extract it from a separate property
+ user = properties.getProperty(pdpxPrefix + "username", defaultUser);
+ }
+ if (nullOrEmpty(password)) {
+ // password was not provided on '*.url' line --
+ // extract it from a separate property
+ password = properties.getProperty(pdpxPrefix + "password",
+ defaultPassword);
+ }
+
+ // see if 'user' and 'password' entries both exist
+ if (!nullOrEmpty(user) && !nullOrEmpty(password)) {
+ urlEntry.authorization = "Basic "
+ + Base64.getEncoder().encodeToString(
+ (user + ":" + password).getBytes());
+ }
+
+ // see if 'client.user' and 'client.password' entries both exist
+ String clientUser = properties.getProperty(pdpxPrefix
+ + "client.username", defaultClientUser);
+ String clientPassword = properties.getProperty(pdpxPrefix
+ + "client.password", defaultClientPassword);
+ if (!nullOrEmpty(clientUser) && !nullOrEmpty(clientPassword)) {
+ urlEntry.clientAuth = "Basic "
+ + Base64.getEncoder().encodeToString(
+ (clientUser + ":" + clientPassword)
+ .getBytes());
+ }
+
+ // see if there is an 'environment' entry
+ String environment = properties.getProperty(pdpxPrefix
+ + "environment", defaultEnvironment);
+ if (!nullOrEmpty(environment)) {
+ urlEntry.environment = environment;
+ }
+
+ // include this URLEntry in the list
+ entries.add(urlEntry);
+ }
+ }
+
+ if (entries.size() == 0) {
+ sb.append("'pdpx.*' -- no URLs specified, ");
+ } else {
+ restUrls = entries.toArray(new URLEntry[0]);
+ }
+
+ if (timeoutString != null) {
+ try {
+ // decode optional 'pdpx.timeout' parameter
+ timeout = Integer.valueOf(timeoutString);
+ } catch (NumberFormatException e) {
+ sb.append("'pdpx.timeout': " + e + ", ");
+ logger.trace(e.getLocalizedMessage());
+ }
+ }
+
+
+ // if there are any errors, update 'errorMessage' & disable guard
+ // queries
+ if (sb.length() != 0) {
+ // remove the terminating ", ", and extract resulting error message
+ sb.setLength(sb.length() - 2);
+ errorMessage = sb.toString();
+ disabled = true;
+ logger.error("Initialization failure: " + errorMessage);
+ }
+ }
+
+ /**
+ * Check if a string is null or an empty string
+ *
+ * @param value
+ * the string to be tested
+ * @return 'true' if the string is 'null' or has a length of 0, 'false'
+ * otherwise
+ */
+ static private boolean nullOrEmpty(String value) {
+ return (value == null || value.isEmpty());
}
-
-
-
+
}
diff --git a/controlloop/common/guard/src/main/java/org/onap/policy/guard/Util.java b/controlloop/common/guard/src/main/java/org/onap/policy/guard/Util.java
index b594aff0a..f572cd7fa 100644
--- a/controlloop/common/guard/src/main/java/org/onap/policy/guard/Util.java
+++ b/controlloop/common/guard/src/main/java/org/onap/policy/guard/Util.java
@@ -31,12 +31,31 @@ import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.onap.policy.controlloop.policy.ControlLoopPolicy;
import org.onap.policy.controlloop.policy.guard.ControlLoopGuard;
+import org.onap.policy.drools.system.PolicyEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
public final class Util {
+
+ /*
+ * Keys for guard properties
+ */
+ public static final String PROP_GUARD_URL = "guard.url";
+ public static final String PROP_GUARD_USER = "pdpx.username";
+ public static final String PROP_GUARD_PASS = "pdpx.password";
+ public static final String PROP_GUARD_CLIENT_USER = "pdpx.client.username";
+ public static final String PROP_GUARD_CLIENT_PASS = "pdpx.client.password";
+ public static final String PROP_GUARD_ENV = "pdpx.environment";
+
+ /*
+ * Guard responses
+ */
+ public static final String INDETERMINATE = "Indeterminate";
+ public static final String PERMIT = "Permit";
+ public static final String DENY = "Deny";
+
private static final Logger logger = LoggerFactory.getLogger(Util.class);
public static class Pair<A, B> {
@@ -83,5 +102,26 @@ public final class Util {
}
return null;
}
+
+ /**
+ * Sets Guard Properties.
+ *
+ * @see /guard/src/test/java/org/onap/policy/guard/UtilTest.java
+ * for setting test properties
+ */
+ public static void setGuardEnvProps(String url, String username, String password, String clientName, String clientPassword, String environment){
+ PolicyEngine.manager.setEnvironmentProperty(org.onap.policy.guard.Util.PROP_GUARD_URL, url);
+ PolicyEngine.manager.setEnvironmentProperty(org.onap.policy.guard.Util.PROP_GUARD_USER, username);
+ PolicyEngine.manager.setEnvironmentProperty(org.onap.policy.guard.Util.PROP_GUARD_PASS, password);
+ PolicyEngine.manager.setEnvironmentProperty(org.onap.policy.guard.Util.PROP_GUARD_CLIENT_USER, clientName);
+ PolicyEngine.manager.setEnvironmentProperty(org.onap.policy.guard.Util.PROP_GUARD_CLIENT_PASS, clientPassword);
+ PolicyEngine.manager.setEnvironmentProperty(org.onap.policy.guard.Util.PROP_GUARD_ENV, environment);
+ }
+ public static void setGuardEnvProp(String key, String value){
+ PolicyEngine.manager.setEnvironmentProperty(key, value);
+ }
+ public static String getGuardProp(String propName){
+ return PolicyEngine.manager.getEnvironmentProperty(propName);
+ }
}