Format ONAP-XACML and add JUnit
[policy/engine.git] / ONAP-XACML / src / main / java / org / onap / policy / xacml / std / pip / engines / aaf / AAFEngine.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-XACML
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
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.aaf;
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.XACML3;
27 import com.att.research.xacml.api.pip.PIPException;
28 import com.att.research.xacml.api.pip.PIPFinder;
29 import com.att.research.xacml.api.pip.PIPRequest;
30 import com.att.research.xacml.api.pip.PIPResponse;
31 import com.att.research.xacml.std.IdentifierImpl;
32 import com.att.research.xacml.std.StdMutableAttribute;
33 import com.att.research.xacml.std.datatypes.DataTypes;
34 import com.att.research.xacml.std.pip.StdMutablePIPResponse;
35 import com.att.research.xacml.std.pip.StdPIPRequest;
36 import com.att.research.xacml.std.pip.StdPIPResponse;
37 import com.att.research.xacml.std.pip.engines.StdConfigurableEngine;
38 import com.att.research.xacml.util.XACMLProperties;
39
40 import java.io.IOException;
41 import java.util.ArrayList;
42 import java.util.Collection;
43 import java.util.HashMap;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Properties;
48
49 import org.apache.commons.logging.Log;
50 import org.apache.commons.logging.LogFactory;
51 import org.onap.policy.utils.AAFPolicyClient;
52 import org.onap.policy.utils.AAFPolicyException;
53
54 /**
55  * PIP Engine for Implementing {@link com.att.research.xacml.std.pip.engines.ConfigurableEngine} interface to provide
56  * attribute retrieval from AAF interface.
57  *
58  * @version $Revision$
59  */
60 public class AAFEngine extends StdConfigurableEngine {
61
62     public static final String DEFAULT_DESCRIPTION =
63             "PIP for authenticating aaf attributes using the AAF REST interface";
64     public static final String DEFAULT_ISSUER = "aaf";
65
66     private static final String SUCCESS = "Success";
67
68     public static final String AAF_RESULT = "AAF_RESULT";
69     public static final String AAF_RESPONSE = "AAF_RESPONSE";
70     //
71     public static final Identifier AAF_RESPONSE_ID = new IdentifierImpl(AAF_RESPONSE);
72     public static final Identifier AAF_RESULT_ID = new IdentifierImpl(AAF_RESULT);
73
74     //
75     private static final PIPRequest PIP_REQUEST_UID = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
76             new IdentifierImpl("AAF_ID"), XACML3.ID_DATATYPE_STRING);
77     private static final PIPRequest PIP_REQUEST_PASS = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
78             new IdentifierImpl("AAF_PASS"), XACML3.ID_DATATYPE_STRING);
79     private static final PIPRequest PIP_REQUEST_TYPE = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
80             new IdentifierImpl("AAF_TYPE"), XACML3.ID_DATATYPE_STRING);
81     private static final PIPRequest PIP_REQUEST_INSTANCE = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
82             new IdentifierImpl("AAF_INSTANCE"), XACML3.ID_DATATYPE_STRING);
83     private static final PIPRequest PIP_REQUEST_ACTION = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
84             new IdentifierImpl("AAF_ACTION"), XACML3.ID_DATATYPE_STRING);
85
86     private static final List<PIPRequest> mapRequiredAttributes = new ArrayList<>();
87
88     static {
89         mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_UID));
90         mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_PASS));
91         mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_TYPE));
92         mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_INSTANCE));
93         mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_ACTION));
94     }
95
96     private static final Map<PIPRequest, String> mapSupportedAttributes = new HashMap<>();
97
98     static {
99         mapSupportedAttributes.put(
100                 new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, AAF_RESPONSE_ID, XACML3.ID_DATATYPE_STRING),
101                 "response");
102         mapSupportedAttributes.put(
103                 new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, AAF_RESULT_ID, XACML3.ID_DATATYPE_BOOLEAN),
104                 "result");
105     }
106
107     protected Log logger = LogFactory.getLog(this.getClass());
108
109     public AAFEngine() {
110         // default constructor
111     }
112
113     private PIPResponse getAttribute(PIPRequest pipRequest, PIPFinder pipFinder) {
114         PIPResponse pipResponse = null;
115         try {
116             pipResponse = pipFinder.getMatchingAttributes(pipRequest, this);
117             if (pipResponse.getStatus() != null && !pipResponse.getStatus().isOk()) {
118                 this.logger.warn("Error retrieving " + pipRequest.getAttributeId().stringValue() + ": "
119                         + pipResponse.getStatus().toString());
120                 pipResponse = null;
121             }
122             if (pipResponse != null && pipResponse.getAttributes().isEmpty()) {
123                 this.logger.warn("No value for " + pipRequest.getAttributeId().stringValue());
124                 pipResponse = null;
125             }
126         } catch (PIPException ex) {
127             this.logger.error("PIPException getting subject-id attribute: " + ex.getMessage(), ex);
128         }
129         return pipResponse;
130     }
131
132     private String getValue(PIPResponse pipResponse) {
133         String result = null;
134         Collection<Attribute> listAttributes = pipResponse.getAttributes();
135         for (Attribute attribute : listAttributes) {
136             Iterator<AttributeValue<String>> iterAttributeValues = attribute.findValues(DataTypes.DT_STRING);
137             if (iterAttributeValues != null) {
138                 while (iterAttributeValues.hasNext()) {
139                     result = iterAttributeValues.next().getValue();
140                     break;
141                 }
142             }
143         }
144         return result;
145     }
146
147     private synchronized String getResult(PIPFinder pipFinder) {
148         PIPResponse pipResponseUID = this.getAttribute(PIP_REQUEST_UID, pipFinder);
149         PIPResponse pipResponsePass = this.getAttribute(PIP_REQUEST_PASS, pipFinder);
150         PIPResponse pipResponseType = this.getAttribute(PIP_REQUEST_TYPE, pipFinder);
151         PIPResponse pipResponseAction = this.getAttribute(PIP_REQUEST_ACTION, pipFinder);
152         PIPResponse pipResponseInstance = this.getAttribute(PIP_REQUEST_INSTANCE, pipFinder);
153         String response = null;
154         // Evaluate AAF if we have all the required values.
155         if (pipResponseUID != null && pipResponsePass != null && pipResponseType != null && pipResponseAction != null
156                 && pipResponseInstance != null) {
157             String userName = getValue(pipResponseUID);
158             String pass = getValue(pipResponsePass);
159
160             AAFPolicyClient aafClient = null;
161             Properties properties;
162             try {
163                 properties = XACMLProperties.getProperties();
164                 logger.debug("environment : " + properties.getProperty("ENVIRONMENT"));
165             } catch (IOException e1) {
166                 logger.error("Exception while getting the properties " + e1);
167                 properties = new Properties();
168                 properties.setProperty("AAF_LOG_LEVEL", "DEBUG");
169             }
170             if (userName != null && pass != null) {
171                 try {
172                     aafClient = AAFPolicyClient.getInstance(properties);
173                 } catch (AAFPolicyException e) {
174                     logger.error("AAF configuration failed. " + e.getMessage() + e);
175                 }
176                 if (aafClient != null) {
177                     if (aafClient.checkAuth(userName, pass)) {
178                         String type = getValue(pipResponseType);
179                         String instance = getValue(pipResponseInstance);
180                         String action = getValue(pipResponseAction);
181                         if (aafClient.checkPerm(userName, pass, type, instance, action)) {
182                             response = SUCCESS + "Permissions Validated";
183                         } else {
184                             response =
185                                     "No Permissions for " + userName + " to: " + type + ", " + instance + ", " + action;
186                         }
187                     } else {
188                         response = "Authentication Failed for the given Values";
189                     }
190                 }
191             } else {
192                 response = "ID and Password are not given";
193             }
194
195         } else {
196             response = "Insufficient Values to Evaluate AAF";
197         }
198         return response;
199     }
200
201     private void addStringAttribute(StdMutablePIPResponse stdPIPResponse, Identifier category, Identifier attributeId,
202             String value) {
203         if (value != null) {
204             AttributeValue<String> attributeValue = null;
205             try {
206                 attributeValue = DataTypes.DT_STRING.createAttributeValue(value);
207             } catch (Exception ex) {
208                 this.logger.error("Failed to convert " + value + " to an AttributeValue<String>", ex);
209             }
210             if (attributeValue != null) {
211                 stdPIPResponse.addAttribute(
212                         new StdMutableAttribute(category, attributeId, attributeValue, this.getIssuer(), false));
213             }
214         }
215     }
216
217     private void addBooleanAttribute(StdMutablePIPResponse stdPIPResponse, Identifier category, Identifier attributeId,
218             boolean value) {
219         AttributeValue<Boolean> attributeValue = null;
220         try {
221             attributeValue = DataTypes.DT_BOOLEAN.createAttributeValue(value);
222         } catch (Exception ex) {
223             this.logger.error("Failed to convert " + value + " to an AttributeValue<Boolean>", ex);
224         }
225         if (attributeValue != null) {
226             stdPIPResponse.addAttribute(
227                     new StdMutableAttribute(category, attributeId, attributeValue, this.getIssuer(), false));
228         }
229     }
230
231     @Override
232     public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
233         /*
234          * First check to see if the issuer is set and then match it
235          */
236         String string;
237
238         if ((string = pipRequest.getIssuer()) != null && !string.equals(this.getIssuer())) {
239             this.logger.debug("Requested issuer '" + string + "' does not match "
240                     + (this.getIssuer() == null ? "null" : "'" + this.getIssuer() + "'"));
241             return StdPIPResponse.PIP_RESPONSE_EMPTY;
242         }
243
244         /*
245          * Drop the issuer and see if the request matches any of our supported queries
246          */
247         PIPRequest pipRequestSupported = pipRequest.getIssuer() == null ? pipRequest
248                 : new StdPIPRequest(pipRequest.getCategory(), pipRequest.getAttributeId(), pipRequest.getDataTypeId());
249         if (!mapSupportedAttributes.containsKey(pipRequestSupported)) {
250             this.logger.debug("Requested attribute '" + pipRequest.toString() + "' is not supported");
251             return StdPIPResponse.PIP_RESPONSE_EMPTY;
252         }
253         StdMutablePIPResponse stdPIPResponse = new StdMutablePIPResponse();
254         String response = this.getResult(pipFinder);
255         boolean result = false;
256         if (response != null && response.contains(SUCCESS)) {
257             result = true;
258         }
259         this.addBooleanAttribute(stdPIPResponse, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, AAF_RESULT_ID, result);
260         this.addStringAttribute(stdPIPResponse, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, AAF_RESPONSE_ID, response);
261         return new StdPIPResponse(stdPIPResponse);
262     }
263
264     @Override
265     public void configure(String id, Properties properties) throws PIPException {
266         super.configure(id, properties);
267         if (this.getDescription() == null) {
268             this.setDescription(DEFAULT_DESCRIPTION);
269         }
270         if (this.getIssuer() == null) {
271             this.setIssuer(DEFAULT_ISSUER);
272         }
273     }
274
275     @Override
276     public Collection<PIPRequest> attributesRequired() {
277         List<PIPRequest> attributes = new ArrayList<>();
278         for (PIPRequest attribute : mapRequiredAttributes) {
279             attributes.add(new StdPIPRequest(attribute));
280         }
281         return attributes;
282     }
283
284     @Override
285     public Collection<PIPRequest> attributesProvided() {
286         List<PIPRequest> attributes = new ArrayList<>();
287         for (PIPRequest attribute : mapSupportedAttributes.keySet()) {
288             attributes.add(new StdPIPRequest(attribute));
289         }
290         return attributes;
291     }
292
293 }