Unit/SONAR/Checkstyle in ONAP-REST
[policy/engine.git] / ONAP-XACML / src / main / java / org / onap / policy / xacml / std / pip / engines / OperationHistoryEngine.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-XACML
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.xacml.std.pip.engines;
22
23 import java.math.BigInteger;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.Properties;
29 import java.util.Set;
30
31 import javax.persistence.EntityManager;
32 import javax.persistence.Persistence;
33 import javax.persistence.Query;
34
35 import org.eclipse.persistence.config.PersistenceUnitProperties;
36 import org.onap.policy.common.logging.flexlogger.FlexLogger;
37 import org.onap.policy.common.logging.flexlogger.Logger;
38
39 import com.att.research.xacml.api.Attribute;
40 import com.att.research.xacml.api.AttributeValue;
41 import com.att.research.xacml.api.Identifier;
42 import com.att.research.xacml.api.XACML;
43 import com.att.research.xacml.api.XACML3;
44 import com.att.research.xacml.api.pip.PIPException;
45 import com.att.research.xacml.api.pip.PIPFinder;
46 import com.att.research.xacml.api.pip.PIPRequest;
47 import com.att.research.xacml.api.pip.PIPResponse;
48 import com.att.research.xacml.std.IdentifierImpl;
49 import com.att.research.xacml.std.StdMutableAttribute;
50 import com.att.research.xacml.std.datatypes.DataTypes;
51 import com.att.research.xacml.std.pip.StdMutablePIPResponse;
52 import com.att.research.xacml.std.pip.StdPIPRequest;
53 import com.att.research.xacml.std.pip.StdPIPResponse;
54 import com.att.research.xacml.std.pip.engines.StdConfigurableEngine;
55 import com.att.research.xacml.util.XACMLProperties;
56
57 /**
58  * PIP Engine for Implementing {@link com.att.research.xacml.std.pip.engines.ConfigurableEngine} interface to provide
59  * attribute retrieval from Operation History Table.  
60  * 
61  * @version $Revision$
62  */
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";
66         
67         private static final Logger LOGGER= FlexLogger.getLogger(OperationHistoryEngine.class);
68         
69         private static final PIPRequest PIP_REQUEST_ACTOR       = new StdPIPRequest(
70                         XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
71                         new IdentifierImpl("actor"),
72                         XACML.ID_DATATYPE_STRING);
73
74         private static final PIPRequest PIP_REQUEST_RECIPE      = new StdPIPRequest(
75                         XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
76                         new IdentifierImpl("recipe"), 
77                         XACML.ID_DATATYPE_STRING);
78
79         private static final PIPRequest PIP_REQUEST_TARGET      = new StdPIPRequest(
80                         XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
81                         new IdentifierImpl("target"), 
82                         XACML.ID_DATATYPE_STRING);
83         
84         public OperationHistoryEngine() {
85                 super();
86         }
87
88         private void addIntegerAttribute(StdMutablePIPResponse stdPIPResponse, Identifier category, Identifier attributeId, int value, PIPRequest pipRequest) {
89                 AttributeValue<BigInteger> attributeValue       = null;
90                 try {
91                         attributeValue  = DataTypes.DT_INTEGER.createAttributeValue(value);
92                 } catch (Exception ex) {
93                         LOGGER.error("Failed to convert " + value + " to an AttributeValue<Boolean>", ex);
94                 }
95                 if (attributeValue != null) {
96                         stdPIPResponse.addAttribute(new StdMutableAttribute(category, attributeId, attributeValue, pipRequest.getIssuer()/*this.getIssuer()*/, false));
97                 }
98         }
99
100         @Override
101         public Collection<PIPRequest> attributesRequired() {
102                 return new ArrayList<>();
103         }
104
105         @Override
106         public Collection<PIPRequest> attributesProvided() {
107                 return new ArrayList<>();
108         }
109
110         @Override
111         public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
112                 LOGGER.info("Entering FeqLimiter PIP");
113                 /*
114                  * First check to see if the issuer is set and then match it
115                  */
116                 String string;
117                 if ((string = pipRequest.getIssuer()) == null) {
118                         LOGGER.info("FeqLimiter PIP - No issuer in the request!");
119                         return StdPIPResponse.PIP_RESPONSE_EMPTY;
120                 }
121                 else{
122                         //Notice, we are checking here for the base issuer prefix.
123                         if (!string.contains(this.getIssuer())) {
124                                 LOGGER.debug("Requested issuer '" + string + "' does not match " + (this.getIssuer() == null ? "null" : "'" + this.getIssuer() + "'"));
125                                 LOGGER.info("FeqLimiter PIP - Issuer "+ string +" does not match with: "+this.getIssuer());
126                                 return StdPIPResponse.PIP_RESPONSE_EMPTY;
127                         }
128                 }
129                 String[] s1 = string.split("tw:");
130                 String[] s2 = s1[1].split(":");
131                 int timeWindowVal = Integer.parseInt(s2[0]);// number [of minutes, hours, days...]
132                 String timeWindowScale = s2[1];//e.g., minute, hour, day, week, month, year
133                 String actor = getActor(pipFinder).iterator().next();
134                 String operation = getRecipe(pipFinder).iterator().next();
135                 String target = getTarget(pipFinder).iterator().next();
136                 String timeWindow = timeWindowVal + " " + timeWindowScale;
137                 LOGGER.info("Going to query DB about: "+actor + " " + operation + " " + target + " " + timeWindow);
138                 int countFromDB = getCountFromDB(actor, operation, target, timeWindowVal, timeWindowScale);
139                 StdMutablePIPResponse stdPIPResponse    = new StdMutablePIPResponse();
140                 this.addIntegerAttribute(stdPIPResponse,
141                                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
142                                 new IdentifierImpl("count"), 
143                                 countFromDB,
144                                 pipRequest);
145                 return new StdPIPResponse(stdPIPResponse);
146         }
147
148         @Override
149         public void configure(String id, Properties properties) throws PIPException {
150                 super.configure(id, properties);
151                 if (this.getDescription() == null) {
152                         this.setDescription(DEFAULT_DESCRIPTION);
153                 }
154                 if (this.getIssuer() == null) {
155                         this.setIssuer(DEFAULT_ISSUER);
156                 }
157         }
158
159         private PIPResponse getAttribute(PIPRequest pipRequest, PIPFinder pipFinder) {
160                 PIPResponse pipResponse = null;
161                 try {
162                         pipResponse     = pipFinder.getMatchingAttributes(pipRequest, this);
163                         if (pipResponse.getStatus() != null && !pipResponse.getStatus().isOk()) {
164                                 LOGGER.info("Error retrieving " + pipRequest.getAttributeId().stringValue() + ": " + pipResponse.getStatus().toString());
165                                 pipResponse     = null;
166                         }
167                         if (pipResponse!=null && pipResponse.getAttributes().isEmpty()) {
168                                 LOGGER.info("No value for " + pipRequest.getAttributeId().stringValue());
169                                 pipResponse     = null;
170                         }
171                 } catch (PIPException ex) {
172                         LOGGER.error("PIPException getting subject-id attribute: " + ex.getMessage(), ex);                      
173                 }
174                 return pipResponse;
175         }
176
177
178         private Set<String> getActor(PIPFinder pipFinder) {
179                 /*
180                  * Get the AT&T UID from either the subject id or the attuid property
181                  */
182                 PIPResponse pipResponseATTUID   = this.getAttribute(PIP_REQUEST_ACTOR, pipFinder);
183                 if (pipResponseATTUID == null) {
184                         return new HashSet<>();
185                 }
186                 /*
187                  * Iterate over all of the returned results and do the LDAP requests
188                  */
189                 Collection<Attribute> listATTUIDs       = pipResponseATTUID.getAttributes();
190                 Set<String> setATTUIDs                  = new HashSet<>();
191                 for (Attribute attributeATTUID: listATTUIDs) {
192                         Iterator<AttributeValue<String>> iterAttributeValues    = attributeATTUID.findValues(DataTypes.DT_STRING);
193                         if (iterAttributeValues != null) {
194                                 while (iterAttributeValues.hasNext()) {
195                                         String attuid   = iterAttributeValues.next().getValue();
196                                         if (attuid != null) {
197                                                 setATTUIDs.add(attuid);
198                                         }
199                                 }
200                         }
201                 }
202                 return setATTUIDs;
203         }
204
205         private Set<String> getRecipe(PIPFinder pipFinder) {
206                 /*
207                  * Get the AT&T UID from either the subject id or the attuid property
208                  */
209                 PIPResponse pipResponseATTUID   = this.getAttribute(PIP_REQUEST_RECIPE, pipFinder);
210                 if (pipResponseATTUID == null) {
211                         return new HashSet<>();
212                 }
213                 /*
214                  * Iterate over all of the returned results and do the LDAP requests
215                  */
216                 Collection<Attribute> listATTUIDs       = pipResponseATTUID.getAttributes();
217                 Set<String> setATTUIDs                  = new HashSet<>();
218                 for (Attribute attributeATTUID: listATTUIDs) {
219                         Iterator<AttributeValue<String>> iterAttributeValues    = attributeATTUID.findValues(DataTypes.DT_STRING);
220                         if (iterAttributeValues != null) {
221                                 while (iterAttributeValues.hasNext()) {
222                                         String attuid   = iterAttributeValues.next().getValue();
223                                         if (attuid != null) {
224                                                 setATTUIDs.add(attuid);
225                                         }
226                                 }
227                         }
228                 }
229                 return setATTUIDs;
230         }
231
232
233         private Set<String> getTarget(PIPFinder pipFinder) {
234                 /*
235                  * Get the AT&T UID from either the subject id or the attuid property
236                  */
237                 PIPResponse pipResponseATTUID   = this.getAttribute(PIP_REQUEST_TARGET, pipFinder);
238                 if (pipResponseATTUID == null) {
239                         return new HashSet<>();
240                 }
241                 /*
242                  * Iterate over all of the returned results and do the LDAP requests
243                  */
244                 Collection<Attribute> listATTUIDs       = pipResponseATTUID.getAttributes();
245                 Set<String> setATTUIDs                  = new HashSet<>();
246                 for (Attribute attributeATTUID: listATTUIDs) {
247                         Iterator<AttributeValue<String>> iterAttributeValues    = attributeATTUID.findValues(DataTypes.DT_STRING);
248                         if (iterAttributeValues != null) {
249                                 while (iterAttributeValues.hasNext()) {
250                                         String attuid   = iterAttributeValues.next().getValue();
251                                         if (attuid != null) {
252                                                 setATTUIDs.add(attuid);
253                                         }
254                                 }
255                         }
256                 }
257                 return setATTUIDs;
258         }
259
260         private static int getCountFromDB(String actor, String operation, String target, int timeWindow, String timeUnits){
261                 EntityManager em;
262                 try{
263                         Properties properties = XACMLProperties.getProperties();
264                         properties.setProperty(PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML, "META-INF/operationHistoryPU.xml");
265                         em = Persistence.createEntityManagerFactory("OperationsHistoryPU",properties).createEntityManager();
266                 }catch(Exception e){
267                         LOGGER.error("Test thread got Exception " + e.getLocalizedMessage() + " Can't connect to Operations History DB.", e);
268                         return -1;
269                 }
270                 // Preventing SQL injection
271                 if(!validTimeUnits(timeUnits)){
272                         LOGGER.error("given PIP timeUnits is not valid. " + timeUnits);
273                         em.close();
274                         return -1;
275                 }
276                 String sql = "select count(*) as count from operationshistory10 where outcome<>'Failure_Guard' and actor=?"
277                                 + " and operation=?"
278                                 + " and target=?"
279                                 + " and endtime between date_sub(now(),interval ? "+timeUnits+") and now()";
280                 Query nq = em.createNativeQuery(sql);
281                 nq.setParameter(1, actor);
282                 nq.setParameter(2, operation);
283                 nq.setParameter(3, target);
284                 nq.setParameter(4, timeWindow);
285                 int ret = ((Number)nq.getSingleResult()).intValue();
286                 LOGGER.info("###########************** History count: " + ret);
287                 em.close();
288                 return ret;     
289         }
290         
291         // Validating Time Units to prevent SQL Injection. 
292         private static boolean validTimeUnits(String timeUnits) {
293                 return ("minute".equalsIgnoreCase(timeUnits) || "hour".equalsIgnoreCase(timeUnits) || "day".equalsIgnoreCase(timeUnits) 
294                         || "week".equalsIgnoreCase(timeUnits) || "month".equalsIgnoreCase(timeUnits)|| "year".equalsIgnoreCase(timeUnits))?
295                                 true: false;
296         }
297 }