diff options
author | Kajur, Harish (vk250x) <vk250x@att.com> | 2020-02-21 14:34:10 -0500 |
---|---|---|
committer | Harish Venkata Kajur <vk250x@att.com> | 2020-02-25 23:59:33 -0500 |
commit | 98749c47bbb5f5ddcc1c4f0690b79c7288f6bdd6 (patch) | |
tree | a472ce2edabd497b643917f44785b775fa16e15e /aai-aaf-auth | |
parent | e654645a50a0d028d8e67ea997f84efe8d28a6a0 (diff) |
Enhancements for the aai-common library
Issue-ID: AAI-2806
Change-Id: I2dbb46b897b35136ac1bb802978d3f974af1b307
Signed-off-by: Kajur, Harish (vk250x) <vk250x@att.com>
Diffstat (limited to 'aai-aaf-auth')
43 files changed, 2913 insertions, 0 deletions
diff --git a/aai-aaf-auth/pom.xml b/aai-aaf-auth/pom.xml new file mode 100644 index 00000000..87eb9537 --- /dev/null +++ b/aai-aaf-auth/pom.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-parent</artifactId> + <version>1.6.6-SNAPSHOT</version> + <relativePath>../aai-parent/pom.xml</relativePath> + </parent> + <artifactId>aai-aaf-auth</artifactId> + <name>aai-aaf-auth</name> + <packaging>jar</packaging> + <dependencies> + <dependency> + <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-els-onap-logging</artifactId> + </dependency> + <dependency> + <groupId>org.onap.aaf.authz</groupId> + <artifactId>aaf-cadi-core</artifactId> + </dependency> + <dependency> + <groupId>org.onap.aaf.authz</groupId> + <artifactId>aaf-cadi-aaf</artifactId> + </dependency> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + <exclusions> + <exclusion> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-tomcat</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + </dependency> + </dependencies> +</project> diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIAuthCore.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIAuthCore.java new file mode 100644 index 00000000..c64251ad --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIAuthCore.java @@ -0,0 +1,377 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.eclipse.jetty.util.security.Password; +import org.onap.aai.aaf.auth.exceptions.AAIUnrecognizedFunctionException; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.util.AAIConfig; +import org.onap.aai.util.AAIConstants; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * The Class AAIAuthCore. + */ +public final class AAIAuthCore { + + private static final Logger LOGGER = LoggerFactory.getLogger(AAIAuthCore.class); + + private static final String ERROR_CODE_AAI_4001 = "AAI_4001"; + + private String globalAuthFileName = AAIConstants.AAI_AUTH_CONFIG_FILENAME; + + private final Pattern AUTH_POLICY_PATTERN; + private final Set<String> validFunctions = new HashSet<>(); + private Map<String, AAIUser> users; + private boolean timerSet = false; + private Timer timer = null; + + private String basePath; + + /** + * Instantiates a new AAI auth core. + */ + public AAIAuthCore(String basePath) { + this(basePath, AAIConstants.AAI_AUTH_CONFIG_FILENAME); + } + + public AAIAuthCore(String basePath, String filename){ + this.basePath = basePath; + this.globalAuthFileName = filename; + AUTH_POLICY_PATTERN = Pattern.compile("^" + this.basePath + "/v\\d+/([\\w\\-]*)"); + init(); + } + + public AAIAuthCore(String basePath, String filename, String pattern){ + this.basePath = basePath; + this.globalAuthFileName = filename; + AUTH_POLICY_PATTERN = Pattern.compile(pattern); + init(); + } + + /** + * Inits the. + */ + private synchronized void init() { + + LOGGER.debug("Initializing Auth Policy Config"); + + reloadUsers(); + + /* + * this timer code is setting up a recurring task that checks if the + * auth config file has been updated and reloads the users if so to get + * the most up to date info (that update check logic is within + * FileWatcher) + * + * the timing this method uses is coarser than the frequency of requests + * AI&I gets so we're looking at better ways of doing this (TODO) + */ + TimerTask task = new FileWatcher(new File(globalAuthFileName)) { + @Override + protected void onChange(File file) { + reloadUsers(); + } + }; + + if (!timerSet) { + timerSet = true; + timer = new Timer(); + + // repeat the check every second + timer.schedule(task, new Date(), 10000); + } + LOGGER.debug("Static Initializiation complete"); + } + + /** + * Cleanup. + */ + // just ends the auth config file update checking timer + public void cleanup() { + timer.cancel(); + } + + /** + * Reload users. + */ + /* + * this essentially takes the data file, which is organized role-first with + * users under each role and converts it to data organized user-first with + * each user containing their role with its associated allowed functions + * this data stored in the class field users + */ + private synchronized void reloadUsers() { + + Map<String, AAIUser> tempUsers = new HashMap<>(); + + try { + LOGGER.debug("Reading from " + globalAuthFileName); + String authFile = new String(Files.readAllBytes(Paths.get(globalAuthFileName))); + + JsonParser parser = new JsonParser(); + JsonObject authObject = parser.parse(authFile).getAsJsonObject(); + if (authObject.has("roles")) { + JsonArray roles = authObject.getAsJsonArray("roles"); + for (JsonElement role : roles) { + if (role.isJsonObject()) { + JsonObject roleObject = role.getAsJsonObject(); + String roleName = roleObject.get("name").getAsString(); + Map<String, Boolean> usrs = this.getUsernamesFromRole(roleObject); + List<String> aaiFunctions = this.getAAIFunctions(roleObject); + + usrs.forEach((key, value) -> { + final AAIUser au = tempUsers.getOrDefault(key, new AAIUser(key, value)); + au.addRole(roleName); + aaiFunctions.forEach(f -> { + List<String> httpMethods = this.getRoleHttpMethods(f, roleObject); + httpMethods.forEach(hm -> au.setUserAccess(f, hm)); + this.validFunctions.add(f); + }); + + tempUsers.put(key, au); + + }); + } + } + if (!tempUsers.isEmpty()) { + users = tempUsers; + } + } + } catch (FileNotFoundException e) { + ErrorLogHelper.logError(ERROR_CODE_AAI_4001, globalAuthFileName + ". Exception: " + e); + } catch (JsonProcessingException e) { + ErrorLogHelper.logError(ERROR_CODE_AAI_4001, globalAuthFileName + ". Not valid JSON: " + e); + } catch (Exception e) { + ErrorLogHelper.logError(ERROR_CODE_AAI_4001, globalAuthFileName + ". Exception caught: " + e); + } + } + + private List<String> getRoleHttpMethods(String aaiFunctionName, JsonObject roleObject) { + List<String> httpMethods = new ArrayList<>(); + + JsonArray ja = roleObject.getAsJsonArray("functions"); + for (JsonElement je : ja) { + if (je.isJsonObject() && je.getAsJsonObject().has("name") + && je.getAsJsonObject().get("name").getAsString().equals(aaiFunctionName)) { + JsonArray jaMeth = je.getAsJsonObject().getAsJsonArray("methods"); + for (JsonElement jeMeth : jaMeth) { + if (jeMeth.isJsonObject() && jeMeth.getAsJsonObject().has("name")) { + httpMethods.add(jeMeth.getAsJsonObject().get("name").getAsString()); + } + } + } + } + + return httpMethods; + } + + private List<String> getAAIFunctions(JsonObject roleObject) { + List<String> aaiFunctions = new ArrayList<>(); + + JsonArray ja = roleObject.getAsJsonArray("functions"); + for (JsonElement je : ja) { + if (je.isJsonObject() && je.getAsJsonObject().has("name")) { + aaiFunctions.add(je.getAsJsonObject().get("name").getAsString()); + } + } + + return aaiFunctions; + } + + private Map<String, Boolean> getUsernamesFromRole(JsonObject roleObject) throws UnsupportedEncodingException { + Map<String, Boolean> usernames = new HashMap<>(); + + JsonArray uja = roleObject.getAsJsonArray("users"); + for (JsonElement je : uja) { + if (je.isJsonObject()) { + if (je.getAsJsonObject().has("username")) { + if (je.getAsJsonObject().has("is-wildcard-id")) { + usernames.put(je.getAsJsonObject().get("username").getAsString().toLowerCase(), + je.getAsJsonObject().get("is-wildcard-id").getAsBoolean()); + } else { + usernames.put(je.getAsJsonObject().get("username").getAsString().toLowerCase(), false); + } + } else if (je.getAsJsonObject().has("user")) { + String auth = je.getAsJsonObject().get("user").getAsString() + ":" + + Password.deobfuscate(je.getAsJsonObject().get("pass").getAsString()); + String authorizationCode = new String(Base64.getEncoder().encode(auth.getBytes("utf-8"))); + usernames.put(authorizationCode, false); + } + } + } + + return usernames; + } + + public String getAuthPolicyFunctName(String uri) { + String authPolicyFunctionName = ""; + if (uri.startsWith(basePath + "/search")) { + authPolicyFunctionName = "search"; + } else if (uri.startsWith(basePath + "/recents")) { + authPolicyFunctionName = "recents"; + } else if (uri.startsWith(basePath + "/cq2gremlin")) { + authPolicyFunctionName = "cq2gremlin"; + } else if (uri.startsWith(basePath + "/cq2gremlintest")) { + authPolicyFunctionName = "cq2gremlintest"; + } else if (uri.startsWith(basePath + "/util/echo")) { + authPolicyFunctionName = "util"; + } else if (uri.startsWith(basePath + "/tools")) { + authPolicyFunctionName = "tools"; + } else { + Matcher match = AUTH_POLICY_PATTERN.matcher(uri); + if (match.find()) { + authPolicyFunctionName = match.group(1); + } + } + return authPolicyFunctionName; + } + + /** + * for backwards compatibility + * + * @param username + * @param uri + * @param httpMethod + * @param haProxyUser + * @return + * @throws AAIUnrecognizedFunctionException + */ + public boolean authorize(String username, String uri, String httpMethod, String haProxyUser) + throws AAIUnrecognizedFunctionException { + return authorize(username, uri, httpMethod, haProxyUser, null); + } + + /** + * + * @param username + * @param uri + * @param httpMethod + * @param haProxyUser + * @param issuer issuer of the cert + * @return + * @throws AAIUnrecognizedFunctionException + */ + public boolean authorize(String username, String uri, String httpMethod, String haProxyUser, String issuer) + throws AAIUnrecognizedFunctionException { + String aaiMethod = this.getAuthPolicyFunctName(uri); + if (!this.validFunctions.contains(aaiMethod) && !("info".equalsIgnoreCase(aaiMethod))) { + throw new AAIUnrecognizedFunctionException(aaiMethod); + } + boolean wildcardCheck = isWildcardIssuer(issuer); + boolean authorized; + LOGGER.debug( + "Authorizing the user for the request cert {}, haproxy header {}, aai method {}, httpMethod {}, cert issuer {}", + username, haProxyUser, aaiMethod, httpMethod, issuer); + Optional<AAIUser> oau = this.getUser(username, wildcardCheck); + if (oau.isPresent()) { + AAIUser au = oau.get(); + if (au.hasRole("HAProxy")) { + LOGGER.debug("User has HAProxy role"); + if ("GET".equalsIgnoreCase(httpMethod) && "util".equalsIgnoreCase(aaiMethod) && haProxyUser.isEmpty()) { + LOGGER.debug("Authorized user has HAProxy role with echo request"); + authorized = this.authorize(au, aaiMethod, httpMethod); + } else { + authorized = this.authorize(haProxyUser, uri, httpMethod, "", issuer); + } + } else { + LOGGER.debug("User doesn't have HAProxy role so assuming its a regular client"); + authorized = this.authorize(au, aaiMethod, httpMethod); + } + } else { + LOGGER.debug("User not found: " + username + " on function " + aaiMethod + " request type " + httpMethod); + authorized = false; + } + + return authorized; + } + + private boolean isWildcardIssuer(String issuer) { + if (issuer != null && !issuer.isEmpty()) { + List<String> validIssuers = Arrays + .asList(AAIConfig.get("aaf.valid.issuer.wildcard", UUID.randomUUID().toString()).split("\\|")); + for (String validIssuer : validIssuers) { + if (issuer.contains(validIssuer)) { + return true; + } + } + } + return false; + } + + /** + * returns aai user either matching the username or containing the wildcard. + * + * @param username + * @return + */ + public Optional<AAIUser> getUser(String username, boolean wildcardCheck) { + if (users.containsKey(username)) { + return Optional.of(users.get(username)); + } else if (wildcardCheck) { + List<AAIUser> laus = + users.entrySet().stream().filter(e -> e.getValue().isWildcard() && username.contains(e.getKey())) + .map(Map.Entry::getValue).collect(Collectors.toList()); + if (!laus.isEmpty()) { + return Optional.of(laus.get(0)); + } + } + return Optional.empty(); + } + + /** + * + * @param aaiUser + * aai user with the username + * @param aaiMethod + * aai function the authorization is required on + * @param httpMethod + * http action user is attempting + * @return true, if successful + */ + private boolean authorize(AAIUser aaiUser, String aaiMethod, String httpMethod) { + if ("info".equalsIgnoreCase(aaiMethod)|| aaiUser.hasAccess(aaiMethod, httpMethod)) { + LOGGER.debug("AUTH ACCEPTED: " + aaiUser.getUsername() + " on function " + aaiMethod + " request type " + + httpMethod); + return true; + } else { + LOGGER.debug("AUTH FAILED: " + aaiUser.getUsername() + " on function " + aaiMethod + " request type " + + httpMethod); + return false; + } + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIUser.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIUser.java new file mode 100644 index 00000000..4512adb0 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIUser.java @@ -0,0 +1,81 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright © 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import java.util.*; + +public class AAIUser { + + private String username; + + private boolean isWildcard = false; + private Set<String> roles; + private Map<String, Set<String>> aaiFunctionToHttpMethod; + + public AAIUser(String username) { + this(username, false); + } + + public AAIUser(String username, boolean isWildcard) { + this.username = username; + this.roles = new HashSet<>(); + this.aaiFunctionToHttpMethod = new HashMap<>(); + this.isWildcard = isWildcard; + } + + public boolean isWildcard() { + return isWildcard; + } + + public String getUsername() { + return username; + } + + public void addRole(String role) { + this.roles.add(role); + } + + public boolean hasRole(String role) { + return this.roles.contains(role); + } + + public void setUserAccess(String aaiMethod, String... httpMethods) { + for (String httpMethod : httpMethods) { + this.addUserAccess(aaiMethod, httpMethod); + } + } + + private void addUserAccess(String aaiMethod, String httpMethod) { + Set<String> httpMethods = new HashSet<>(); + if (this.aaiFunctionToHttpMethod.containsKey(aaiMethod)) { + httpMethods = this.aaiFunctionToHttpMethod.get(aaiMethod); + } + httpMethods.add(httpMethod); + this.aaiFunctionToHttpMethod.put(aaiMethod, httpMethods); + } + + public boolean hasAccess(String aaiMethod, String httpMethod) { + return this.aaiFunctionToHttpMethod.getOrDefault(aaiMethod, Collections.emptySet()).contains(httpMethod); + } + +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestFilter.java new file mode 100644 index 00000000..9a02fe2c --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestFilter.java @@ -0,0 +1,114 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.onap.aaf.cadi.filter.CadiFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; + +import static org.onap.aai.aaf.auth.ResponseFormatter.errorResponse; + +/** + * The Class AafRequestFilter provides common auth filter methods + */ +public class AafRequestFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AafRequestFilter.class); + + public static void authenticationFilter(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain, CadiFilter cadiFilter, Properties props, String userChainPattern) + throws IOException, ServletException { + if (!request.getRequestURI().matches("^.*/util/echo$")) { + + List<String> cadiConfiguredIssuers = CertUtil.getCadiCertIssuers(props); + String issuer = CertUtil.getCertIssuer(request); + if (issuer == null || issuer.isEmpty()) { + errorResponse(request, response); + return; + } + issuer = issuer.replaceAll("\\s+", "").toUpperCase(); + + if (cadiConfiguredIssuers.contains(issuer)) { + LOGGER.debug("authenticationFilter CADI issuer " + issuer); + if (CertUtil.isHaProxy(request)) { + // get the end user/client mechid and use it in the user chain header value + String user = CertUtil.getMechId(request); + LOGGER.debug("authenticationFilter haProxy sent end user/mechid " + user); + if (user == null || user.isEmpty()) { + errorResponse(request, response); + return; + } + AafRequestWrapper reqWrapper = new AafRequestWrapper(request); + String userChainHdr = CertUtil.buildUserChainHeader(user, userChainPattern); + LOGGER.debug("User chain header value: " + userChainHdr); + reqWrapper.putHeader(CertUtil.AAF_USER_CHAIN_HDR, userChainHdr); + cadiFilter.doFilter(reqWrapper, response, filterChain); + } else { + cadiFilter.doFilter(request, response, filterChain); + } + if (response.getStatus() == 401 || response.getStatus() == 403) { + LOGGER.debug("authenticationFilter failed CADI authentication"); + errorResponse(request, response); + return; + } + } else { + filterChain.doFilter(request, response); + } + } else { + filterChain.doFilter(request, response); + } + } + + public static void authorizationFilter(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain, String permission, Properties props) throws IOException, ServletException { + if (request.getRequestURI().matches("^.*/util/echo$")) { + filterChain.doFilter(request, response); + } + List<String> cadiConfiguredIssuers = CertUtil.getCadiCertIssuers(props); + String issuer = CertUtil.getCertIssuer(request); + if (issuer == null || issuer.isEmpty()) { + errorResponse(request, response); + return; + } + issuer = issuer.replaceAll("\\s+", "").toUpperCase(); + Enumeration hdrs = request.getHeaders(CertUtil.AAF_USER_CHAIN_HDR); + while (hdrs.hasMoreElements()) { + String headerValue = (String) hdrs.nextElement(); + LOGGER.debug("authorizationFilter user chain headerValue=" + headerValue); + } + if ((cadiConfiguredIssuers.contains(issuer)) && (!request.isUserInRole(permission))) { + LOGGER.debug( + "authorizationFilter failed CADI authorization issuer=" + issuer + " permission=" + permission); + errorResponse(request, response); + } else { + filterChain.doFilter(request, response); + } + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestWrapper.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestWrapper.java new file mode 100644 index 00000000..0ecca679 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestWrapper.java @@ -0,0 +1,78 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.util.*; + +/** + * The AafRequestWrapper sets the user in the principal name + */ +public class AafRequestWrapper extends HttpServletRequestWrapper { + + private final Map<String, String> customHeaders; + + public AafRequestWrapper(HttpServletRequest request) { + super(request); + this.customHeaders = new HashMap<String, String>(); + } + + public void putHeader(String name, String value) { + this.customHeaders.put(name, value); + } + + @Override + public String getHeader(String name) { + String headerValue = customHeaders.get(name); + if (headerValue != null) { + return headerValue; + } + return (((HttpServletRequest) getRequest()).getHeader(name)); + } + + @Override + public Enumeration<String> getHeaderNames() { + Set<String> nameSet = new HashSet<String>(customHeaders.keySet()); + + Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames(); + while (e.hasMoreElements()) { + String headerName = e.nextElement(); + nameSet.add(headerName); + } + return Collections.enumeration(nameSet); + } + + @Override + public Enumeration<String> getHeaders(String name) { + String myHeaderValue = customHeaders.get(name); + Set<String> headerValueSet = new HashSet<String>(); + if (myHeaderValue != null) { + headerValueSet.add(myHeaderValue); + } + Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaders(name); + while (e.hasMoreElements()) { + String headerValue = e.nextElement(); + headerValueSet.add(headerValue); + } + return Collections.enumeration(headerValueSet); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/CertUtil.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/CertUtil.java new file mode 100644 index 00000000..334a3060 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/CertUtil.java @@ -0,0 +1,157 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.*; +import java.util.stream.Collectors; + +/** + * The Class CertUtil provides cert related utility methods. + */ +public class CertUtil { + public static final String DEFAULT_CADI_ISSUERS = + "CN=ATT AAF CADI Test Issuing CA 01, OU=CSO, O=ATT, C=US:CN=ATT AAF CADI Test Issuing CA 02, OU=CSO, O=ATT, C=US"; + public static final String CADI_PROP_FILES = "cadi_prop_files"; + public static final String CADI_ISSUERS_PROP_NAME = "cadi_x509_issuers"; + public static final String CADI_ISSUERS_SEPARATOR = ":"; + public static final String AAI_SSL_CLIENT_OU_HDR = "X-AAI-SSL-Client-OU"; + public static final String AAI_SSL_ISSUER_HDR = "X-AAI-SSL-Issuer"; + public static final String AAI_SSL_CLIENT_CN_HDR = "X-AAI-SSL-Client-CN"; + public static final String AAI_SSL_CLIENT_O_HDR = "X-AAI-SSL-Client-O"; + public static final String AAI_SSL_CLIENT_L_HDR = "X-AAI-SSL-Client-L"; + public static final String AAI_SSL_CLIENT_ST_HDR = "X-AAI-SSL-Client-ST"; + public static final String AAI_SSL_CLIENT_C_HDR = "X-AAI-SSL-Client-C"; + public static final String AAF_USER_CHAIN_HDR = "USER_CHAIN"; + public static final String AAF_ID = "<AAF-ID>"; + private static final Logger LOGGER = LoggerFactory.getLogger(CertUtil.class); + + public static String getAaiSslClientOuHeader(HttpServletRequest hsr) { + return (hsr.getHeader(AAI_SSL_CLIENT_OU_HDR)); + } + + public static boolean isHaProxy(HttpServletRequest hsr) { + + String haProxyUser = ""; + if (Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_CN_HDR)) || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_OU_HDR)) + || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_O_HDR)) + || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_L_HDR)) + || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_ST_HDR)) + || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_C_HDR))) { + haProxyUser = ""; + } else { + haProxyUser = String.format("CN=%s, OU=%s, O=\"%s\", L=%s, ST=%s, C=%s", + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_CN_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_OU_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_O_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_L_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_ST_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_C_HDR), "")).toLowerCase(); + } + if (!haProxyUser.isEmpty()) { + LOGGER.debug("isHaProxy haProxyUser=" + haProxyUser); + return true; + } + LOGGER.debug("isHaProxy haProxyUser not found"); + return false; + } + + public static String getMechId(HttpServletRequest hsr) { + String mechId = null; + String ou = getAaiSslClientOuHeader(hsr); + if ((ou != null) && (!ou.isEmpty())) { + String[] parts = ou.split(CADI_ISSUERS_SEPARATOR); + if (parts != null && parts.length >= 1) { + mechId = parts[0]; + } + } + LOGGER.debug("getMechId mechId=" + mechId); + return (mechId); + } + + public static String getCertIssuer(HttpServletRequest hsr) { + String issuer = hsr.getHeader(AAI_SSL_ISSUER_HDR); + if (issuer != null && !issuer.isEmpty()) { + LOGGER.debug("getCertIssuer issuer from header " + AAI_SSL_ISSUER_HDR + " " + issuer); + // the haproxy header replaces the ', ' with '/' and reverses on the '/' need to undo that. + List<String> broken = Arrays.asList(issuer.split("/")); + broken = broken.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList()); + Collections.reverse(broken); + issuer = String.join(", ", broken); + } else { + if (hsr.getAttribute("javax.servlet.request.cipher_suite") != null) { + X509Certificate[] certChain = + (X509Certificate[]) hsr.getAttribute("javax.servlet.request.X509Certificate"); + if (certChain != null && certChain.length > 0) { + X509Certificate clientCert = certChain[0]; + issuer = clientCert.getIssuerX500Principal().getName(); + LOGGER.debug("getCertIssuer issuer from client cert " + issuer); + } + } + } + return issuer; + } + + public static List<String> getCadiCertIssuers(Properties cadiProperties) { + + List<String> defaultList = new ArrayList<String>(); + List<String> resultList = new ArrayList<String>(); + + String[] cIssuers = DEFAULT_CADI_ISSUERS.split(CADI_ISSUERS_SEPARATOR); + for (String issuer : cIssuers) { + defaultList.add(issuer.replaceAll("\\s+", "").toUpperCase()); + } + try { + String certPropFileName = cadiProperties.getProperty(CADI_PROP_FILES); + String configuredIssuers = DEFAULT_CADI_ISSUERS; + Properties certProperties = new Properties(); + if (certPropFileName != null) { + certProperties.load(new FileInputStream(new File(certPropFileName))); + configuredIssuers = certProperties.getProperty(CADI_ISSUERS_PROP_NAME); + } + if ((configuredIssuers != null) && (!configuredIssuers.isEmpty())) { + cIssuers = configuredIssuers.split(CADI_ISSUERS_SEPARATOR); + for (String issuer : cIssuers) { + resultList.add(issuer.replaceAll("\\s+", "").toUpperCase()); + } + } + } catch (IOException ioe) { + return (defaultList); + } + if (resultList.isEmpty()) { + return defaultList; + } + LOGGER.debug("getCadiCertIssuers " + resultList.toString()); + return resultList; + } + + public static String buildUserChainHeader(String user, String userChainPattern) { + // aaf.userchain.pattern=<AAF-ID>:${aaf.userchain.service.reference}:${aaf.userchain.auth.type}:AS + return (userChainPattern.replaceAll(AAF_ID, user)); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/FileWatcher.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/FileWatcher.java new file mode 100644 index 00000000..45331ed9 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/FileWatcher.java @@ -0,0 +1,60 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import java.io.File; +import java.util.TimerTask; + +public abstract class FileWatcher extends TimerTask { + private long timeStamp; + private File file; + + /** + * Instantiates a new file watcher. + * + * @param file the file + */ + public FileWatcher(File file) { + this.file = file; + this.timeStamp = file.lastModified(); + } + + /** + * runs a timer task + * + * @see TimerTask#run + */ + public final void run() { + long timeStamp = file.lastModified(); + + if ((timeStamp - this.timeStamp) > 500) { + this.timeStamp = timeStamp; + onChange(file); + } + } + + /** + * On change. + * + * @param file the file + */ + protected abstract void onChange(File file); +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/ResponseFormatter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/ResponseFormatter.java new file mode 100644 index 00000000..d7c88e81 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/ResponseFormatter.java @@ -0,0 +1,57 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; + +public class ResponseFormatter { + + private static final String ACCEPT_HEADER = "accept"; + + public static void errorResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { + errorResponse(new AAIException("AAI_3300"), request, response); + } + + public static void errorResponse(AAIException exception, HttpServletRequest request, HttpServletResponse response) throws IOException { + + if(response.isCommitted()){ + return; + } + + String accept = request.getHeader(ACCEPT_HEADER) == null ? MediaType.APPLICATION_XML : request.getHeader(ACCEPT_HEADER); + + response.setStatus(exception.getErrorObject().getHTTPResponseCode().getStatusCode()); + response.setHeader("Content-Type", accept); + response.resetBuffer(); + + String resp = ErrorLogHelper.getRESTAPIErrorResponse(Collections.singletonList(MediaType.valueOf(accept)), exception, new ArrayList<>()); + response.getOutputStream().print(resp); + response.flushBuffer(); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/exceptions/AAIUnrecognizedFunctionException.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/exceptions/AAIUnrecognizedFunctionException.java new file mode 100644 index 00000000..c6a97ac5 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/exceptions/AAIUnrecognizedFunctionException.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright © 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth.exceptions; + +import org.onap.aai.exceptions.AAIException; + +public class AAIUnrecognizedFunctionException extends AAIException { + + private static final String AAI_3012 = "AAI_3012"; + private static final long serialVersionUID = 3297064867724071290L; + + public AAIUnrecognizedFunctionException() { + } + + public AAIUnrecognizedFunctionException(String message) { + super(AAI_3012, message); + } + + public AAIUnrecognizedFunctionException(Throwable cause) { + super(AAI_3012, cause); + } + + public AAIUnrecognizedFunctionException(String message, Throwable cause) { + super(AAI_3012, cause, message); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafAuthorizationFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafAuthorizationFilter.java new file mode 100644 index 00000000..9f2782a4 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafAuthorizationFilter.java @@ -0,0 +1,119 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.filters; + +import org.onap.aai.aaf.auth.ResponseFormatter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * AAF authorization filter + */ + +@Component +@Profile(AafProfiles.AAF_AUTHENTICATION) +@PropertySource(value = "file:${CONFIG_HOME}/aaf/permissions.properties", ignoreResourceNotFound = true) +@PropertySource(value = "file:${server.local.startpath}/aaf/permissions.properties", ignoreResourceNotFound = true) +public class AafAuthorizationFilter extends OrderedRequestContextFilter { + + private static final String ADVANCED = "advanced"; + private static final String BASIC = "basic"; + + private final String type; + private final String instance; + + private GremlinFilter gremlinFilter; + + private List<String> advancedKeywordsList; + + @Autowired + public AafAuthorizationFilter( + GremlinFilter gremlinFilter, + @Value("${permission.type}") String type, + @Value("${permission.instance}") String instance, + @Value("${advanced.keywords.list:}") String advancedKeys + ) { + this.gremlinFilter = gremlinFilter; + this.type = type; + this.instance = instance; + if(advancedKeys == null || advancedKeys.isEmpty()){ + this.advancedKeywordsList = new ArrayList<>(); + } else { + this.advancedKeywordsList = Arrays.stream(advancedKeys.split(",")) + .collect(Collectors.toList()); + } + this.setOrder(FilterPriority.AAF_AUTHORIZATION.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + if(request.getRequestURI().endsWith("/query")){ + gremlinFilter.doBasicAuthFilter(request, response, filterChain); + } else { + + String permission = null; + + if(advancedKeywordsList == null || advancedKeywordsList.size() == 0) { + permission = String.format("%s|%s|%s", type, instance, request.getMethod().toLowerCase()); + } else { + + boolean isAdvanced = this.containsAdvancedKeywords(request); + + //if the URI contains advanced.keywords it's an advanced query + String queryType = isAdvanced ? ADVANCED : BASIC; + permission = String.format("%s|%s|%s", type, instance, queryType); + } + + boolean isAuthorized = request.isUserInRole(permission); + + if(!isAuthorized){ + ResponseFormatter.errorResponse(request, response); + } else { + filterChain.doFilter(request,response); + } + + } + } + + private boolean containsAdvancedKeywords(HttpServletRequest request) { + String uri = request.getRequestURI(); + for (String keyword: advancedKeywordsList) { + if (uri.contains(keyword)) { + return true; + } + } + return false; + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertAuthorizationFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertAuthorizationFilter.java new file mode 100644 index 00000000..7ec6bb64 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertAuthorizationFilter.java @@ -0,0 +1,107 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.filters; + +import org.onap.aai.aaf.auth.AafRequestFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; + + +/** + * AAF with client cert authorization filter + */ + +@Component +@Profile(AafProfiles.AAF_CERT_AUTHENTICATION) +@PropertySource(value = "file:${CONFIG_HOME}/aaf/permissions.properties", ignoreResourceNotFound = true) +@PropertySource(value = "file:${server.local.startpath}/aaf/permissions.properties", ignoreResourceNotFound = true) +public class AafCertAuthorizationFilter extends OrderedRequestContextFilter { + + private static final String ADVANCED = "advanced"; + private static final String BASIC = "basic"; + + String type; + + String instance; + + private CadiProps cadiProps; + + private List<String> advancedKeywordsList; + + @Autowired + public AafCertAuthorizationFilter( + @Value("${permission.type}") String type, + @Value("${permission.instance}") String instance, + @Value("${advanced.keywords.list:}") String advancedKeys, + CadiProps cadiProps + ) { + this.type = type; + this.instance = instance; + this.cadiProps = cadiProps; + if(advancedKeys == null || advancedKeys.isEmpty()){ + this.advancedKeywordsList = new ArrayList<>(); + } else { + this.advancedKeywordsList = Arrays.stream(advancedKeys.split(",")) + .collect(Collectors.toList()); + } + this.setOrder(FilterPriority.AAF_CERT_AUTHORIZATION.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + if(advancedKeywordsList == null || advancedKeywordsList.size() == 0){ + String permission = String.format("%s|%s|%s", type, instance, request.getMethod().toLowerCase()); + AafRequestFilter.authorizationFilter(request, response, filterChain, permission, cadiProps.getCadiProperties()); + } else { + boolean isAdvanced = this.containsAdvancedKeywords(request); + + //if the URI contains advanced.keywords it's an advanced query + String queryType = isAdvanced ? ADVANCED : BASIC; + String permission = String.format("%s|%s|%s", type, instance, queryType); + AafRequestFilter.authorizationFilter(request, response, filterChain, permission, cadiProps.getCadiProperties()); + } + } + + private boolean containsAdvancedKeywords(HttpServletRequest request) { + String uri = request.getRequestURI(); + for (String keyword: advancedKeywordsList) { + if (uri.contains(keyword)) { + return true; + } + } + return false; + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertFilter.java new file mode 100644 index 00000000..71238cfc --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertFilter.java @@ -0,0 +1,111 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.aai.aaf.auth.AafRequestFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * AAF with client cert authentication filter + */ + +@Component +@Profile(AafProfiles.AAF_CERT_AUTHENTICATION) +@PropertySource(value = "file:${CONFIG_HOME}/aaf/permissions.properties", ignoreResourceNotFound = true) +@PropertySource(value = "file:${server.local.startpath}/aaf/permissions.properties", ignoreResourceNotFound = true) +public class AafCertFilter extends OrderedRequestContextFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AafCertFilter.class); + + String aafUserChainPattern; + + private final CadiFilter cadiFilter; + + private final CadiProps cadiProps; + + @Autowired + public AafCertFilter( @Value("${aaf.userchain.pattern}") String aafUserChainPattern, + CadiProps cadiProps) throws IOException, ServletException { + + this.aafUserChainPattern = aafUserChainPattern; + this.cadiProps = cadiProps; + cadiFilter = new CadiFilter(new PropAccess((level,element)->{ + switch (level) { + case DEBUG: + LOGGER.debug(buildMsg(element)); + break; + case INFO: + case AUDIT: + LOGGER.info(buildMsg(element)); + break; + case WARN: + LOGGER.warn(buildMsg(element)); + break; + case ERROR: + LOGGER.error(buildMsg(element)); + break; + case INIT: + LOGGER.info(buildMsg(element)); + break; + case TRACE: + LOGGER.trace(buildMsg(element)); + break; + case NONE: + break; + } + }, new String[]{"cadi_prop_files=" + cadiProps.getCadiFileName()} )); + this.setOrder(FilterPriority.AAF_CERT_AUTHENTICATION.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + AafRequestFilter.authenticationFilter(request, response, filterChain, cadiFilter, cadiProps.getCadiProperties(), aafUserChainPattern); + } + private String buildMsg(Object[] objects) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for ( Object o: objects ) { + if (first) { + first = false; + } + else { + sb.append(' '); + } + sb.append(o.toString()); + } + return (sb.toString()); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafFilter.java new file mode 100644 index 00000000..16d9afd2 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafFilter.java @@ -0,0 +1,108 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.aai.aaf.auth.ResponseFormatter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * AAF authentication filter + */ + +@Component +@Profile(AafProfiles.AAF_AUTHENTICATION) +public class AafFilter extends OrderedRequestContextFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AafCertFilter.class); + + private final CadiFilter cadiFilter; + + @Autowired + public AafFilter(CadiProps cadiProps) throws IOException, ServletException { + cadiFilter = new CadiFilter(new PropAccess((level,element)->{ + switch (level) { + case DEBUG: + LOGGER.debug(buildMsg(element)); + break; + case INFO: + case AUDIT: + LOGGER.info(buildMsg(element)); + break; + case WARN: + LOGGER.warn(buildMsg(element)); + break; + case ERROR: + LOGGER.error(buildMsg(element)); + break; + case INIT: + LOGGER.info(buildMsg(element)); + break; + case TRACE: + LOGGER.trace(buildMsg(element)); + break; + case NONE: + break; + } + }, new String[]{"cadi_prop_files=" + cadiProps.getCadiFileName()} )); + this.setOrder(FilterPriority.AAF_AUTHENTICATION.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + if (!request.getRequestURI().matches("^.*/util/echo$")) { + cadiFilter.doFilter(request, response, filterChain); + if (response.getStatus() == 401 || response.getStatus() == 403) { + ResponseFormatter.errorResponse(request, response); + } + } else { + filterChain.doFilter(request, response); + } + } + + private String buildMsg(Object[] objects) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for ( Object o: objects ) { + if (first) { + first = false; + } + else { + sb.append(' '); + } + sb.append(o.toString()); + } + return (sb.toString()); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafProfiles.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafProfiles.java new file mode 100644 index 00000000..b587716e --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafProfiles.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.aaf.filters; + +public class AafProfiles { + + // AAF Basic Auth + public static final String AAF_AUTHENTICATION = "aaf-auth"; + + // AAF Auth with Client Certs + public static final String AAF_CERT_AUTHENTICATION = "aaf-cert-auth"; + + public static final String TWO_WAY_SSL = "two-way-ssl"; + + private AafProfiles(){} +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/CadiProps.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/CadiProps.java new file mode 100644 index 00000000..35e88f5f --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/CadiProps.java @@ -0,0 +1,81 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +// This component will be created if and only if any of the following profiles are active +@Component +@Profile({ + AafProfiles.AAF_CERT_AUTHENTICATION, + AafProfiles.AAF_AUTHENTICATION, + AafProfiles.TWO_WAY_SSL +}) +public class CadiProps { + + private static final Logger LOGGER = LoggerFactory.getLogger(CadiProps.class); + + private String cadiFileName; + + private Properties cadiProperties; + + @Autowired + public CadiProps(@Value("${aaf.cadi.file:./resources/cadi.properties}") String filename){ + cadiFileName = filename; + cadiProperties = new Properties(); + } + + @PostConstruct + public void init() throws IOException { + + File cadiFile = new File(cadiFileName); + + if(!cadiFile.exists()){ + LOGGER.warn("Unable to find the cadi file in the given path {} so loading cadi.properties from classloader", cadiFileName); + InputStream is = this.getClass().getClassLoader().getResourceAsStream("cadi.properties"); + cadiProperties.load(is); + } else { + LOGGER.info("Successfully found the file {} and started loading the properties from it", cadiFileName); + cadiFileName = cadiFile.getAbsolutePath(); + try (InputStream inputStream = new FileInputStream(cadiFile)) { + cadiProperties.load(inputStream); + } + + } + } + public String getCadiFileName() { + return cadiFileName; + } + public Properties getCadiProperties(){ + return cadiProperties; + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/FilterPriority.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/FilterPriority.java new file mode 100644 index 00000000..17b9f0e4 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/FilterPriority.java @@ -0,0 +1,39 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.aaf.filters; + +import org.springframework.core.Ordered; + +public enum FilterPriority { + + AAF_AUTHENTICATION(Ordered.HIGHEST_PRECEDENCE), + AAF_AUTHORIZATION(Ordered.HIGHEST_PRECEDENCE + 1), //higher number = lower priority + AAF_CERT_AUTHENTICATION(Ordered.HIGHEST_PRECEDENCE + 2 ), + AAF_CERT_AUTHORIZATION(Ordered.HIGHEST_PRECEDENCE + 3), + TWO_WAY_SSL_AUTH(Ordered.HIGHEST_PRECEDENCE + 4); + + private final int priority; + + FilterPriority(final int p) { + priority = p; + } + + public int getPriority() { return priority; } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/GremlinFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/GremlinFilter.java new file mode 100644 index 00000000..23ff0c6d --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/GremlinFilter.java @@ -0,0 +1,99 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.commons.io.IOUtils; +import org.onap.aai.aaf.auth.ResponseFormatter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +@Component +@Profile({ + AafProfiles.AAF_CERT_AUTHENTICATION, + AafProfiles.AAF_AUTHENTICATION +}) +public class GremlinFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(GremlinFilter.class); + + private static final String ADVANCED = "advanced"; + private static final String BASIC = "basic"; + private static final Pattern ECHO_ENDPOINT = Pattern.compile("^.*/util/echo$"); + + String type; + + String instance; + + private CadiProps cadiProps; + + @Autowired + public GremlinFilter( + @Value("${permission.type}") String type, + @Value("${permission.instance}") String instance, + CadiProps cadiProps + ) { + this.type = type; + this.instance = instance; + this.cadiProps = cadiProps; + } + + public void doBasicAuthFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + PayloadBufferingRequestWrapper requestBufferWrapper = new PayloadBufferingRequestWrapper(request); + + if(ECHO_ENDPOINT.matcher(request.getRequestURI()).matches()){ + filterChain.doFilter(requestBufferWrapper, response); + } + + String payload = IOUtils.toString(requestBufferWrapper.getInputStream(), StandardCharsets.UTF_8.name()); + boolean containsWordGremlin = payload.contains("\"gremlin\""); + + //if the requestBufferWrapper contains the word "gremlin" it's an "advanced" query needing an "advanced" role + String permissionBasic = String.format("%s|%s|%s", type, instance, BASIC); + String permissionAdvanced = String.format("%s|%s|%s", type, instance, ADVANCED); + + boolean isAuthorized; + + if(containsWordGremlin){ + isAuthorized = requestBufferWrapper.isUserInRole(permissionAdvanced); + }else{ + isAuthorized = requestBufferWrapper.isUserInRole(permissionAdvanced) || requestBufferWrapper.isUserInRole(permissionBasic); + } + + if(!isAuthorized){ + String name = requestBufferWrapper.getUserPrincipal() != null ? requestBufferWrapper.getUserPrincipal().getName() : "unknown"; + LOGGER.info("User " + name + " does not have a role for " + (containsWordGremlin ? "gremlin" : "non-gremlin") + " query" ); + ResponseFormatter.errorResponse(request, response); + } else { + filterChain.doFilter(requestBufferWrapper,response); + } + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/PayloadBufferingRequestWrapper.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/PayloadBufferingRequestWrapper.java new file mode 100644 index 00000000..eb8a61dd --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/PayloadBufferingRequestWrapper.java @@ -0,0 +1,50 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.aaf.filters; + +import org.apache.commons.io.IOUtils; +import org.onap.aaf.cadi.BufferedServletInputStream; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** + * This class buffers the payload of the servlet request. The reason is that we access the payload multiple times, + * which is not supported by the request per se. + */ + +class PayloadBufferingRequestWrapper extends HttpServletRequestWrapper { + + private byte[] buffer; + + PayloadBufferingRequestWrapper(HttpServletRequest req) throws IOException { + super(req); + this.buffer = IOUtils.toByteArray(req.getInputStream()); + } + + @Override + public ServletInputStream getInputStream() { + ByteArrayInputStream bais = new ByteArrayInputStream(this.buffer); + return new BufferedServletInputStream(bais); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/TwoWaySslAuthorization.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/TwoWaySslAuthorization.java new file mode 100644 index 00000000..0e206c50 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/TwoWaySslAuthorization.java @@ -0,0 +1,186 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.onap.aai.aaf.auth.AAIAuthCore; +import org.onap.aai.aaf.auth.CertUtil; +import org.onap.aai.aaf.auth.ResponseFormatter; +import org.onap.aai.exceptions.AAIException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.security.auth.x500.X500Principal; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.*; + +@Component +@Profile("two-way-ssl") +public class TwoWaySslAuthorization extends OrderedRequestContextFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(TwoWaySslAuthorization.class); + + public static final String HTTP_METHOD_OVERRIDE = "X-HTTP-Method-Override"; + + public static final String MERGE_PATCH = "MERGE_PATCH"; + + @Autowired + private Environment environment; + + @Autowired + private AAIAuthCore aaiAuthCore; + + @Autowired + private CadiProps cadiProps; + + public TwoWaySslAuthorization(){ + this.setOrder(FilterPriority.TWO_WAY_SSL_AUTH.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + + String uri = request.getRequestURI(); + String httpMethod = getHttpMethod(request); + + Optional<String> authUser = getUser(request); + + if (authUser.isPresent()) { + Properties cadiProperties = cadiProps.getCadiProperties(); + + String issuer = CertUtil.getCertIssuer(request); + if (issuer == null || issuer.isEmpty()) { + AAIException aaie = new AAIException("AAI_9107"); + ResponseFormatter.errorResponse(aaie, request, response); + return; + } + issuer = issuer.replaceAll("\\s+","").toUpperCase(); + + List<String> cadiConfiguredIssuers = CertUtil.getCadiCertIssuers(cadiProperties); + boolean isAafAuthProfileActive = this.isAafAuthProfileActive(); + if ((!isAafAuthProfileActive) || (!cadiConfiguredIssuers.contains(issuer)) ) { + try { + this.authorize(uri, httpMethod, authUser.get(), this.getHaProxyUser(request), issuer); + } catch (AAIException e) { + ResponseFormatter.errorResponse(e, request, response); + return; + } + } + } else { + AAIException aaie = new AAIException("AAI_9107"); + ResponseFormatter.errorResponse(aaie, request, response); + return; + } + filterChain.doFilter(request, response); + } + + + private String getHttpMethod(HttpServletRequest request) { + String httpMethod = request.getMethod(); + if ("POST".equalsIgnoreCase(httpMethod) + && "PATCH".equals(request.getHeader(HTTP_METHOD_OVERRIDE))) { + httpMethod = MERGE_PATCH; + } + if (httpMethod.equalsIgnoreCase(MERGE_PATCH) || "patch".equalsIgnoreCase(httpMethod)) { + httpMethod = "PUT"; + } + return httpMethod; + } + + private Optional<String> getUser(HttpServletRequest hsr) { + String authUser = null; + if (hsr.getAttribute("javax.servlet.request.cipher_suite") != null) { + X509Certificate[] certChain = (X509Certificate[]) hsr.getAttribute("javax.servlet.request.X509Certificate"); + + /* + * If the certificate is null or the certificate chain length is zero Then + * retrieve the authorization in the request header Authorization Check that it + * is not null and that it starts with Basic and then strip the basic portion to + * get the base64 credentials Check if this is contained in the AAIBasicAuth + * Singleton class If it is, retrieve the username associated with that + * credentials and set to authUser Otherwise, get the principal from certificate + * and use that authUser + */ + + if (certChain == null || certChain.length == 0) { + + String authorization = hsr.getHeader("Authorization"); + + if (authorization != null && authorization.startsWith("Basic ")) { + authUser = authorization.replace("Basic ", ""); + } + + } else { + X509Certificate clientCert = certChain[0]; + X500Principal subjectDN = clientCert.getSubjectX500Principal(); + authUser = subjectDN.toString().toLowerCase(); + } + } + + return Optional.ofNullable(authUser); + } + + private String getHaProxyUser(HttpServletRequest hsr) { + String haProxyUser; + if (Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-CN")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-OU")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-O")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-L")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-ST")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-C"))) { + haProxyUser = ""; + } else { + haProxyUser = String.format("CN=%s, OU=%s, O=\"%s\", L=%s, ST=%s, C=%s", + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-CN"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-OU"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-O"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-L"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-ST"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-C"), "")).toLowerCase(); + } + return haProxyUser; + } + + private void authorize(String uri, String httpMethod, String authUser, String haProxyUser, String issuer) throws AAIException { + if (!aaiAuthCore.authorize(authUser, uri, httpMethod, haProxyUser, issuer)) { + throw new AAIException("AAI_9101", "Request on " + httpMethod + " " + uri + " status is not OK"); + } + } + + private boolean isAafAuthProfileActive() { + String[] profiles = environment.getActiveProfiles(); + if (profiles != null) { + if (Arrays.stream(profiles).anyMatch( + env -> (env.equalsIgnoreCase(AafProfiles.AAF_CERT_AUTHENTICATION)))) { + return true; + } + } + return false; + } +} diff --git a/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIAuthCoreTest.java b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIAuthCoreTest.java new file mode 100644 index 00000000..6fca4fdb --- /dev/null +++ b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIAuthCoreTest.java @@ -0,0 +1,235 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.aaf.auth.exceptions.AAIUnrecognizedFunctionException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class AAIAuthCoreTest extends AAISetup { + + private AAIAuthCore authCore; + + @Before + public void setup() { + authCore = new AAIAuthCore("/aai"); + } + + @Test + public void getAuthPolicyFunctionNameTest() { + + String uri = "/aai/v3/search/edge-tag-query"; + assertEquals("Get aai function name from " + uri, "search", authCore.getAuthPolicyFunctName(uri)); + + uri = "/aai/v10/search/edge-tag-query"; + assertEquals("Get aai function name from " + uri, "search", authCore.getAuthPolicyFunctName(uri)); + + uri = "/aai/search/model"; + assertEquals("Get aai function name from " + uri, "search", authCore.getAuthPolicyFunctName(uri)); + + uri = "/aai/v9/cloud-infrastructure/cloud-regions/cloud-region/somecloudregion/some-cloud-owner"; + assertEquals("Get aai function name from " + uri, "cloud-infrastructure", authCore.getAuthPolicyFunctName(uri)); + + uri = "/aai/v8/network/pnfs/pnf/ff4ca01orc/p-interfaces"; + assertEquals("Get aai function name from " + uri, "network", authCore.getAuthPolicyFunctName(uri)); + + uri = "/aai/util/echo"; + assertEquals("Get aai function name from " + uri, "util", authCore.getAuthPolicyFunctName(uri)); + + uri = "/aai/tools"; + assertEquals("Get aai function name from " + uri, "tools", authCore.getAuthPolicyFunctName(uri)); + + uri = "/aai/v12/bulk/single-transaction"; + assertEquals("Get aai function name from " + uri, "bulk", authCore.getAuthPolicyFunctName(uri)); + + } + + @Test + public void validUsernameAuthTest() throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("testUser".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", "")); + } + + @Test + public void validUsernameInvalidHttpMethodAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("testUser".toLowerCase(), "/aai/v0/testFunction/someUri", "POST", "")); + } + + @Test(expected = AAIUnrecognizedFunctionException.class) + public void validUsernameInvalidFunctionInURIAuthTest() throws AAIUnrecognizedFunctionException { + authCore.authorize("testUser".toLowerCase(), "/aai/v0/badFunction/someUri", "PUT", ""); + } + + @Test + public void invalidUsernameAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("invlaidTestUser".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", "")); + } + + @Test + public void validUsernameIsTheExactWildcardIdAuthTest() throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("testWildcardId".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", "")); + } + + @Test + public void validUsernameContainsTheWildcardIdAuthTest() throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("cn=blah, testWildcardId, O=".toLowerCase(), "/aai/v0/testFunction/someUri", + "PUT", "", "aafWildCardIssuer")); + } + + @Test + public void validUsernameContainsTheWildcardIdInvalidIssuerAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("cn=blah, testWildcardId, O=".toLowerCase(), "/aai/v0/testFunction/someUri", + "PUT", "", "invalidIssuer")); + } + + @Test + public void invalidUsernameContainsRegularUsernameAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse( + authCore.authorize("cn=blah, testUser, O=".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", "")); + } + + @Test + public void haProxyUsernameAuthTest() throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/util/echo", "GET", "")); + } + + @Test + public void haProxyUsernameInvalidFunctionAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", "")); + } + + @Test + public void validUsernameViaHaProxyAuthTest() throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", + "testUser".toLowerCase())); + } + + @Test + public void validUsernameInvalidHttpMethodViaHaProxyAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/v0/testFunction/someUri", "POST", + "testUser".toLowerCase())); + } + + @Test(expected = AAIUnrecognizedFunctionException.class) + public void validUsernameInvalidFunctionInURIViaHaProxyAuthTest() throws AAIUnrecognizedFunctionException { + authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/v0/badFunction/someUri", "PUT", + "testUser".toLowerCase()); + } + + @Test + public void invalidUsernameViaHaProxyAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", + "invlaidTestUser".toLowerCase())); + } + + @Test + public void validUsernameIsTheExactWildcardIdViaHaProxyAuthTest() throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", + "testWildcardId".toLowerCase())); + } + + @Test + public void validUsernameContainsTheWildcardIdViaHaProxyAuthTest() throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", + "cn=blah, testWildcardId, O=".toLowerCase(), "aafWildCardIssuer")); + } + + @Test + public void invalidUsernameContainsRegularUsernameViaHaProxyAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", + "cn=blah, testUser, O=".toLowerCase())); + } + + @Test + public void haProxyUsernameTwiceAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("ha-proxy-user".toLowerCase(), "/aai/v0/testFunction/someUri", "PUT", + "ha-proxy-user".toLowerCase())); + } + + @Test + public void haProxyWildcardIdAuthTest() throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), "/aai/util/echo", "GET", "", + "aafWildCardIssuer")); + } + + @Test + public void haProxyWildcardIdInvalidFunctionAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), + "/aai/v0/testFunction/someUri", "PUT", "")); + } + + @Test + public void validUsernameViaHaProxyWildcardIdAuthTest() throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), "/aai/v0/testFunction/someUri", + "PUT", "testUser".toLowerCase(), "aafWildCardIssuer")); + } + + @Test + public void validUsernameInvalidHttpMethodViaHaProxyWildcardIdAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), + "/aai/v0/testFunction/someUri", "POST", "testUser".toLowerCase())); + } + + @Test(expected = AAIUnrecognizedFunctionException.class) + public void validUsernameInvalidFunctionInURIViaHaProxyWildcardIdAuthTest() + throws AAIUnrecognizedFunctionException { + authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), "/aai/v0/badFunction/someUri", "PUT", + "testUser".toLowerCase()); + } + + @Test + public void invalidUsernameViaHaProxyWildcardIdAuthTest() throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), + "/aai/v0/testFunction/someUri", "PUT", "invlaidTestUser".toLowerCase())); + } + + @Test + public void validUsernameIsTheExactWildcardIdViaHaProxyWildcardIdAuthTest() + throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), "/aai/v0/testFunction/someUri", + "PUT", "testWildcardId".toLowerCase(), "aafWildCardIssuer")); + } + + @Test + public void validUsernameContainsTheWildcardIdViaHaProxyWildcardIdAuthTest() + throws AAIUnrecognizedFunctionException { + assertTrue(authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), "/aai/v0/testFunction/someUri", + "PUT", "cn=blah, testWildcardId, O=".toLowerCase(), "aafWildCardIssuer")); + } + + @Test + public void validUsernameContainsTheWildcardIdViaHaProxyWildcardIdInvalidIssuerAuthTest() + throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), + "/aai/v0/testFunction/someUri", "PUT", "cn=blah, testWildcardId, O=".toLowerCase(), "invalidIssuer")); + } + + @Test + public void invalidUsernameContainsRegularUsernameViaHaProxyWildcardIdAuthTest() + throws AAIUnrecognizedFunctionException { + assertFalse(authCore.authorize("cn=blah, ha-proxy-wildcard-id, O=".toLowerCase(), + "/aai/v0/testFunction/someUri", "PUT", "cn=blah, testUser, O=".toLowerCase())); + } + +} diff --git a/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAISetup.java b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAISetup.java new file mode 100644 index 00000000..0827782e --- /dev/null +++ b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAISetup.java @@ -0,0 +1,31 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.aaf.auth; + +import org.junit.BeforeClass; + +public class AAISetup { + + @BeforeClass + public static void preSetup(){ + System.setProperty("AJSC_HOME", "."); + System.setProperty("BUNDLECONFIG_DIR", "src/test/resources/bundleconfig-local"); + } +} diff --git a/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIUserTest.java b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIUserTest.java new file mode 100644 index 00000000..e3b79cb7 --- /dev/null +++ b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIUserTest.java @@ -0,0 +1,53 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class AAIUserTest extends AAISetup { + + @Test + public void testIsAuth() { + AAIUser usr = new AAIUser("testUser"); + usr.addRole("testRole"); + usr.setUserAccess("auth", "GET"); + usr.setUserAccess("auth", "PUT"); + usr.setUserAccess("authentication", "PUT", "GET", "POST"); + + assertEquals(true, usr.hasAccess("auth", "GET")); + assertEquals(true, usr.hasAccess("auth", "PUT")); + assertEquals(true, usr.hasAccess("authentication", "POST")); + } + + @Test + public void testIsNotAuth() { + AAIUser usr = new AAIUser("testUser"); + usr.addRole("testRole"); + + assertEquals(false, usr.hasAccess("auth", "GET")); + + usr.setUserAccess("auth", "GET"); + assertEquals(false, usr.hasAccess("auth", "PUT")); + } + +} diff --git a/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/CertUtilTest.java b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/CertUtilTest.java new file mode 100644 index 00000000..9f307ac2 --- /dev/null +++ b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/CertUtilTest.java @@ -0,0 +1,87 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; +import java.util.Properties; + +import static org.easymock.EasyMock.*; +import static org.junit.Assert.assertTrue; + +/** + * The Class CertUtilTest + */ +public class CertUtilTest extends AAISetup { + + @Test + public void testCadiCertIssuers() throws IOException { + String propFile = System.getProperty("BUNDLECONFIG_DIR") + "/aaf/cadi.properties"; + Properties cadiProperties = new Properties(); + cadiProperties.load(new FileInputStream(new File(propFile))); + + List<String> issuersList = CertUtil.getCadiCertIssuers(cadiProperties); + assertTrue("issuersList isn't populated", !issuersList.isEmpty()); + + int x = issuersList.get(0).indexOf(" "); + assertTrue("issuer contains spaces", x < 0); + } + + @Test + public void testAaiSslClientOuHeader() { + + HttpServletRequest mockRequest = createMock(HttpServletRequest.class); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_OU_HDR)).andReturn("m55555@org.onap.com:TEST").times(1, 4); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_CN_HDR)).andReturn("CN").times(1, 2); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_O_HDR)).andReturn("O").times(1, 2); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_L_HDR)).andReturn("L").times(1, 2); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_ST_HDR)).andReturn("ST").times(1, 2); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_C_HDR)).andReturn("C").times(1, 2); + + replay(mockRequest); + String ou = CertUtil.getAaiSslClientOuHeader(mockRequest); + assertTrue("OU Header value is not as expected", ou.equals("m55555@org.onap.com:TEST")); + + assertTrue("Unexpected isHaProxy() return value", CertUtil.isHaProxy(mockRequest)); + + String mechId = CertUtil.getMechId(mockRequest); + assertTrue("mechid value is not as expected", mechId.equals("m55555@org.onap.com")); + + } + + @Test + public void testBuildUserChain() { + + // aaf.userchain.pattern=<AAF-ID>:${aaf.userchain.service.reference}:${aaf.userchain.auth.type}:AS + String aafUserChainPattern = "<AAF-ID>:org.onap.haproxy:X509:AS"; + String mechid = "m11111@onap.org"; + String result = CertUtil.buildUserChainHeader(mechid, aafUserChainPattern); + + assertTrue("user chain value is not as expected", "m11111@onap.org:org.onap.haproxy:X509:AS".equals(result)); + + } +} diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/cadi.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/cadi.properties new file mode 100644 index 00000000..8f7004ff --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/cadi.properties @@ -0,0 +1,14 @@ +## Location properties +## +## Localized Machine Information +## +cadi_loglevel=DEBUG +cadi_latitude=38.0 +cadi_longitude=-72.0 + +# Locate URL (which AAF Env) - Use lower case +aaf_locate_url=https://aafist.test.org:8095 +# AAF URL - Use upper case +aaf_url=https://AAF_LOCATE_URL/service:2.0 +# +cadi_prop_files=src/test/resources/bundleconfig-local/aaf/org.onap.aai.props diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/org.onap.aai.props b/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/org.onap.aai.props new file mode 100644 index 00000000..3056e5f9 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/org.onap.aai.props @@ -0,0 +1,4 @@ +cm_url=cm_url +hostname=hostname +aaf_env=IST +cadi_x509_issuers=CN=AAF CADI Test Issuing CA 01, OU=CSO, O=CO, C=US:CN=AAF CADI Test Issuing CA 02, OU=CSO, O=CO, C=US
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties new file mode 100644 index 00000000..0239e2ef --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties @@ -0,0 +1,58 @@ +# +# ============LICENSE_START======================================================= +# org.onap.aai +# ================================================================================ +# Copyright © 2017 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= + +aai.config.checktime=1000 + +# this could come from siteconfig.pl? +aai.config.nodename=AutomaticallyOverwritten + +aai.transaction.logging=true +aai.transaction.logging.get=true +aai.transaction.logging.post=true + +aai.server.url.base=https://localhost:8443/aai/ +aai.server.url=https://localhost:8443/aai/v10/ +aai.oldserver.url.base=https://localhost:8443/aai/servers/ +aai.oldserver.url=https://localhost:8443/aai/servers/v2/ +aai.global.callback.url=https://localhost:8443/aai/ + +aai.notification.current.version=v10 +aai.notificationEvent.default.status=UNPROCESSED +aai.notificationEvent.default.eventType=AAI-EVENT +aai.notificationEvent.default.domain=devINT1 +aai.notificationEvent.default.sourceName=aai +aai.notificationEvent.default.sequenceNumber=0 +aai.notificationEvent.default.severity=NORMAL +aai.notificationEvent.default.version=v10 +# This one lets us enable/disable resource-version checking on updates/deletes +aai.resourceversion.enableflag=true +aai.default.api.version=v10 + +aai.example.passwd.x=OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0 +aai.example.string=hello +aai.example.int=7748 + +aai.realtime.clients=RO,SDNC,SO + +aai.jms.enable=false + +aai.rest.getall.depthparam=someuuid + +aaf.valid.issuer.wildcard=aaf wild card issuer|aafWildCardIssuer|OU=another + diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/error.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/error.properties new file mode 100644 index 00000000..3a5671c2 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/error.properties @@ -0,0 +1,160 @@ +# Adding comment trying to trigger a build +#------------------------------------------------------------------------------- ---------- +#Key=Disposition:Category:Severity:Error Code:HTTP ResponseCode:RESTError Code:Error Message +#------------------------------------------------------------------------------- ---------- +# testing code, please don't change unless error utility source code changes +AAI_TESTING=5:2:WARN:0000:400:0001:Error code for testing + +# General success +AAI_0000=0:0:INFO:0000:200:0000:Success + +# health check success +AAI_0001=0:0:INFO:0001:200:0001:Success X-FromAppId=%1 X-TransactionId=%2 +AAI_0002=0:0:INFO:0002:200:0001:Successful health check + +# Success with additional info +AAI_0003=0:3:INFO:0003:202:0003:Success with additional info performing %1 on %2. Added %3 with key %4 +AAI_0004=0:3:INFO:0004:202:0003:Added prerequisite object to db + +#--- aairest: 3000-3299 +# svc errors +AAI_3000=5:2:INFO:3000:400:3000:Invalid input performing %1 on %2 +AAI_3001=5:6:INFO:3001:404:3001:Resource not found for %1 using id %2 +AAI_3002=5:1:WARN:3002:400:3002:Error writing output performing %1 on %2 +AAI_3003=5:1:WARN:3003:400:3003:Failed to make edge to missing target node of type %3 with keys %4 performing %1 on %2 +AAI_3005=5:6:WARN:3005:404:3001:Node cannot be directly accessed for read, must be accessed via ancestor(s) +AAI_3006=5:6:WARN:3006:404:3001:Node cannot be directly accessed for write, must be accessed via ancestor(s) +AAI_3007=5:6:INFO:3007:410:3007:This version (%1) of the API is retired, please migrate to %2 +AAI_3008=5:6:ERROR:3008:400:3008:URI is not encoded in UTF-8 +AAI_3009=5:6:ERROR:3009:400:3002:Malformed URL +# pol errors +AAI_3100=5:1:WARN:3100:400:3100:Unsupported operation %1 +AAI_3101=5:1:WARN:3101:403:3101:Attempt by client %1 to execute API %2 +AAI_3102=5:1:WARN:3102:400:3102:Error parsing input performing %1 on %2 +AAI_3300=5:1:WARN:3300:403:3300:Unauthorized +AAI_3301=5:1:WARN:3301:401:3301:Stale credentials +AAI_3302=5:1:WARN:3302:401:3301:Not authenticated +AAI_3303=5:1:ERROR:3303:403:3300:Too many objects would be returned by this request, please refine your request and retry + +#--- aaigen: 4000-4099 +AAI_4000=5:4:ERROR:4000:500:3002:Internal Error +AAI_4001=5:4:FATAL:4001:500:3002:Configuration file not found +AAI_4002=5:4:FATAL:4002:500:3002:Error reading Configuration file +AAI_4003=5:4:ERROR:4003:500:3002:Error writing to log file +AAI_4004=5:4:FATAL:4004:500:3002:Error reading/parsing the error properties file +AAI_4005=5:4:FATAL:4005:500:3002:Missing or invalid configuration parameter +AAI_4006=5:4:FATAL:4006:500:3002:Unexpected error in service +AAI_4007=5:4:ERROR:4007:500:3102:Input parsing error +AAI_4008=5:4:ERROR:4008:500:3002:Output parsing error +AAI_4009=4:0:ERROR:4009:400:3000:Invalid X-FromAppId in header +AAI_4010=4:0:ERROR:4010:400:3000:Invalid X-TransactionId in header +AAI_4011=5:4:ERROR:4011:500:3002:Missing data for REST error response +AAI_4014=4:0:ERROR:4014:400:3000:Invalid Accept header +AAI_4015=4:0:ERROR:4015:400:3000:You must provide at least one indexed property +AAI_4016=4:0:ERROR:4016:400:3000:The depth parameter must be a number or the string "all" +AAI_4017=5:2:INFO:4017:400:3000:Could not set property +AAI_4018=5:2:ERROR:4018:400:3000:Unable to convert the string to integer +#--- aaidbmap: 5102-5199 +AAI_5102=5:4:FATAL:5102:500:3002:Graph database is null after open +AAI_5105=5:4:ERROR:5105:500:3002:Unexpected error reading/updating database +AAI_5106=5:4:WARN:5106:404:3001:Node not found +AAI_5107=5:2:WARN:5107:400:3000:Required information missing +AAI_5108=5:2:WARN:5108:200:0:Unexpected information in request being ignored + +#--- aaidbgen: 6101-6199 +AAI_6101=5:4:ERROR:6101:500:3002:null JanusGraph object passed +AAI_6102=5:4:WARN:6102:400:3000:Passed-in property is not valid for this nodeType +AAI_6103=5:4:WARN:6103:400:3000:Required Node-property not found in input data +AAI_6104=5:4:WARN:6104:400:3000:Required Node-property was passed with no data +AAI_6105=5:4:WARN:6105:400:3000:Node-Key-Property not defined in DbMaps +AAI_6106=5:4:WARN:6106:400:3000:Passed-in property is not valid for this edgeType +AAI_6107=5:4:WARN:6107:400:3000:Required Edge-property not found in input data +AAI_6108=5:4:WARN:6108:400:3000:Required Edge-property was passed with no data +AAI_6109=5:4:WARN:6109:400:3000:Bad dependent Node value +AAI_6110=5:4:ERROR:6110:400:3100:Node cannot be deleted +AAI_6111=5:4:ERROR:6111:400:3000:JSON processing error +AAI_6112=5:4:ERROR:6112:400:3000:More than one node found by getUniqueNode() +AAI_6114=5:4:INFO:6114:404:3001:Node Not Found +AAI_6115=5:4:ERROR:6115:400:3000:Unrecognized NodeType +AAI_6116=5:4:ERROR:6116:400:3000:Unrecognized Property +AAI_6117=5:4:ERROR:6117:400:3000:Uniqueness constraint violated +AAI_6118=5:4:ERROR:6118:400:3000:Required Field not passed. +AAI_6120=5:4:ERROR:6120:400:3000:Bad Parameter Passed +AAI_6121=5:4:ERROR:6121:400:3000:Problem with internal AAI reference data +AAI_6122=5:4:ERROR:6122:400:3000:Data Set not complete in DB for this request +AAI_6123=5:4:ERROR:6123:500:3000:Bad Data found by DataGrooming Tool - Investigate +AAI_6124=5:4:ERROR:6124:500:3000:File read/write error +AAI_6125=5:4:WARN:6125:500:3000:Problem Pulling Data Set +AAI_6126=5:4:ERROR:6126:400:3000:Edge cannot be deleted +AAI_6127=5:4:INFO:6127:404:3001:Edge Not Found +AAI_6128=5:4:INFO:6128:500:3000:Unexpected error +AAI_6129=5:4:INFO:6129:404:3003:Error making edge to target node +AAI_6130=5:4:WARN:6130:412:3000:Precondition Required +AAI_6131=5:4:WARN:6131:412:3000:Precondition Failed +AAI_6132=5:4:WARN:6132:400:3000:Bad Model Definition +AAI_6133=5:4:WARN:6133:400:3000:Bad Named Query Definition +AAI_6134=5:4:ERROR:6134:500:6134:Could not persist transaction to storage back end. Exhausted retry amount +AAI_6135=5:4:WARN:6135:412:3000:Resource version specified on create +AAI_6136=5:4:ERROR:6136:400:3000:Object cannot hold multiple items +AAI_6137=5:4:ERROR:6137:400:3000:Cannot perform writes on multiple vertices +AAI_6138=5:4:ERROR:6138:400:3000:Cannot delete multiple vertices +AAI_6139=5:4:ERROR:6139:404:3000:Attempted to add edge to vertex that does not exist +AAI_6140=5:4:ERROR:6140:400:3000:Edge multiplicity violated +AAI_6141=5:4:WARN:6141:400:3000:Please Refine Query +AAI_6142=5:4:INFO:6142:400:3000:Retrying transaction +AAI_6143=5:4:INFO:6143:400:3000:Ghost vertex found +AAI_6144=5:4:WARN:6144:400:3000:Cycle found in graph +AAI_6145=5:4:ERROR:6145:400:3000:Cannot create a nested/containment edge via relationship +AAI_6146=5:4:ERROR:6146:400:3000:Ambiguous identity map found, use a URI instead + +#--- aaicsvp: 7101-7199 +AAI_7101=5:4:ERROR:7101:500:3002:Unexpected error in CSV file processing +AAI_7102=5:4:ERROR:7102:500:3002:Error in cleanup temporary directory +#AAI_7103=4:2:ERROR:7103:500:3002:Unsupported user +AAI_7104=5:4:ERROR:7104:500:3002:Failed to create directory +AAI_7105=5:4:ERROR:7105:500:3002:Temporary directory exists +AAI_7106=5:4:ERROR:7106:500:3002:Cannot delete +AAI_7107=5:4:ERROR:7107:500:3002:Input file does not exist +AAI_7108=5:4:ERROR:7108:500:3002:Output file does not exist +AAI_7109=5:4:ERROR:7109:500:3002:Error closing file +AAI_7110=5:4:ERROR:7110:500:3002:Error loading/reading properties file +AAI_7111=5:4:ERROR:7111:500:3002:Error executing shell script +AAI_7112=5:4:ERROR:7112:500:3002:Error creating output file +AAI_7113=5:4:ERROR:7113:500:3002:Trailer record error +AAI_7114=5:4:ERROR:7114:500:3002:Input file error +AAI_7115=5:4:ERROR:7115:500:3002:Unexpected error +AAI_7116=5:4:ERROR:7116:500:3002:Request error +AAI_7117=5:4:ERROR:7117:500:3002:Error in get http client object +AAI_7118=5:4:ERROR:7118:500:3002:Script Error +AAI_7119=5:4:ERROR:7119:500:3002:Unknown host + +#--- aaisdnc: 7201-7299 +AAI_7202=5:4:ERROR:7202:500:3002:Error getting connection to odl +AAI_7203=5:4:ERROR:7203:500:3002:Unexpected error calling DataChangeNotification API +AAI_7204=5:4:ERROR:7204:500:3002:Error returned by DataChangeNotification API +AAI_7205=5:4:ERROR:7205:500:3002:Unexpected error running notifySDNCOnUpdate +AAI_7206=5:4:ERROR:7206:500:3002:Invalid data returned from ODL + +#--- NotificationEvent, using UEB space +AAI_7350=5:4:ERROR:7305:500:3002:Notification event creation failed + +#--- aairestctlr: 7401-7499 +AAI_7401=5:4:ERROR:7401:500:3002:Error connecting to AAI REST API +AAI_7402=5:4:ERROR:7402:500:3002:Unexpected error +AAI_7403=5:4:WARN:7403:400:3001:Request error +AAI_7404=5:4:INFO:7404:404:3001:Node not found +AAI_7405=5:4:WARN:7405:200:0:UUID not formatted correctly, generating UUID + +#--- aaiauth: 9101-9199 +AAI_9101=5:0:WARN:9101:403:3300:User is not authorized to perform function +AAI_9102=5:0:WARN:9102:401:3301:Refresh credentials from source +AAI_9103=5:0:WARN:9103:403:3300:User not found +AAI_9104=5:0:WARN:9104:401:3302:Authentication error +AAI_9105=5:0:WARN:9105:403:3300:Authorization error +AAI_9106=5:0:WARN:9106:403:3300:Invalid AppId +#AAI_9107=5:0:WARN:9107:403:3300:No Username in Request +AAI_9107=5:0:WARN:9107:403:3300:SSL is not provided in request, please contact admin + +#--- aaiinstar: 9201-9299 +AAI_9201=5:4:ERROR:9201:500:3002:Unable to send notification +AAI_9202=5:4:ERROR:9202:500:3002:Unable to start a thread diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties new file mode 100644 index 00000000..aa3c0631 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties @@ -0,0 +1,36 @@ +# +# ============LICENSE_START======================================================= +# org.onap.aai +# ================================================================================ +# Copyright © 2017-18 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= + +query.fast-property=true +# the following parameters are not reloaded automatically and require a manual bounce +storage.backend=inmemory +storage.hostname=localhost + +#schema.default=none +storage.lock.wait-time=300 +storage.hbase.table=aaigraph-dev1.dev +storage.hbase.ext.zookeeper.znode.parent=/hbase-unsecure +#caching on +cache.db-cache = true +cache.db-cache-clean-wait = 20 +cache.db-cache-time = 180000 +cache.db-cache-size = 0.3 + +#load graphson file on startup +load.snapshot.file=false diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties new file mode 100644 index 00000000..05394334 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties @@ -0,0 +1,33 @@ +# +# ============LICENSE_START======================================================= +# org.onap.aai +# ================================================================================ +# Copyright © 2017-18 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. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= + +query.fast-property=true +# the following parameters are not reloaded automatically and require a manual bounce +storage.backend=inmemory +storage.hostname=localhost + +#schema.default=none +storage.lock.wait-time=300 +storage.hbase.table=aaigraph-dev1.dev +storage.hbase.ext.zookeeper.znode.parent=/hbase-unsecure +# Setting db-cache to false ensure the fastest propagation of changes across servers +cache.db-cache = false + +#load graphson file on startup +load.snapshot.file=false diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/auth/aai_policy.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/auth/aai_policy.json new file mode 100644 index 00000000..9335a7bb --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/auth/aai_policy.json @@ -0,0 +1,73 @@ +{ + "roles": [ + { + "name": "testRole", + "functions": [ + { + "name": "testFunction", + "methods": [ + { + "name": "GET" + }, + { + "name": "DELETE" + }, + { + "name": "PUT" + } + ] + } + ], + "users": [ + { + "username": "testUser" + }, + { + "username": "testWildcardId", + "is-wildcard-id": true + } + ] + }, + { + "name": "HAProxy", + "functions": [ + { + "name": "util", + "methods": [ + { + "name": "GET" + } + ] + } + ], + "users": [ + { + "username": "ha-proxy-user" + }, + { + "username": "ha-proxy-wildcard-id", + "is-wildcard-id": true + } + ] + }, + { + "name": "testBasicAuth", + "functions": [ + { + "name": "testBasicAuthFunction", + "methods": [ + { + "name": "GET" + } + ] + } + ], + "users": [ + { + "user": "testBasicAuthUser", + "pass": "OBF:1ytc1vu91v2p1rxf1mqh1v8s1z0d1msn1san1mqf1z0h1v9u1msl1rvf1v1p1vv11yta" + } + ] + } + ] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/graphson/resource.graphson b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/graphson/resource.graphson new file mode 100644 index 00000000..04f48174 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/graphson/resource.graphson @@ -0,0 +1,2 @@ +{"id": 386506928,"label": "vertex","properties": {"aai-last-mod-ts": [{"id": "ob632u-6e46nk-5j45","value": 1488308500413}],"aai-uri": [{"id": "ob6712-6e46nk-5lhh","value": "/cloud-infrastructure/cloud-regions/cloud-region/cloud-owner-987654321-9922-as988q/cloud-region-id-987654321-9922-as988q/tenants/tenant/tenant-987654321-9999-as988q/vservers/vserver/vserver-987654321-9999-as988q"}],"prov-status": [{"id": "ob651y-6e46nk-1kw5","value": "example-prov-status-val-7367"}],"aai-created-ts": [{"id": "ob62ae-6e46nk-5gqt","value": 1488308500413}],"source-of-truth": [{"id": "ob61w6-6e46nk-5jwl","value": "FitNesse-Test-as988q"}],"vserver-selflink": [{"id": "ob65g6-6e46nk-3xfp","value": "example-vserver-selflink-val-7367"}],"aai-node-type": [{"id": "ob61hy-6e46nk-5f5x","value": "vserver"}],"in-maint": [{"id": "ob65ue-6e46nk-20p1","value": false}],"resource-version": [{"id": "ob62om-6e46nk-23ut","value": "1488308500413"}],"vserver-name": [{"id": "ob649i-6e46nk-3u9x","value": "example-vserver-name-val-7367vserver-987654321-9999-as988q"}],"vserver-id": [{"id": "ob63va-6e46nk-3sp1","value": "vserver-987654321-9999-as988q"}],"last-mod-source-of-truth": [{"id": "ob63h2-6e46nk-5edh","value": "FitNesse-Test-as988q"}],"vserver-name2": [{"id": "ob64nq-6e46nk-3vut","value": "example-vserver-name2-val-7367"}],"is-closed-loop-disabled": [{"id": "ob668m-6e46nk-229x","value": false}]}} +{"id": 2461872,"label": "vertex","properties": {"aai-last-mod-ts": [{"id": "21hqu-1grlc-5j45","value": 1467901600}],"in-maint": [{"id": "21i52-1grlc-20p1","value": false}],"resource-version": [{"id": "21ija-1grlc-23ut","value": "1467901600"}],"vserver-name": [{"id": "21ixi-1grlc-3u9x","value": "PerfTest_VServerFix0027TenantPez002701611467901587187Name"}],"aai-created-ts": [{"id": "21jbq-1grlc-5gqt","value": 1467901600}],"vserver-id": [{"id": "21jpy-1grlc-3sp1","value": "PerfTest_VServerFix0027TenantPez002701611467901587187"}],"last-mod-source-of-truth": [{"id": "21k46-1grlc-5edh","value": "MSO"}],"vserver-name2": [{"id": "21kie-1grlc-3vut","value": "PerfTest_VServerFix0027TenantPez002701611467901587187-VM Name2 optional"}],"source-of-truth": [{"id": "21kwm-1grlc-5jwl","value": "MSO"}],"vserver-selflink": [{"id": "21lau-1grlc-3xfp","value": "http://testvserverLink.com/.html?vserv=VserverLink"}],"is-closed-loop-disabled": [{"id": "21lp2-1grlc-229x","value": false}],"aai-node-type": [{"id": "21m3a-1grlc-5f5x","value": "vserver"}],"aai-uri": [{"id": "21m3a-1grlc-5a5x","value": "/vservers/vserver/test1"}]}}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource-format.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource-format.json new file mode 100644 index 00000000..c7e42556 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource-format.json @@ -0,0 +1,13 @@ +{ + "results": [ + { + "vserver": { + + } + }, + { + "vserver": { + } + } + ] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource_and_url-format.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource_and_url-format.json new file mode 100644 index 00000000..d90a71bc --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource_and_url-format.json @@ -0,0 +1,16 @@ +{ + "results": [ + { + "url" : "/cloud-infrastructure/cloud-regions/cloud-region/cloud-owner-987654321-9922-as988q/cloud-region-id-987654321-9922-as988q/tenants/tenant/tenant-987654321-9999-as988q/vservers/vserver/vserver-987654321-9999-as988q", + "vserver": { + + } + }, + { + "url" : "/vservers/vserver/test1", + "vserver": { + + } + } + ] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/simple-format.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/simple-format.json new file mode 100644 index 00000000..dd342615 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/simple-format.json @@ -0,0 +1,43 @@ +{ + "results" : [{ + "id" : "0", + "node-type" : "generic-vnf", + "url" : "urimissing", + "properties" : { + "vnf-name" : "myVnf" + }, + "related-to" : [{ + "node-type" : "vserver", + "id" : "1", + "url" : "urimissing" + }] + } , { + "id" : "1", + "node-type" : "vserver", + "url" : "urimissing", + "properties" : { + "vserver-name" : "myVserver" + }, + "related-to" : [{ + "node-type" : "generic-vnf", + "id" : "0", + "url" : "urimissing" + },{ + "node-type" : "pserver", + "id" : "2", + "url" : "/pservers/pserver/key1" + }] + },{ + "id" : "2", + "node-type" : "pserver", + "url" : "/pservers/pserver/key1", + "properties" : { + "hostname" : "myPserver" + }, + "related-to" : [{ + "node-type" : "vserver", + "id" : "1", + "url" : "urimissing" + }] + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/ambiguous-relationship.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/ambiguous-relationship.json new file mode 100644 index 00000000..c6407e2c --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/ambiguous-relationship.json @@ -0,0 +1,10 @@ +{ + "related-to": "generic-vnf", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key1" + },{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key2" + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-failv10-successv9.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-failv10-successv9.json new file mode 100644 index 00000000..5bafc9ff --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-failv10-successv9.json @@ -0,0 +1,8 @@ +{ + "related-to": "generic-vnf", + "related-link": "/aai/v10/network/generic-vnfs/test-objet/key1", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key2" + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-successv10-failv9.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-successv10-failv9.json new file mode 100644 index 00000000..3afe6bb7 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-successv10-failv9.json @@ -0,0 +1,8 @@ +{ + "related-to": "generic-vnf", + "related-link": "http://localhost/aai/v10/network/generic-vnfs/generic-vnf/key1", + "relationship-data" : [{ + "relationship-key" : "test-obect.vnf-id", + "relationship-value":"key2" + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/nothing-to-parse.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/nothing-to-parse.json new file mode 100644 index 00000000..b24834af --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/nothing-to-parse.json @@ -0,0 +1,4 @@ +{ + "related-to": "generic-vnf", + "relationship-data" : [] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-related-link.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-related-link.json new file mode 100644 index 00000000..4cc103e8 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-related-link.json @@ -0,0 +1,4 @@ +{ + "related-to": "generic-vnf", + "related-link": "http://localhost/aai/v10/network/generic-vnfs/generic-vnf/key1" +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-relationship-data.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-relationship-data.json new file mode 100644 index 00000000..b9fccc9c --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-relationship-data.json @@ -0,0 +1,7 @@ +{ + "related-to": "generic-vnf", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key1" + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/too-many-items-relationship.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/too-many-items-relationship.json new file mode 100644 index 00000000..97765cfb --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/too-many-items-relationship.json @@ -0,0 +1,19 @@ +{ + "related-to": "l-interface", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key1" + },{ + "relationship-key" : "subnet.subnet-id", + "relationship-value":"key5" + },{ + "relationship-key" : "vlan.vlan-interface", + "relationship-value":"key3" + },{ + "relationship-key" : "l-interface.interface-name", + "relationship-value":"key2" + },{ + "relationship-key" : "l3-interface-ipv4-address-list.l3-interface-ipv4-address", + "relationship-value":"key4" + }] +} diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/top-level-two-keys-relationship.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/top-level-two-keys-relationship.json new file mode 100644 index 00000000..c6dbf557 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/top-level-two-keys-relationship.json @@ -0,0 +1,13 @@ +{ + "related-to" : "availability-zone", + "relationship-data" : [ { + "relationship-key" : "cloud-region.cloud-owner", + "relationship-value" : "key1" + }, { + "relationship-key" : "cloud-region.cloud-region-id", + "relationship-value" : "key2" + }, { + "relationship-key" : "availability-zone.availability-zone-name", + "relationship-value" : "key3" + } ] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/two-top-level-relationship.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/two-top-level-relationship.json new file mode 100644 index 00000000..54cac2c8 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/two-top-level-relationship.json @@ -0,0 +1,19 @@ +{ + "related-to": "l-interface", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key1" + },{ + "relationship-key" : "vlan.vlan-interface", + "relationship-value":"key3" + },{ + "relationship-key" : "l-interface.interface-name", + "relationship-value":"key2" + },{ + "relationship-key" : "zone.zone-id", + "relationship-value":"key5" + },{ + "relationship-key" : "l3-interface-ipv4-address-list.l3-interface-ipv4-address", + "relationship-value":"key4" + }] +} |