2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2019 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.onap.policy.xacml.std.pip.engines;
23 import com.att.research.xacml.api.Attribute;
24 import com.att.research.xacml.api.AttributeValue;
25 import com.att.research.xacml.api.Identifier;
26 import com.att.research.xacml.api.XACML;
27 import com.att.research.xacml.api.XACML3;
28 import com.att.research.xacml.api.pip.PIPException;
29 import com.att.research.xacml.api.pip.PIPFinder;
30 import com.att.research.xacml.api.pip.PIPRequest;
31 import com.att.research.xacml.api.pip.PIPResponse;
32 import com.att.research.xacml.std.IdentifierImpl;
33 import com.att.research.xacml.std.StdMutableAttribute;
34 import com.att.research.xacml.std.datatypes.DataTypes;
35 import com.att.research.xacml.std.pip.StdMutablePIPResponse;
36 import com.att.research.xacml.std.pip.StdPIPRequest;
37 import com.att.research.xacml.std.pip.StdPIPResponse;
38 import com.att.research.xacml.std.pip.engines.StdConfigurableEngine;
39 import com.att.research.xacml.util.XACMLProperties;
41 import java.math.BigInteger;
42 import java.util.ArrayList;
43 import java.util.Collection;
44 import java.util.HashSet;
45 import java.util.Iterator;
46 import java.util.Properties;
49 import javax.persistence.EntityManager;
50 import javax.persistence.Persistence;
51 import javax.persistence.Query;
53 import org.eclipse.persistence.config.PersistenceUnitProperties;
54 import org.onap.policy.common.logging.flexlogger.FlexLogger;
55 import org.onap.policy.common.logging.flexlogger.Logger;
58 * PIP Engine for Implementing {@link com.att.research.xacml.std.pip.engines.ConfigurableEngine} interface to provide
59 * attribute retrieval from Operation History Table.
63 public class OperationHistoryEngine extends StdConfigurableEngine {
64 public static final String DEFAULT_DESCRIPTION = "PIP for retrieving Operations History from DB";
65 public static final String DEFAULT_ISSUER = "org:onap:xacml:guard:historydb";
67 private static final Logger LOGGER = FlexLogger.getLogger(OperationHistoryEngine.class);
69 private static final PIPRequest PIP_REQUEST_ACTOR = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
70 new IdentifierImpl("actor"), XACML.ID_DATATYPE_STRING);
72 private static final PIPRequest PIP_REQUEST_RECIPE = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
73 new IdentifierImpl("recipe"), XACML.ID_DATATYPE_STRING);
75 private static final PIPRequest PIP_REQUEST_TARGET = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
76 new IdentifierImpl("target"), XACML.ID_DATATYPE_STRING);
78 public OperationHistoryEngine() {
82 private void addIntegerAttribute(StdMutablePIPResponse stdPipResponse, Identifier category, Identifier attributeId,
83 int value, PIPRequest pipRequest) {
84 AttributeValue<BigInteger> attributeValue = null;
86 attributeValue = DataTypes.DT_INTEGER.createAttributeValue(value);
87 } catch (Exception ex) {
88 LOGGER.error("Failed to convert " + value + " to an AttributeValue<Boolean>", ex);
90 if (attributeValue != null) {
91 stdPipResponse.addAttribute(new StdMutableAttribute(category, attributeId, attributeValue,
92 pipRequest.getIssuer()/* this.getIssuer() */, false));
97 public Collection<PIPRequest> attributesRequired() {
98 return new ArrayList<>();
102 public Collection<PIPRequest> attributesProvided() {
103 return new ArrayList<>();
107 public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
108 LOGGER.info("Entering FeqLimiter PIP");
110 * First check to see if the issuer is set and then match it
113 if ((string = pipRequest.getIssuer()) == null) {
114 LOGGER.info("FeqLimiter PIP - No issuer in the request!");
115 return StdPIPResponse.PIP_RESPONSE_EMPTY;
117 // Notice, we are checking here for the base issuer prefix.
118 if (!string.contains(this.getIssuer())) {
119 LOGGER.debug("Requested issuer '" + string + "' does not match "
120 + (this.getIssuer() == null ? "null" : "'" + this.getIssuer() + "'"));
121 LOGGER.info("FeqLimiter PIP - Issuer " + string + " does not match with: " + this.getIssuer());
122 return StdPIPResponse.PIP_RESPONSE_EMPTY;
125 String[] s1 = string.split("tw:");
126 String[] s2 = s1[1].split(":");
127 int timeWindowVal = Integer.parseInt(s2[0]);// number [of minutes, hours, days...]
128 String timeWindowScale = s2[1];// e.g., minute, hour, day, week, month, year
129 String actor = getActor(pipFinder).iterator().next();
130 String operation = getRecipe(pipFinder).iterator().next();
131 String target = getTarget(pipFinder).iterator().next();
132 String timeWindow = timeWindowVal + " " + timeWindowScale;
133 LOGGER.info("Going to query DB about: " + actor + " " + operation + " " + target + " " + timeWindow);
134 int countFromDB = getCountFromDB(actor, operation, target, timeWindowVal, timeWindowScale);
135 StdMutablePIPResponse stdPipResponse = new StdMutablePIPResponse();
136 this.addIntegerAttribute(stdPipResponse, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, new IdentifierImpl("count"),
137 countFromDB, pipRequest);
138 return new StdPIPResponse(stdPipResponse);
142 public void configure(String id, Properties properties) throws PIPException {
143 super.configure(id, properties);
144 if (this.getDescription() == null) {
145 this.setDescription(DEFAULT_DESCRIPTION);
147 if (this.getIssuer() == null) {
148 this.setIssuer(DEFAULT_ISSUER);
152 private PIPResponse getAttribute(PIPRequest pipRequest, PIPFinder pipFinder) {
153 PIPResponse pipResponse = null;
155 pipResponse = pipFinder.getMatchingAttributes(pipRequest, this);
156 if (pipResponse.getStatus() != null && !pipResponse.getStatus().isOk()) {
157 LOGGER.info("Error retrieving " + pipRequest.getAttributeId().stringValue() + ": "
158 + pipResponse.getStatus().toString());
161 if (pipResponse != null && pipResponse.getAttributes().isEmpty()) {
162 LOGGER.info("No value for " + pipRequest.getAttributeId().stringValue());
165 } catch (PIPException ex) {
166 LOGGER.error("PIPException getting subject-id attribute: " + ex.getMessage(), ex);
171 private Set<String> getActor(PIPFinder pipFinder) {
172 return getUuids(this.getAttribute(PIP_REQUEST_ACTOR, pipFinder));
175 private Set<String> getRecipe(PIPFinder pipFinder) {
176 return getUuids(this.getAttribute(PIP_REQUEST_RECIPE, pipFinder));
179 private Set<String> getTarget(PIPFinder pipFinder) {
180 return getUuids(this.getAttribute(PIP_REQUEST_TARGET, pipFinder));
183 private Set<String> getUuids(PIPResponse pipResponseAttUid) {
185 * Get the UID from either the subject id or the attuid property
187 if (pipResponseAttUid == null) {
188 return new HashSet<>();
191 * Iterate over all of the returned results and do the LDAP requests
193 Set<String> setAttUids = new HashSet<>();
194 for (Attribute attributeAttUid : pipResponseAttUid.getAttributes()) {
195 Iterator<AttributeValue<String>> iterAttributeValues = attributeAttUid.findValues(DataTypes.DT_STRING);
196 if (iterAttributeValues != null) {
197 while (iterAttributeValues.hasNext()) {
198 String attuid = iterAttributeValues.next().getValue();
199 if (attuid != null) {
200 setAttUids.add(attuid);
208 private static int getCountFromDB(String actor, String operation, String target, int timeWindow, String timeUnits) {
211 Properties properties = XACMLProperties.getProperties();
212 properties.setProperty(PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML,
213 "META-INF/operationHistoryPU.xml");
214 em = Persistence.createEntityManagerFactory("OperationsHistoryPU", properties).createEntityManager();
215 } catch (Exception e) {
217 "Test thread got Exception " + e.getLocalizedMessage() + " Can't connect to Operations History DB.",
221 // Preventing SQL injection
222 if (!validTimeUnits(timeUnits)) {
223 LOGGER.error("given PIP timeUnits is not valid. " + timeUnits);
227 String sql = "select count(*) as count from operationshistory10 where outcome<>'Failure_Guard' and actor=?"
228 + " and operation=?" + " and target=?" + " and endtime between date_sub(now(),interval ? " + timeUnits
230 Query nq = em.createNativeQuery(sql);
231 nq.setParameter(1, actor);
232 nq.setParameter(2, operation);
233 nq.setParameter(3, target);
234 nq.setParameter(4, timeWindow);
235 int ret = ((Number) nq.getSingleResult()).intValue();
236 LOGGER.info("###########************** History count: " + ret);
241 // Validating Time Units to prevent SQL Injection.
242 private static boolean validTimeUnits(String timeUnits) {
243 return ("minute".equalsIgnoreCase(timeUnits) || "hour".equalsIgnoreCase(timeUnits)
244 || "day".equalsIgnoreCase(timeUnits) || "week".equalsIgnoreCase(timeUnits)
245 || "month".equalsIgnoreCase(timeUnits) || "year".equalsIgnoreCase(timeUnits)) ? true : false;