37c4e4c68b626c1049646e7936eb8c2e65315535
[policy/drools-applications.git] / controlloop / common / guard / src / main / java / org / onap / policy / guard / PipEngineGetHistory.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * guard
4  * ================================================================================
5  * Copyright (C) 2017-2018 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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.policy.guard;
22
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.pip.PIPException;
27 import com.att.research.xacml.api.pip.PIPFinder;
28 import com.att.research.xacml.api.pip.PIPRequest;
29 import com.att.research.xacml.api.pip.PIPResponse;
30 import com.att.research.xacml.std.IdentifierImpl;
31 import com.att.research.xacml.std.StdMutableAttribute;
32 import com.att.research.xacml.std.datatypes.DataTypes;
33 import com.att.research.xacml.std.pip.StdMutablePIPResponse;
34 import com.att.research.xacml.std.pip.StdPIPRequest;
35 import com.att.research.xacml.std.pip.StdPIPResponse;
36 import com.att.research.xacml.std.pip.engines.StdConfigurableEngine;
37
38 import java.math.BigInteger;
39 import java.sql.Timestamp;
40 import java.util.Collection;
41 import java.util.Collections;
42 import java.util.Date;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.Properties;
46 import java.util.Set;
47
48 import javax.persistence.EntityManager;
49 import javax.persistence.NoResultException;
50 import javax.persistence.NonUniqueResultException;
51 import javax.persistence.Persistence;
52 import javax.persistence.Query;
53
54 import org.onap.policy.drools.system.PolicyEngine;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 public class PipEngineGetHistory extends StdConfigurableEngine {
59     private static final Logger logger = LoggerFactory.getLogger(PipEngineGetHistory.class);
60
61     //
62     // Base issuer string. The issuer in the policy will also contain time window information
63     // E.g., "com:att:research:xacml:guard:historydb:tw:10:min"
64     //
65     public static final String DEFAULT_ISSUER = "com:att:research:xacml:guard:historydb";
66     public static final String DEFAULT_DESCRIPTION = "PIP for retrieving Operations History from DB";
67
68     private static final String XML_SCHEMA_STRING = "http://www.w3.org/2001/XMLSchema#string";
69
70     private static final String XACML_SUBJECT_CATEGORY_ACCESS_SUBJECT =
71             "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject";
72     private static final String XACML_ACTOR_ACTOR_ID = "urn:oasis:names:tc:xacml:1.0:actor:actor-id";
73     private static final String XACML_ATTRIBUTE_CATEGORY_ACTION =
74             "urn:oasis:names:tc:xacml:3.0:attribute-category:action";
75     private static final String XACML_OPERATION_OPERATION_ID = "urn:oasis:names:tc:xacml:1.0:operation:operation-id";
76     private static final String XACML_ATTRIBUTE_CATEGORY_RESOURCE =
77             "urn:oasis:names:tc:xacml:3.0:attribute-category:resource";
78     private static final String XACML_TARGET_TARGET_ID = "urn:oasis:names:tc:xacml:1.0:target:target-id";
79     private static final String XACML_TEST_SQL_RESOURCE_OPERATIONS_COUNT =
80             "com:att:research:xacml:test:sql:resource:operations:count";
81
82     private static final PIPRequest PIP_REQUEST_ACTOR =
83             new StdPIPRequest(new IdentifierImpl(XACML_SUBJECT_CATEGORY_ACCESS_SUBJECT),
84                     new IdentifierImpl(XACML_ACTOR_ACTOR_ID), new IdentifierImpl(XML_SCHEMA_STRING));
85
86     private static final PIPRequest PIP_REQUEST_RECIPE =
87             new StdPIPRequest(new IdentifierImpl(XACML_ATTRIBUTE_CATEGORY_ACTION),
88                     new IdentifierImpl(XACML_OPERATION_OPERATION_ID), new IdentifierImpl(XML_SCHEMA_STRING));
89
90     private static final PIPRequest PIP_REQUEST_TARGET =
91             new StdPIPRequest(new IdentifierImpl(XACML_ATTRIBUTE_CATEGORY_RESOURCE),
92                     new IdentifierImpl(XACML_TARGET_TARGET_ID), new IdentifierImpl(XML_SCHEMA_STRING));
93
94     public PipEngineGetHistory() {
95         super();
96     }
97
98     @Override
99     public Collection<PIPRequest> attributesRequired() {
100         return Collections.emptySet();
101     }
102
103     @Override
104     public Collection<PIPRequest> attributesProvided() {
105         return Collections.emptySet();
106     }
107
108     @Override
109     public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
110         logger.debug("Entering FeqLimiter PIP");
111
112         /*
113          * First check to see if the issuer is set and then match it
114          */
115         String string;
116         if ((string = pipRequest.getIssuer()) == null) {
117
118             logger.debug("No issuer in the request...");
119             logger.debug("FeqLimiter PIP - No issuer in the request!");
120             return StdPIPResponse.PIP_RESPONSE_EMPTY;
121         } else {
122             // Notice, we are checking here for the base issuer prefix.
123             if (!string.contains(this.getIssuer())) {
124                 logger.debug("Requested issuer '{}' does not match {}", string, getIssuer());
125                 logger.debug("FeqLimiter PIP - Issuer {}  does not match with: {}", string, this.getIssuer());
126                 return StdPIPResponse.PIP_RESPONSE_EMPTY;
127             }
128         }
129
130         String[] s1 = string.split("tw:");
131         String[] s2 = s1[1].split(":");
132         String timeWindowVal = s2[0];// number [of minutes, hours, days...]
133         String timeWindowScale = s2[1];// e.g., minute, hour, day, week, month, year
134
135         String actor = null;
136         String operation = null;
137         String target = null;
138         try {
139             actor = getActor(pipFinder).iterator().next();
140             operation = getRecipe(pipFinder).iterator().next();
141             target = getTarget(pipFinder).iterator().next();
142         } catch (Exception e) {
143             logger.debug("could not retrieve actor, operation, or target from PIP finder", e);
144             return StdPIPResponse.PIP_RESPONSE_EMPTY;
145         }
146
147         String timeWindow = timeWindowVal + " " + timeWindowScale;
148
149         logger.debug("Going to query DB about: {} {} {} {}", actor, operation, target, timeWindow);
150         int countFromDb = getCountFromDb(actor, operation, target, timeWindow);
151
152         StdMutablePIPResponse stdPipResponse = new StdMutablePIPResponse();
153
154         this.addIntegerAttribute(stdPipResponse, new IdentifierImpl(XACML_ATTRIBUTE_CATEGORY_RESOURCE),
155                 new IdentifierImpl(XACML_TEST_SQL_RESOURCE_OPERATIONS_COUNT), countFromDb, pipRequest);
156
157         return new StdPIPResponse(stdPipResponse);
158     }
159
160     @Override
161     public void configure(String id, Properties properties) throws PIPException {
162         super.configure(id, properties);
163
164         if (this.getDescription() == null) {
165             this.setDescription(DEFAULT_DESCRIPTION);
166         }
167         if (this.getIssuer() == null) {
168             this.setIssuer(DEFAULT_ISSUER);
169         }
170     }
171
172     private PIPResponse getAttribute(PIPRequest pipRequest, PIPFinder pipFinder) {
173         PIPResponse pipResponse = null;
174
175         try {
176             pipResponse = pipFinder.getMatchingAttributes(pipRequest, this);
177         } catch (PIPException ex) {
178             logger.error("getAttribute threw:", ex);
179             return null;
180         }
181         if (pipResponse == null) {
182             return null;
183         }
184         if (pipResponse.getStatus() != null && !pipResponse.getStatus().isOk()) {
185             if (logger.isWarnEnabled()) {
186                 logger.warn("PIP response error {}: {}", pipRequest.getAttributeId().stringValue(),
187                         pipResponse.getStatus());
188             }
189             return null;
190         }
191         if (pipResponse.getAttributes() != null && pipResponse.getAttributes().isEmpty()) {
192             if (logger.isWarnEnabled()) {
193                 logger.warn("No attributes in POP response {}: {}", pipRequest.getAttributeId().stringValue(),
194                         pipResponse.getStatus());
195             }
196             return null;
197         }
198         return pipResponse;
199     }
200
201     private Set<String> getActor(PIPFinder pipFinder) {
202         /*
203          * Get the AT&T UID from either the subject id or the attuid property
204          */
205         PIPResponse pipResponseAttUid = this.getAttribute(PIP_REQUEST_ACTOR, pipFinder);
206         if (pipResponseAttUid == null) {
207             return new HashSet<>();
208         }
209
210         /*
211          * Iterate over all of the returned results and do the LDAP requests
212          */
213         Collection<Attribute> listAttUids = pipResponseAttUid.getAttributes();
214         Set<String> setAttUids = new HashSet<>();
215         for (Attribute attributeAttUid : listAttUids) {
216             Iterator<AttributeValue<String>> iterAttributeValues = attributeAttUid.findValues(DataTypes.DT_STRING);
217             if (iterAttributeValues != null) {
218                 while (iterAttributeValues.hasNext()) {
219                     String attuid = iterAttributeValues.next().getValue();
220                     if (attuid != null) {
221                         setAttUids.add(attuid);
222                     }
223                 }
224             }
225         }
226
227         return setAttUids;
228     }
229
230     private Set<String> getRecipe(PIPFinder pipFinder) {
231         /*
232          * Get the AT&T UID from either the subject id or the attuid property
233          */
234         PIPResponse pipResponseAttUid = this.getAttribute(PIP_REQUEST_RECIPE, pipFinder);
235         if (pipResponseAttUid == null) {
236             return new HashSet<>();
237         }
238
239         /*
240          * Iterate over all of the returned results and do the LDAP requests
241          */
242         Collection<Attribute> listAttUids = pipResponseAttUid.getAttributes();
243         Set<String> setAttUids = new HashSet<>();
244         for (Attribute attributeAttUid : listAttUids) {
245             Iterator<AttributeValue<String>> iterAttributeValues = attributeAttUid.findValues(DataTypes.DT_STRING);
246             if (iterAttributeValues != null) {
247                 while (iterAttributeValues.hasNext()) {
248                     String attuid = iterAttributeValues.next().getValue();
249                     if (attuid != null) {
250                         setAttUids.add(attuid);
251                     }
252                 }
253             }
254         }
255
256         return setAttUids;
257     }
258
259     private void addIntegerAttribute(StdMutablePIPResponse stdPipResponse, Identifier category, Identifier attributeId,
260             int value, PIPRequest pipRequest) {
261         AttributeValue<BigInteger> attributeValue = null;
262         try {
263             attributeValue = DataTypes.DT_INTEGER.createAttributeValue(value);
264         } catch (Exception ex) {
265             logger.error("Failed to convert {} to an AttributeValue<Boolean>", value, ex);
266         }
267         if (attributeValue != null) {
268             stdPipResponse.addAttribute(new StdMutableAttribute(category, attributeId, attributeValue,
269                     pipRequest.getIssuer()/* this.getIssuer() */, false));
270         }
271     }
272
273     private Set<String> getTarget(PIPFinder pipFinder) {
274         /*
275          * Get the AT&T UID from either the subject id or the attuid property
276          */
277         PIPResponse pipResponseAttUid = this.getAttribute(PIP_REQUEST_TARGET, pipFinder);
278         if (pipResponseAttUid == null) {
279             return new HashSet<>();
280         }
281
282         /*
283          * Iterate over all of the returned results and do the LDAP requests
284          */
285         Collection<Attribute> listAttUids = pipResponseAttUid.getAttributes();
286         Set<String> setAttUids = new HashSet<>();
287         for (Attribute attributeAttUid : listAttUids) {
288             Iterator<AttributeValue<String>> iterAttributeValues = attributeAttUid.findValues(DataTypes.DT_STRING);
289             if (iterAttributeValues != null) {
290                 while (iterAttributeValues.hasNext()) {
291                     String attuid = iterAttributeValues.next().getValue();
292                     if (attuid != null) {
293                         setAttUids.add(attuid);
294                     }
295                 }
296             }
297         }
298
299         return setAttUids;
300     }
301
302     private static int getCountFromDb(String actor, String operation, String target, String timeWindow) {
303         // DB Properties
304         Properties props = new Properties();
305         props.put(Util.ECLIPSE_LINK_KEY_URL, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL));
306         props.put(Util.ECLIPSE_LINK_KEY_USER, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER));
307         props.put(Util.ECLIPSE_LINK_KEY_PASS, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS));
308
309
310         EntityManager em = null;
311         String opsHistPu = System.getProperty("OperationsHistoryPU");
312         if (!"TestOperationsHistoryPU".equals(opsHistPu)) {
313             opsHistPu = "OperationsHistoryPU";
314         } else {
315             props.clear();
316         }
317
318         try {
319             em = Persistence.createEntityManagerFactory(opsHistPu, props).createEntityManager();
320         } catch (Exception ex) {
321             logger.error("PIP thread got Exception. Can't connect to Operations History DB -- {}", opsHistPu);
322             logger.error("getCountFromDb threw: ", ex);
323             return -1;
324         }
325
326         long now = new Date().getTime();
327         long diff;
328         try {
329             diff = now - getMsFromTimeWindow(timeWindow);
330         } catch (Exception ex) {
331             logger.error("PIP thread got Exception ", ex);
332             return -1;
333         }
334
335         StringBuilder sqlBuilder = new StringBuilder();
336         sqlBuilder.append("select count(*) as count from operationshistory10 where outcome<>'Failure_Guard'");
337         sqlBuilder.append(" and actor= ?");
338         sqlBuilder.append(" and operation= ?");
339         sqlBuilder.append(" and target= ?");
340         sqlBuilder.append(" and endtime between '");
341         sqlBuilder.append(new Timestamp(diff));
342         sqlBuilder.append("' and '");
343         sqlBuilder.append(new Timestamp(now));
344         sqlBuilder.append('\'');
345
346         Query nq = em.createNativeQuery(sqlBuilder.toString());
347         nq.setParameter(1, actor);
348         nq.setParameter(2, operation);
349         nq.setParameter(3, target);
350
351         int ret = -1;
352         try {
353             ret = ((Number) nq.getSingleResult()).intValue();
354         } catch (NoResultException | NonUniqueResultException ex) {
355             logger.error("getCountFromDb threw: ", ex);
356             return -1;
357         }
358
359         em.close();
360
361         return ret;
362     }
363
364     /**
365      * Get the Millisecond time from a time window string.
366      * 
367      * @param timeWindow the time window string to parse
368      * @return the millisecond time from the time window string
369      * @throws PIPException On invalid time window strings
370      */
371     private static long getMsFromTimeWindow(String timeWindowString) throws PIPException {
372         long ms = 0;
373         double multiplier = 0;
374
375         String[] split = timeWindowString.split(" ");
376         if (split.length != 2) {
377             throw new PIPException("Invalid Value Unit pair for SQL");
378         }
379
380         ms = Long.parseLong(split[0]);
381
382         if ("SECOND".compareToIgnoreCase(split[1]) == 0) {
383             multiplier = 1000;
384         } else if ("MINUTE".compareToIgnoreCase(split[1]) == 0) {
385             multiplier = 60000;
386         } else if ("HOUR".compareToIgnoreCase(split[1]) == 0) {
387             multiplier = 3.6e+6;
388         } else if ("DAY".compareToIgnoreCase(split[1]) == 0) {
389             multiplier = 8.64e+7;
390         } else if ("WEEK".compareToIgnoreCase(split[1]) == 0) {
391             multiplier = 6.048e+8;
392         } else if ("MONTH".compareToIgnoreCase(split[1]) == 0) {
393             multiplier = 2.628e+9;
394         } else if ("QUARTER".compareToIgnoreCase(split[1]) == 0) {
395             multiplier = 2.628e+9 * 3;
396         } else if ("YEAR".compareToIgnoreCase(split[1]) == 0) {
397             multiplier = 3.154e+10;
398         } else {
399             logger.error("{} not supported", split[1]);
400         }
401
402         ms *= multiplier;
403         return ms;
404     }
405 }