2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 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=========================================================
20 package org.onap.policy.pdp.rest.api.services;
22 import java.io.ByteArrayInputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.ObjectInputStream;
26 import java.io.OutputStream;
27 import java.net.HttpURLConnection;
29 import java.nio.charset.StandardCharsets;
30 import java.util.Arrays;
31 import java.util.Base64;
32 import java.util.Collections;
33 import java.util.List;
35 import java.util.UUID;
37 import org.apache.commons.io.IOUtils;
38 import org.onap.policy.api.PolicyException;
39 import org.onap.policy.common.logging.flexlogger.FlexLogger;
40 import org.onap.policy.common.logging.flexlogger.Logger;
41 import org.onap.policy.pdp.rest.config.PDPApiAuth;
42 import org.onap.policy.rest.XACMLRestProperties;
43 import org.onap.policy.xacml.api.XACMLErrorConstants;
44 import org.onap.policy.xacml.std.pap.StdPDPPolicy;
46 import com.att.research.xacml.util.XACMLProperties;
47 import com.fasterxml.jackson.databind.ObjectMapper;
49 public class PAPServices {
50 private static final String SUCCESS = "success";
51 private static Logger LOGGER = FlexLogger.getLogger(PAPServices.class
54 private int responseCode = 0;
55 private static String environment = "DEVL";
56 private static Boolean junit = false;
57 private static List<String> paps = null;
58 private static final Object papResourceLock = new Object();
59 private String operation = null;
60 private String requestMethod = null;
61 private String encoding = null;
63 public PAPServices() {
64 environment = PDPApiAuth.getEnvironment();
66 synchronized (papResourceLock) {
67 String urlList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URLS);
69 urlList = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL);
71 paps = Arrays.asList(urlList.split(","));
76 private String getPAPEncoding(){
78 String userID = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_USERID);
79 String pass = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_PASS);
80 Base64.Encoder encoder = Base64.getEncoder();
81 encoding = encoder.encodeToString((userID+":"+pass).getBytes(StandardCharsets.UTF_8));
86 private void rotatePAPList(){
87 synchronized (papResourceLock) {
88 Collections.rotate(paps, -1);
92 private String getPAP(){
94 synchronized (papResourceLock) {
100 public int getResponseCode() {
104 public Object callPAP(Object content, String[] parameters, UUID requestID,
105 String clientScope) throws PolicyException {
106 String response = null;
107 HttpURLConnection connection = null;
109 // Checking for the available PAPs is done during the first Request and
110 // the List is going to have the connected PAP as first element.
111 // This makes it Real-Time to change the list depending on their
113 if (paps == null || paps.isEmpty()) {
114 String message = XACMLErrorConstants.ERROR_DATA_ISSUE + "PAPs List is Empty.";
115 LOGGER.error(message);
116 throw new PolicyException(message);
119 boolean connected = false;
120 while (papsCount < paps.size()) {
122 String fullURL = getPAP();
123 fullURL = checkParameter(parameters, fullURL);
124 URL url = new URL(fullURL);
125 LOGGER.debug("--- Sending Request to PAP : "+ url.toString() + " ---");
126 // Open the connection
127 connection = (HttpURLConnection) url.openConnection();
128 // Setting Content-Type
129 connection.setRequestProperty("Content-Type","application/json");
130 // Adding Authorization
131 connection.setRequestProperty("Authorization", "Basic "+ getPAPEncoding());
132 connection.setRequestProperty("Environment", environment);
133 connection.setRequestProperty("ClientScope", clientScope);
134 // set the method and headers
135 connection.setRequestMethod(requestMethod);
136 connection.setUseCaches(false);
137 connection.setInstanceFollowRedirects(false);
138 connection.setDoOutput(true);
139 connection.setDoInput(true);
141 if (requestID == null) {
142 requestID = UUID.randomUUID();
143 LOGGER.info("No request ID provided, sending generated ID: "
144 + requestID.toString());
146 LOGGER.info("Using provided request ID: "
147 + requestID.toString());
149 connection.setRequestProperty("X-ECOMP-RequestID",
150 requestID.toString());
151 if (content != null && (content instanceof InputStream)) {
152 // send current configuration
153 try (OutputStream os = connection.getOutputStream()) {
154 int count = IOUtils.copy((InputStream) content, os);
155 if (LOGGER.isDebugEnabled()) {
156 LOGGER.debug("copied to output, bytes=" + count);
159 } else if(content != null){
160 // the content is an object to be encoded in JSON
161 ObjectMapper mapper = new ObjectMapper();
163 mapper.writeValue(connection.getOutputStream(),
168 connection.connect();
169 responseCode = connection.getResponseCode();
170 // If Connected to PAP then break from the loop and continue
172 if (connection.getResponseCode() > 0 || junit) {
176 LOGGER.debug(XACMLErrorConstants.ERROR_PERMISSIONS+ "PAP Response Code : " + connection.getResponseCode());
179 } catch (Exception e) {
180 // This means that the PAP is not working
185 LOGGER.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR
186 + "PAP connection Error : " + e);
193 LOGGER.debug("connected to the PAP : " + getPAP());
194 LOGGER.debug("--- Response: ---");
195 if(connection != null){
196 Map<String, List<String>> headers = connection.getHeaderFields();
197 for (String key : headers.keySet()) {
198 LOGGER.debug("Header :" + key + " Value: " + headers.get(key));
202 response = checkResponse(connection, requestID);
203 } catch (IOException e) {
204 LOGGER.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + e);
205 response = XACMLErrorConstants.ERROR_SYSTEM_ERROR + e;
206 throw new PolicyException(
207 XACMLErrorConstants.ERROR_SYSTEM_ERROR
208 + "Decoding the result ", e);
214 response = XACMLErrorConstants.ERROR_SYSTEM_ERROR + "connection is null";
218 response = XACMLErrorConstants.ERROR_SYSTEM_ERROR
219 + "Unable to get valid response from PAP(s) " + paps;
224 public String getActiveVersion(String policyScope, String filePrefix, String policyName, String clientScope, UUID requestID) {
225 String version = null;
226 HttpURLConnection connection = null;
227 String [] parameters = {"apiflag=version","policyScope="+policyScope, "filePrefix="+filePrefix, "policyName="+policyName};
228 if (paps == null || paps.isEmpty()) {
229 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "PAPs List is Empty.");
232 boolean connected = false;
233 while (papsCount < paps.size()) {
235 String fullURL = getPAP();
236 if (parameters != null && parameters.length > 0) {
237 String queryString = "";
238 for (String p : parameters) {
239 queryString += "&" + p;
241 fullURL += "?" + queryString.substring(1);
244 URL url = new URL (fullURL);
246 //Open the connection
247 connection = (HttpURLConnection)url.openConnection();
249 // Setting Content-Type
250 connection.setRequestProperty("Content-Type",
253 // Adding Authorization
254 connection.setRequestProperty("Authorization", "Basic "
257 connection.setRequestProperty("Environment", environment);
258 connection.setRequestProperty("ClientScope", clientScope);
261 //set the method and headers
262 connection.setRequestMethod("GET");
263 connection.setUseCaches(false);
264 connection.setInstanceFollowRedirects(false);
265 connection.setDoOutput(true);
266 connection.setDoInput(true);
267 connection.setRequestProperty("X-ECOMP-RequestID", requestID.toString());
270 connection.connect();
272 // If Connected to PAP then break from the loop and continue with the Request
273 if (connection.getResponseCode() > 0) {
278 LOGGER.debug(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "PAP connection Error");
280 } catch (Exception e) {
281 // This means that the PAP is not working
282 LOGGER.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "PAP connection Error : " + e);
290 LOGGER.debug("connected to the PAP : " + getPAP());
291 LOGGER.debug("--- Response: ---");
292 Map<String, List<String>> headers = connection.getHeaderFields();
293 for (String key : headers.keySet()) {
294 LOGGER.debug("Header :" + key + " Value: " + headers.get(key));
297 if (connection.getResponseCode() == 200) {
298 // Check for successful creation of policy
299 version = connection.getHeaderField("version");
300 LOGGER.debug("ActiveVersion from the Header: " + version);
301 } else if (connection.getResponseCode() == 403) {
302 LOGGER.error(XACMLErrorConstants.ERROR_PERMISSIONS + "response code of the URL is "
303 + connection.getResponseCode() + ". PEP is not Authorized for making this Request!! \n Contact Administrator for this Scope. ");
305 } else if (connection.getResponseCode() == 404) {
306 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "response code of the URL is "
307 + connection.getResponseCode() + ". This indicates a problem with getting the version from the PAP");
310 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "BAD REQUEST: Error occured while getting the version from the PAP. The request may be incorrect.");
312 } catch (IOException e) {
313 LOGGER.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
316 LOGGER.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Unable to get valid response from PAP(s) " + paps);
322 private String checkResponse(HttpURLConnection connection, UUID requestID) throws IOException {
323 String response = null;
324 if (responseCode == 200 || junit) {
325 // Check for successful creation of policy
326 String isSuccess = null;
327 if (!junit) { // is this a junit test?
328 isSuccess = connection.getHeaderField("successMapKey");
329 operation = connection.getHeaderField("operation");
333 if (SUCCESS.equals(isSuccess)) {
334 if ("update".equals(operation)) {
335 response = "Transaction ID: " + requestID + " --Policy with the name "+ connection.getHeaderField("policyName")
336 + " was successfully updated. ";
337 if (connection.getHeaderField("safetyChecker")!=null) {
339 + "\n\nPolicy Safety Checker Warning: This closedLoopControlName "
340 + "is potentially in conflict with " + connection.getHeaderField("conflictCLName")
341 + " that already exists." + " See detailed information on ClosedLoop Pairs below: "
342 +"\n\n"+connection.getHeaderField("safetyChecker");
344 } else if ("create".equals(operation)) {
345 response = "Transaction ID: " + requestID + " --Policy with the name "+ connection.getHeaderField("policyName")
346 + " was successfully created.";
347 if (connection.getHeaderField("safetyChecker")!=null) {
349 + "\n\nPolicy Safety Checker Warning: This closedLoopControlName "
350 + "is potentially in conflict with " + connection.getHeaderField("conflictCLName")
351 + " that already exists. " + "See detailed information on ClosedLoop Pairs below: "
352 +"\n\n"+connection.getHeaderField("safetyChecker");
354 } else if ("delete".equals(operation)) {
355 response = "Transaction ID: " + requestID + " --The policy was successfully deleted.";
356 } else if ("import".equals(operation)) {
357 response = "Transaction ID: " + requestID + " --The policy engine import for "+ connection.getHeaderField("service")
358 + " was successfull.";
359 } else if ("createDictionary".equals(operation)) {
360 response = "Transaction ID: " + requestID + " --Dictionary Item was added successfully!";
361 } else if ("updateDictionary".equals(operation)) {
362 response = "Transaction ID: " + requestID + " --Dictionary Item was updated successfully!";
363 } else if ("getDictionary".equals(operation)) {
367 //get the json string from the response
368 InputStream is = connection.getInputStream();
370 // read the inputStream into a buffer (trick found online scans entire input looking for end-of-file)
371 java.util.Scanner scanner = new java.util.Scanner(is);
372 scanner.useDelimiter("\\A");
373 json = scanner.hasNext() ? scanner.next() : "";
376 } catch (IOException e1) {
377 LOGGER.error(e1.getMessage() + e1);
379 response = "Transaction ID: " + requestID + " --Dictionary Items Retrieved " + json;
380 } else if ("getMetrics".equals(operation)) {
381 response = "Transaction ID: " + requestID + " --Policy Metrics Retrieved " + connection.getHeaderField("metrics");
383 LOGGER.info(response);
385 String message = XACMLErrorConstants.ERROR_DATA_ISSUE
386 + "Operation unsuccessful, unable to complete the request!";
387 LOGGER.error(message);
390 } else if (connection.getResponseCode() == 202) {
391 if ("delete".equalsIgnoreCase(connection.getHeaderField("operation")) &&
392 "true".equals(connection.getHeaderField("lockdown"))) {
393 response = "Transaction ID: "
395 + " --Policies are locked down, please try again later.";
396 LOGGER.warn(response);
398 } else if (connection.getResponseCode() == 204) {
399 if ("push".equals(connection.getHeaderField("operation"))) {
400 response = "Transaction ID: "
403 + connection.getHeaderField("policyId")
404 + "' was successfully pushed to the PDP group '"
405 + connection.getHeaderField("groupId") + "'.";
406 LOGGER.info(response);
408 } else if (connection.getResponseCode() == 400 && connection.getHeaderField("error") != null) {
409 response = connection.getHeaderField("error");
410 LOGGER.error(response);
411 } else if (connection.getResponseCode() == 403) {
412 response = XACMLErrorConstants.ERROR_PERMISSIONS
413 + "response code of the URL is "
414 + connection.getResponseCode()
415 + ". PEP is not Authorized for making this Request!! \n Contact Administrator for this Scope. ";
416 LOGGER.error(response);
417 } else if (connection.getResponseCode() == 404 && connection.getHeaderField("error") != null) {
418 if ("unknownGroupId".equals(connection.getHeaderField("error"))) {
419 response = XACMLErrorConstants.ERROR_DATA_ISSUE
420 + connection.getHeaderField("message")
421 + " Please check the pdpGroup you are requesting to move the policy to.";
422 LOGGER.error(response);
424 } else if (connection.getResponseCode() == 409 && connection.getHeaderField("error") != null) {
425 if ("modelExistsDB".equals(connection.getHeaderField("error"))) {
426 response = XACMLErrorConstants.ERROR_DATA_ISSUE
427 + "Import Value Exist Error: The import value "
428 + connection.getHeaderField("service")
429 + " already exist on the PAP. "
430 + "Please create a new import value.";
431 } else if ("policyExists".equals(connection.getHeaderField("error"))) {
432 response = XACMLErrorConstants.ERROR_DATA_ISSUE
433 + "Policy Exist Error: The Policy "
434 + connection.getHeaderField("policyName")
435 + " already exist on the PAP. "
436 + "Please create a new policy or use the update API to modify the existing one.";
437 } else if ("dictionaryItemExists".equals(connection.getHeaderField("error"))) {
438 response = XACMLErrorConstants.ERROR_DATA_ISSUE
439 + "Dictionary Item Exist Error: The Dictionary Item already exist in the database. "
440 + "Please create a new Dictionary Item or use the update API to modify the existing one.";
441 } else if ("duplicateGroup".equals(connection.getHeaderField("error"))) {
442 response = XACMLErrorConstants.ERROR_DATA_ISSUE
443 + "Group Policy Scope List Exist Error: The Group Policy Scope List for this Dictionary Item already exist in the database. "
444 + "Duplicate Group Policy Scope Lists for multiple groupNames is not allowed. "
445 + "Please review the request and verify that the groupPolicyScopeListData1 is unique compared to existing groups.";
446 } else if("PolicyInPDP".equals(connection.getHeaderField("error"))){
447 response = XACMLErrorConstants.ERROR_DATA_ISSUE
448 + "Policy Exist Error: The Policy trying to be deleted is active in PDP. "
449 + "Active PDP Polcies are not allowed to be deleted from PAP. "
450 + "Please First remove the policy from PDP in order to successfully delete the Policy from PAP.";
452 LOGGER.error(response);
453 } else if (connection.getResponseCode() == 500 && connection.getHeaderField("error") != null) {
454 if ("jpautils".equals(connection.getHeaderField("error"))) {
455 response = XACMLErrorConstants.ERROR_SYSTEM_ERROR
456 + "Could not create JPAUtils instance on the PAP";
457 } else if ("deleteDB".equals(connection.getHeaderField("error"))) {
458 response = XACMLErrorConstants.ERROR_SYSTEM_ERROR
459 + "Failed to delete Policy from database.";
460 } else if ("deleteFile".equals(connection.getHeaderField("error"))) {
461 response = XACMLErrorConstants.ERROR_DATA_ISSUE
462 + "Cannot delete the policy file";
463 } else if ("groupUpdate".equals(connection.getHeaderField("error"))) {
464 response = connection.getHeaderField("message");
465 } else if ("unknown".equals(connection.getHeaderField("error"))) {
466 response = XACMLErrorConstants.ERROR_UNKNOWN
467 + "Failed to delete the policy for an unknown reason. Check the file system and other logs for further information.";
468 } else if ("deleteConfig".equals(connection.getHeaderField("error"))) {
469 response = XACMLErrorConstants.ERROR_DATA_ISSUE
470 + "Cannot delete the configuration or action body file in specified location.";
471 } else if ("missing".equals(connection.getHeaderField("error"))) {
472 response = XACMLErrorConstants.ERROR_DATA_ISSUE
473 + "Failed to create value in database because service does match a value in file";
474 } else if ("importDB".equals(connection.getHeaderField("error"))) {
475 response = XACMLErrorConstants.ERROR_DATA_ISSUE
476 + "Database errors during policy engine import";
477 } else if ("policyCopyError".equals(connection.getHeaderField("error"))) {
478 response = XACMLErrorConstants.ERROR_PROCESS_FLOW
479 + connection.getHeaderField("message");
480 } else if ("addGroupError".equals(connection.getHeaderField("error"))) {
481 response = connection.getHeaderField("message");
482 } else if ("validation".equals(connection.getHeaderField("error"))){
483 response = XACMLErrorConstants.ERROR_DATA_ISSUE
484 + "Validation errors during policy engine " + connection.getHeaderField("operation") +
485 " for " + connection.getHeaderField("service");
486 } else if ("error".equals(connection.getHeaderField("error"))) {
487 response = XACMLErrorConstants.ERROR_UNKNOWN
488 + "Could not create or update the policy for and unknown reason";
490 response = XACMLErrorConstants.ERROR_DATA_ISSUE
491 + "BAD REQUEST: Error occured while attempting perform this operation.. the request may be incorrect. " + connection.getHeaderField("error");
493 LOGGER.error(response);
495 response = XACMLErrorConstants.ERROR_DATA_ISSUE
496 + "BAD REQUEST: Error occured while attempting perform this operation.. the request may be incorrect.";
497 LOGGER.error(response);
502 private String checkParameter(String[] parameters, String fullURL) {
503 if (parameters != null && parameters.length > 0) {
504 String queryString = "";
505 for (String p : parameters) {
506 queryString += "&" + p;
507 if (p.equalsIgnoreCase("operation=post")) {
508 requestMethod = "POST";
509 } else if (p.equalsIgnoreCase("operation=delete")) {
510 requestMethod = "DELETE";
511 operation = "delete";
512 } else if (p.equalsIgnoreCase("operation=get")) {
513 requestMethod = "GET";
515 } else if (p.equalsIgnoreCase("operation=put")||p.equalsIgnoreCase("operation=create")
516 ||p.equalsIgnoreCase("operation=update")||p.equalsIgnoreCase("operation=createDictionary")){
517 requestMethod = "PUT";
518 if (p.equalsIgnoreCase("operation=create")) {
519 operation = "create";
520 } else if (p.equalsIgnoreCase("operation=update")) {
521 operation = "update";
522 } else if (p.equalsIgnoreCase("operation=createDictionary")){
523 operation = "createDictionary";
525 }else if (p.equalsIgnoreCase("importService=MICROSERVICE")||p.equalsIgnoreCase("importService=BRMSPARAM")){
526 requestMethod = "PUT";
529 fullURL += "?" + queryString.substring(1);
534 public StdPDPPolicy pushPolicy(String policyScope, String filePrefix,
535 String policyName, String clientScope, String pdpGroup,
536 UUID requestID) throws PolicyException {
538 + "\"apiflag\": \"api\","
539 + "\"policyScope\": \""+policyScope+"\","
540 + "\"filePrefix\": \""+filePrefix+"\","
541 + "\"policyName\": \""+policyName+"\","
542 + "\"clientScope\": \""+clientScope+"\","
543 + "\"pdpGroup\": \""+pdpGroup+"\"}";
544 //String response = null;
545 HttpURLConnection connection = null;
547 if (paps == null || paps.isEmpty()) {
548 String message = XACMLErrorConstants.ERROR_DATA_ISSUE + "PAPs List is Empty.";
549 LOGGER.error(message);
550 throw new PolicyException(message);
553 boolean connected = false;
554 while (papsCount < paps.size()) {
556 String fullURL = getPAP();
557 fullURL = (fullURL.endsWith("/"))? fullURL+"onap/pushPolicy" : fullURL+"/onap/pushPolicy";
558 URL url = new URL(fullURL);
559 LOGGER.debug("--- Sending Request to PAP : "+ url.toString() + " ---");
560 // Open the connection
561 connection = (HttpURLConnection) url.openConnection();
562 // Setting Content-Type
563 connection.setRequestProperty("Content-Type","application/json");
564 // Adding Authorization
565 connection.setRequestProperty("Authorization", "Basic "+ getPAPEncoding());
566 connection.setRequestProperty("Environment", environment);
567 connection.setRequestProperty("ClientScope", clientScope);
568 // set the method and headers
569 connection.setRequestMethod("POST");
570 connection.setUseCaches(false);
571 connection.setInstanceFollowRedirects(false);
572 connection.setDoOutput(true);
574 if (requestID == null) {
575 requestID = UUID.randomUUID();
576 LOGGER.info("No request ID provided, sending generated ID: "
577 + requestID.toString());
579 LOGGER.info("Using provided request ID: "
580 + requestID.toString());
582 connection.setRequestProperty("X-ECOMP-RequestID",
583 requestID.toString());
585 try (OutputStream os = connection.getOutputStream()) {
586 int count = IOUtils.copy(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)), os);
587 if (LOGGER.isDebugEnabled()) {
588 LOGGER.debug("copied to output, bytes=" + count);
591 connection.connect();
592 responseCode = connection.getResponseCode();
593 // If Connected to PAP then break from the loop and continue
595 if (connection.getResponseCode() > 0 || junit) {
599 LOGGER.debug(XACMLErrorConstants.ERROR_PERMISSIONS+ "PAP Response Code : " + connection.getResponseCode());
602 } catch (Exception e) {
603 // This means that the PAP is not working
608 LOGGER.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR
609 + "PAP connection Error : " + e);
616 LOGGER.debug("connected to the PAP : " + getPAP());
617 LOGGER.debug("--- Response: ---");
618 if(connection != null){
619 Map<String, List<String>> headers = connection.getHeaderFields();
620 for (String key : headers.keySet()) {
621 LOGGER.debug("Header :" + key + " Value: " + headers.get(key));
624 if(responseCode==202){
625 StdPDPPolicy policy = (StdPDPPolicy) new ObjectInputStream(connection.getInputStream()).readObject();
628 } catch (IOException | ClassNotFoundException e) {
629 LOGGER.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + e);
630 throw new PolicyException(
631 XACMLErrorConstants.ERROR_SYSTEM_ERROR
632 + "Decoding the result ", e);