2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (c) 2017-2019 AT&T Intellectual Property. All rights reserved.
6 * Copyright (c) 2017-2019 European Software Marketing Ltd.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.aai.auth;
24 import com.fasterxml.jackson.core.JsonProcessingException;
25 import com.fasterxml.jackson.databind.JsonNode;
26 import com.fasterxml.jackson.databind.ObjectMapper;
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.util.ArrayList;
33 import java.util.Date;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map.Entry;
37 import java.util.Optional;
38 import java.util.Timer;
39 import java.util.TimerTask;
40 import java.util.concurrent.TimeUnit;
41 import org.onap.aai.babel.logging.ApplicationMsgs;
42 import org.onap.aai.babel.logging.LogHelper;
44 /** Authentication and authorization by user and role. */
45 public class AAIMicroServiceAuthCore {
47 private static LogHelper applicationLogger = LogHelper.INSTANCE;
50 * The default policy file is expected to be located in either one of
52 * <li><code>$CONFIG_HOME/auth_policy.json</code></li>
53 * <li><code>$CONFIG_HOME/auth/auth_policy.json</code></li>
55 * Note that if <code>CONFIG_HOME</code> is not set then assume it has a value of <code>$APP_HOME/appconfig</code>
57 private static String defaultAuthFileName = "auth_policy.json";
59 private static boolean usersInitialized = false;
60 private static HashMap<String, AAIAuthUser> users;
61 private static boolean timerSet = false;
62 private static Timer timer = null;
63 private static String policyAuthFileName;
65 public enum HTTP_METHODS {
66 GET, PUT, DELETE, HEAD, POST
70 private AAIMicroServiceAuthCore() {}
72 public static String getDefaultAuthFileName() {
73 return defaultAuthFileName;
76 public static void setDefaultAuthFileName(String defaultAuthFileName) {
77 AAIMicroServiceAuthCore.defaultAuthFileName = defaultAuthFileName;
80 public static synchronized void init(String authPolicyFile) throws AAIAuthException {
82 policyAuthFileName = AAIMicroServiceAuthCore.getConfigFile(authPolicyFile);
83 } catch (IOException e) {
84 applicationLogger.debug("Exception while retrieving policy file.");
85 applicationLogger.error(ApplicationMsgs.PROCESS_REQUEST_ERROR, e);
86 throw new AAIAuthException(e.getMessage());
89 if (policyAuthFileName == null) {
90 throw new AAIAuthException("Auth policy file could not be found");
92 AAIMicroServiceAuthCore.reloadUsers();
95 TimerTask task = new AuthFileWatcher(new File(policyAuthFileName));
100 long period = TimeUnit.SECONDS.toMillis(1);
101 timer.schedule(task, new Date(), period);
102 applicationLogger.debug("Config Watcher Interval = " + period);
106 public static void cleanup() {
110 public static String getConfigFile(String authPolicyFile) throws IOException {
111 return locateConfigFile(authPolicyFile).orElse(locateConfigFile(defaultAuthFileName).orElse(null));
115 * Locate the auth policy file by its name or path.
117 * <li>First try to use the absolute path to the file (if provided), or instead locate the path relative to the
118 * current (or user) dir.</li>
119 * <li>If this fails, try resolving the path relative to the configuration home location (either
120 * <code>$CONFIG_HOME</code> or <code>$APP_HOME/appconfig</code>).</li>
121 * <li>If this fails try resolving relative to the <code>auth</code> folder under configuration home.</li>
123 * @param authPolicyFile
125 * @return the Optional canonical path to the located policy file
126 * @throws IOException
127 * if the construction of the canonical pathname requires filesystem queries which cause I/O error(s)
129 private static Optional<String> locateConfigFile(String authPolicyFile) throws IOException {
130 if (authPolicyFile != null) {
131 List<Path> paths = new ArrayList<>();
132 paths.add(Paths.get("."));
134 String configHome = System.getProperty("CONFIG_HOME");
135 if (configHome == null) {
136 configHome = System.getProperty("APP_HOME") + "/appconfig";
139 paths.add(Paths.get(configHome));
140 paths.add(Paths.get(configHome).resolve("auth"));
142 for (Path path : paths) {
143 File authFile = path.resolve(authPolicyFile).toFile();
144 if (authFile.exists()) {
145 return Optional.of(authFile.getCanonicalPath());
150 return Optional.empty();
153 public static synchronized void reloadUsers() throws AAIAuthException {
154 users = new HashMap<>();
156 ObjectMapper mapper = new ObjectMapper();
158 applicationLogger.debug("Reading from " + policyAuthFileName);
159 JsonNode rootNode = mapper.readTree(new File(policyAuthFileName));
160 for (JsonNode roleNode : rootNode.path("roles")) {
161 String roleName = roleNode.path("name").asText();
162 AAIAuthRole r = new AAIAuthRole();
163 installFunctionOnRole(roleNode.path("functions"), roleName, r);
164 assignRoleToUsers(roleNode.path("users"), roleName, r);
166 } catch (FileNotFoundException e) {
167 throw new AAIAuthException("Auth policy file could not be found", e);
168 } catch (JsonProcessingException e) {
169 throw new AAIAuthException("Error processing Auth policy file ", e);
170 } catch (IOException e) {
171 throw new AAIAuthException("Error reading Auth policy file", e);
174 usersInitialized = true;
177 private static void installFunctionOnRole(JsonNode functionsNode, String roleName, AAIAuthRole r) {
178 for (JsonNode functionNode : functionsNode) {
179 String function = functionNode.path("name").asText();
180 JsonNode methodsNode = functionNode.path("methods");
181 boolean hasMethods = false;
182 for (JsonNode method_node : methodsNode) {
183 String methodName = method_node.path("name").asText();
185 String func = methodName + ":" + function;
186 applicationLogger.debug("Installing function " + func + " on role " + roleName);
187 r.addAllowedFunction(func);
191 for (HTTP_METHODS meth : HTTP_METHODS.values()) {
192 String func = meth.toString() + ":" + function;
193 applicationLogger.debug("Installing (all methods) " + func + " on role " + roleName);
194 r.addAllowedFunction(func);
200 private static void assignRoleToUsers(JsonNode usersNode, String roleName, AAIAuthRole r) {
201 for (JsonNode userNode : usersNode) {
202 String name = userNode.path("username").asText().toLowerCase();
204 if (users.containsKey(name)) {
205 user = users.get(name);
207 user = new AAIAuthUser();
209 applicationLogger.debug("Assigning " + roleName + " to user " + name);
210 user.addRole(roleName, r);
211 users.put(name, user);
215 public static class AAIAuthUser {
216 private HashMap<String, AAIAuthRole> roles;
218 public AAIAuthUser() {
219 this.roles = new HashMap<>();
222 public void addRole(String roleName, AAIAuthRole r) {
223 this.roles.put(roleName, r);
226 public boolean checkAllowed(String checkFunc) {
227 for (Entry<String, AAIAuthRole> role_entry : roles.entrySet()) {
228 AAIAuthRole role = role_entry.getValue();
229 if (role.hasAllowedFunction(checkFunc)) {
237 public static class AAIAuthRole {
239 private List<String> allowedFunctions;
241 public AAIAuthRole() {
242 this.allowedFunctions = new ArrayList<>();
245 public void addAllowedFunction(String func) {
246 this.allowedFunctions.add(func);
249 public boolean hasAllowedFunction(String afunc) {
250 return this.allowedFunctions.contains(afunc);
254 public static boolean authorize(String username, String authFunction) throws AAIAuthException {
255 if (!usersInitialized || users == null) {
256 throw new AAIAuthException("Auth module not initialized");
258 if (users.containsKey(username)) {
259 if (users.get(username).checkAllowed(authFunction)) {
260 logAuthenticationResult(username, authFunction, "AUTH ACCEPTED");
263 logAuthenticationResult(username, authFunction, "AUTH FAILED");
267 logAuthenticationResult(username, authFunction, "User not found");
272 private static void logAuthenticationResult(String username, String authFunction, String result) {
273 applicationLogger.debug(result + ": " + username + " on function " + authFunction);