Modified to make AAF configurable in policy/engine
[policy/engine.git] / ONAP-PDP-REST / src / main / java / org / onap / policy / pdp / rest / config / PDPApiAuth.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-PDP-REST
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 package org.onap.policy.pdp.rest.config;
21
22 import java.io.FileInputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Base64;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Properties;
35 import java.util.StringTokenizer;
36
37 import org.onap.policy.api.PolicyEngineException;
38 import org.onap.policy.common.logging.eelf.MessageCodes;
39 import org.onap.policy.common.logging.flexlogger.FlexLogger;
40 import org.onap.policy.common.logging.flexlogger.Logger;
41 import org.onap.policy.rest.XACMLRestProperties;
42 import org.onap.policy.utils.AAFPolicyClient;
43 import org.onap.policy.utils.AAFPolicyException;
44 import org.onap.policy.utils.PolicyUtils;
45 import org.onap.policy.xacml.api.XACMLErrorConstants;
46
47 import com.att.research.xacml.util.XACMLProperties;
48
49 public class PDPApiAuth {
50     private static final Logger LOGGER = FlexLogger.getLogger(PDPApiAuth.class);
51
52     private static String environment = null;
53     private static Path clientPath = null;
54     private static Map<String,ArrayList<String>> clientMap = null;
55     private static Long oldModified = null;
56     private static AAFPolicyClient aafClient = null;
57
58     private PDPApiAuth(){
59         // Private Constructor
60     }
61
62     /*
63      * Set Property by reading the properties File.
64      */
65     public static void setProperty() {
66         environment = XACMLProperties.getProperty("ENVIRONMENT", "DEVL");
67         String clientFile = XACMLProperties.getProperty(XACMLRestProperties.PROP_PEP_IDFILE);
68         if(clientFile!=null){
69             clientPath = Paths.get(clientFile);
70         }
71         try {
72             aafClient = AAFPolicyClient.getInstance(XACMLProperties.getProperties());
73         } catch (AAFPolicyException | IOException e) {
74             LOGGER.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "AAF Client Not instantiated properly.");
75         }
76     }
77
78     /*
79      * Return Environment value of the PDP servlet. 
80      */
81     public static String getEnvironment() {
82         if(environment==null){
83             setProperty();
84         }
85         return environment;
86     }
87
88     /*
89      * Security check for authentication and authorizations. 
90      */
91     public static boolean checkPermissions(String clientEncoding, String requestID,
92             String resource) {
93         try{            
94             String[] userNamePass = PolicyUtils.decodeBasicEncoding(clientEncoding);
95             if(userNamePass==null || userNamePass.length==0){
96                 String usernameAndPassword = null;
97                 byte[] decodedBytes = Base64.getDecoder().decode(clientEncoding);
98                 usernameAndPassword = new String(decodedBytes, "UTF-8");
99                 StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
100                 String username = tokenizer.nextToken();
101                 String password = tokenizer.nextToken();
102                 userNamePass=  new String[]{username,  password};
103             }
104             LOGGER.info("User " + userNamePass[0] + " is Accessing Policy Engine API.");
105             Boolean result = false;
106             // Check Backward Compatibility. 
107             try{
108                 /*
109                  * If AAF is NOT enabled in the properties we will allow the user to 
110                  * continue to use the client.properties file to authenticate.
111                  * Note: Disabling AAF is for testing purposes and not intended for production.
112                  */
113                 if ("false".equals(XACMLProperties.getProperty("enable_aaf"))) {
114                     result = clientAuth(userNamePass);
115                 }
116             }catch(Exception e){
117                 LOGGER.error(MessageCodes.ERROR_PERMISSIONS, e);
118             }
119             if(!result){
120                 String aafPolicyNameSpace = XACMLProperties.getProperty("policy.aaf.namespace");
121                 String aafResource = XACMLProperties.getProperty("policy.aaf.root.permission");
122                 String type = null;
123                 if(!userNamePass[0].contains("@") && aafPolicyNameSpace!= null){
124                     userNamePass[0] = userNamePass[0] + "@" + reverseNamespace(aafPolicyNameSpace);
125                 }else{
126                     LOGGER.info("No AAF NameSpace specified in properties");
127                 }
128                 if(aafResource != null){
129                     type = aafResource + "." + resource;
130                 }else{
131                     LOGGER.warn("No AAF Resource specified in properties");
132                     return false;
133                 }
134                 LOGGER.info("Contacting AAF in : "  + environment);
135                 result = aafClient.checkAuthPerm(userNamePass[0], userNamePass[1], type, environment, "*");
136             }
137             return result;
138         }catch(Exception e){
139             LOGGER.error(MessageCodes.ERROR_PERMISSIONS, e);
140             return false;
141         }
142     }
143
144     private static Boolean clientAuth(String[] userNamePass){
145         if(clientPath==null){
146             setProperty();
147         }
148         if (!clientPath.toFile().exists()) {
149             return false;
150         }else if(clientPath.toString().endsWith(".properties")) {
151             try {
152                 readProps(clientPath);
153                 if (clientMap.containsKey(userNamePass[0]) && clientMap.get(userNamePass[0]).get(0).equals(userNamePass[1])) {
154                     return true;
155                 }
156             }catch(PolicyEngineException e){
157                 LOGGER.error(MessageCodes.ERROR_PERMISSIONS, e);
158                 return false;
159             }
160         }
161         return false;
162     }
163
164     private static String reverseNamespace(String namespace) {
165         final List<String> components = Arrays.asList(namespace.split("\\."));
166         Collections.reverse(components);   
167         return String.join(".", components);
168     }
169
170     private static Map<String, ArrayList<String>> readProps(Path clientPath) throws PolicyEngineException{
171         if(oldModified!=null){
172             Long newModified = clientPath.toFile().lastModified();
173             if (newModified == oldModified) {
174                 return clientMap;
175             }
176         }
177         InputStream in;
178         Properties clientProp = new Properties();
179         try {
180             in = new FileInputStream(clientPath.toFile());
181             clientProp.load(in);
182         } catch (IOException e) {
183             LOGGER.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR , e);
184             throw new PolicyEngineException(XACMLErrorConstants.ERROR_SYSTEM_ERROR +"Cannot Load the Properties file", e);
185         }
186         // Read the Properties and Load the Clients and their scopes.
187         clientMap = new HashMap<>();
188         // 
189         for (Object propKey : clientProp.keySet()) {
190             String clientID = (String)propKey; 
191             String clientValue = clientProp.getProperty(clientID);
192             if (clientValue != null && clientValue.contains(",")) {
193                 ArrayList<String> clientValues = new ArrayList<>(Arrays.asList(clientValue.split("\\s*,\\s*")));
194                 if(clientValues.get(0)!=null || clientValues.get(1)!=null || clientValues.get(0).isEmpty() || clientValues.get(1).isEmpty()){
195                     clientMap.put(clientID, clientValues);
196                 }
197             }
198         }
199         if (clientMap.isEmpty()) {
200             LOGGER.debug(XACMLErrorConstants.ERROR_PERMISSIONS + "No Clients ID , Client Key and Scopes are available. Cannot serve any Clients !!");
201             throw new PolicyEngineException("Empty Client file");
202         }
203         oldModified = clientPath.toFile().lastModified();
204         return clientMap;
205     }
206 }