Make clientAuth header optional and log request
[policy/engine.git] / ONAP-PDP-REST / src / main / java / org / onap / policy / pdp / rest / restauth / AuthenticationService.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP-PDP-REST
  * ================================================================================
- * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017,2019 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.policy.pdp.rest.config;
+package org.onap.policy.pdp.rest.restauth;
 
 import com.att.research.xacml.util.XACMLProperties;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -35,6 +36,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.StringTokenizer;
+import javax.servlet.ServletRequest;
+import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.api.PolicyEngineException;
 import org.onap.policy.common.logging.eelf.MessageCodes;
 import org.onap.policy.common.logging.flexlogger.FlexLogger;
@@ -46,23 +49,22 @@ import org.onap.policy.utils.PeCryptoUtils;
 import org.onap.policy.utils.PolicyUtils;
 import org.onap.policy.xacml.api.XACMLErrorConstants;
 
-public class PDPApiAuth {
-    private static final Logger LOGGER = FlexLogger.getLogger(PDPApiAuth.class);
-
+public class AuthenticationService {
+    private static final Logger LOGGER = FlexLogger.getLogger(AuthenticationService.class);
     private static String environment = null;
     private static Path clientPath = null;
     private static Map<String, ArrayList<String>> clientMap = null;
     private static Long oldModified = null;
     private static AAFPolicyClient aafClient = null;
 
-    private PDPApiAuth() {
+    private AuthenticationService() {
         // Private Constructor
     }
 
     /*
      * Set Property by reading the properties File.
      */
-    public static void setProperty() {
+    private static void setProperty() {
         environment = XACMLProperties.getProperty("ENVIRONMENT", "DEVL");
         String clientFile = XACMLProperties.getProperty(XACMLRestProperties.PROP_PEP_IDFILE);
         if (clientFile != null) {
@@ -75,8 +77,10 @@ public class PDPApiAuth {
         }
     }
 
-    /*
-     * Return Environment value of the PDP servlet.
+    /**
+     * Gets the environment.
+     *
+     * @return the environment
      */
     public static String getEnvironment() {
         if (environment == null) {
@@ -85,54 +89,80 @@ public class PDPApiAuth {
         return environment;
     }
 
-    /*
+    private static String reverseNamespace(String namespace) {
+        final List<String> components = Arrays.asList(namespace.split("\\."));
+        Collections.reverse(components);
+        return String.join(".", components);
+    }
+
+    /**
      * Security check for authentication and authorizations.
+     *
+     * @param clientAuthHeader the client auth header
+     * @param authHeader the auth header
+     * @param resource the resource
+     * @param env the env
+     * @return true, if successful
      */
-    public static boolean checkPermissions(String clientEncoding, String requestID, String resource) {
+    public static boolean checkPermissions(String clientAuthHeader, String authHeader, String resource, String env,
+            ServletRequest request) {
+        boolean result = false;
+        // check whether env matches
+        result = checkEnv(env);
+        if (!result) {
+            LOGGER.info(XACMLErrorConstants.ERROR_PERMISSIONS + " invalid Environment Header");
+            return result;
+        }
+        // decode the user/pwd from the request header
+        String[] userNamePass = getUserInfo(authHeader, clientAuthHeader);
+
         try {
-            String[] userNamePass = PolicyUtils.decodeBasicEncoding(clientEncoding);
-            if (userNamePass == null || userNamePass.length == 0) {
-                String usernameAndPassword = null;
-                byte[] decodedBytes = Base64.getDecoder().decode(clientEncoding);
-                usernameAndPassword = new String(decodedBytes, "UTF-8");
-                StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
-                String username = tokenizer.nextToken();
-                String password = tokenizer.nextToken();
-                userNamePass = new String[] {username, password};
-            }
-            LOGGER.info("User " + userNamePass[0] + " is Accessing Policy Engine API.");
-            Boolean result = false;
             // Check Backward Compatibility.
-            try {
-                /*
-                 * If AAF is NOT enabled in the properties we will allow the user to continue to use the
-                 * client.properties file to authenticate. Note: Disabling AAF is for testing purposes and not intended
-                 * for production.
-                 */
-                if ("false".equals(XACMLProperties.getProperty("enable_aaf"))) {
-                    result = clientAuth(userNamePass);
-                }
-            } catch (Exception e) {
-                LOGGER.error(MessageCodes.ERROR_PERMISSIONS, e);
+            request.setAttribute("Mechid", "");
+            result = false;
+            /*
+             * If AAF is NOT enabled in the properties we will allow the user to continue to use the client.properties
+             * file to authenticate. Note: Disabling AAF is for testing purposes and not intended for production.
+             */
+            if ("false".equals(XACMLProperties.getProperty("enable_aaf"))) {
+                result = clientAuth(userNamePass);
             }
             if (!result) {
-                String aafPolicyNameSpace = XACMLProperties.getProperty("policy.aaf.namespace");
-                String aafResource = XACMLProperties.getProperty("policy.aaf.root.permission");
-                String type = null;
-                if (!userNamePass[0].contains("@") && aafPolicyNameSpace != null) {
-                    userNamePass[0] = userNamePass[0] + "@" + reverseNamespace(aafPolicyNameSpace);
-                } else {
-                    LOGGER.info("No AAF NameSpace specified in properties");
-                }
-                if (aafResource != null) {
-                    type = aafResource + "." + resource;
-                } else {
-                    LOGGER.warn("No AAF Resource specified in properties");
-                    return false;
-                }
-                LOGGER.info("Contacting AAF in : " + environment);
-                result = aafClient.checkAuthPerm(userNamePass[0], userNamePass[1], type, environment, "*");
+                result = aafAuth(userNamePass, resource);
+                request.setAttribute("Mechid", userNamePass[0]);
+            }
+        } catch (Exception e) {
+            LOGGER.error(MessageCodes.ERROR_PERMISSIONS, e);
+            result = false;
+        }
+        return result;
+
+    }
+
+    private static boolean checkEnv(String env) {
+        if (StringUtils.isBlank(env)) {
+            // must be old type of req
+            return true;
+        } else {
+            return env.trim().equalsIgnoreCase(getEnvironment());
+        }
+
+    }
+
+    private static boolean aafAuth(String[] userNamePass, String resource) {
+        boolean result = false;
+        String permission = getPermission(resource);
+        try {
+            String aafPolicyNameSpace = XACMLProperties.getProperty("policy.aaf.namespace");
+            if (!userNamePass[0].contains("@") && aafPolicyNameSpace != null) {
+                userNamePass[0] = userNamePass[0] + "@" + reverseNamespace(aafPolicyNameSpace);
+            } else {
+                LOGGER.info("No AAF NameSpace specified in properties");
             }
+
+            LOGGER.info("Contacting AAF in : " + environment);
+            result = aafClient.checkAuthPerm(userNamePass[0], userNamePass[1], permission, environment, "*");
+
             return result;
         } catch (Exception e) {
             LOGGER.error(MessageCodes.ERROR_PERMISSIONS, e);
@@ -140,6 +170,33 @@ public class PDPApiAuth {
         }
     }
 
+    private static String getPermission(String resource) {
+        String aafResource = XACMLProperties.getProperty("policy.aaf.root.permission");
+        String perm = resource;
+        if (StringUtils.containsIgnoreCase(perm, "Notification")) {
+            perm = "notification";
+        } else if (StringUtils.containsIgnoreCase(perm, "heartbeat")) {
+            perm = "notification";
+        } else if (StringUtils.containsIgnoreCase(perm, "createDictionary")) {
+            perm = "createDictionary";
+        } else if (StringUtils.containsIgnoreCase(perm, "updateDictionary")) {
+            perm = "updateDictionary";
+        } else if (StringUtils.containsIgnoreCase(perm, "getDictionary")) {
+            perm = "getDictionary";
+        } else if (StringUtils.containsIgnoreCase(perm, "create")) {
+            perm = "createPolicy";
+        } else if (StringUtils.containsIgnoreCase(perm, "update")) {
+            perm = "updatePolicy";
+        }
+
+        if (!StringUtils.isBlank(aafResource)) {
+            perm = aafResource + "." + perm;
+        } else {
+            LOGGER.info("No AAF Resource specified in properties");
+        }
+        return perm;
+    }
+
     private static Boolean clientAuth(String[] userNamePass) {
         if (clientPath == null) {
             setProperty();
@@ -161,23 +218,16 @@ public class PDPApiAuth {
         return false;
     }
 
-    private static String reverseNamespace(String namespace) {
-        final List<String> components = Arrays.asList(namespace.split("\\."));
-        Collections.reverse(components);
-        return String.join(".", components);
-    }
-
     private static Map<String, ArrayList<String>> readProps(Path clientPath) throws PolicyEngineException {
         if (oldModified != null) {
             Long newModified = clientPath.toFile().lastModified();
-            if (newModified == oldModified) {
+            if (oldModified.equals(newModified)) {
                 return clientMap;
             }
         }
-        InputStream in;
+
         Properties clientProp = new Properties();
-        try {
-            in = new FileInputStream(clientPath.toFile());
+        try (InputStream in = new FileInputStream(clientPath.toFile())) {
             clientProp.load(in);
         } catch (IOException e) {
             LOGGER.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR, e);
@@ -188,14 +238,13 @@ public class PDPApiAuth {
         clientMap = new HashMap<>();
         //
         for (Object propKey : clientProp.keySet()) {
-            String clientID = (String) propKey;
-            String clientValue = clientProp.getProperty(clientID);
+            String clientId = (String) propKey;
+            String clientValue = clientProp.getProperty(clientId);
             if (clientValue != null && clientValue.contains(",")) {
                 ArrayList<String> clientValues = new ArrayList<>(Arrays.asList(clientValue.split("\\s*,\\s*")));
-                if (clientValues.get(0) != null || clientValues.get(1) != null || clientValues.get(0).isEmpty()
-                        || clientValues.get(1).isEmpty()) {
+                if (!StringUtils.isBlank(clientValues.get(0))) {
                     clientValues.set(0, PeCryptoUtils.decrypt(clientValues.get(0)));
-                    clientMap.put(clientID, clientValues);
+                    clientMap.put(clientId, clientValues);
                 }
             }
         }
@@ -207,4 +256,32 @@ public class PDPApiAuth {
         oldModified = clientPath.toFile().lastModified();
         return clientMap;
     }
+
+    private static String[] getUserInfo(final String authHeader, final String clientAuthHeader) {
+        String userInfo = authHeader;
+        if (!StringUtils.isBlank(clientAuthHeader)) {
+            userInfo = clientAuthHeader;
+        }
+
+        String[] userNamePass = null;
+
+        try {
+            userNamePass = PolicyUtils.decodeBasicEncoding(userInfo);
+            if (userNamePass == null || userNamePass.length == 0) {
+                String usernameAndPassword = null;
+                byte[] decodedBytes = Base64.getDecoder().decode(userInfo);
+                usernameAndPassword = new String(decodedBytes, StandardCharsets.UTF_8);
+                StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
+                String username = tokenizer.nextToken();
+                String password = tokenizer.nextToken();
+                userNamePass = new String[] {username, password};
+            }
+            LOGGER.info("User " + userNamePass[0] + " is Accessing Policy Engine API - ");
+        } catch (Exception e) {
+            LOGGER.error(MessageCodes.ERROR_PERMISSIONS, e);
+            return new String[0];
+        }
+        return userNamePass;
+    }
+
 }