From d44d543dc0330fa4ea2a477688e3f53f58be9c5a Mon Sep 17 00:00:00 2001 From: Arthur Martella Date: Fri, 15 Mar 2019 12:40:25 -0400 Subject: Initial upload of F-GPS seed code 18/21 Includes: API exceptions API helpers API interceptors API proxy code Change-Id: Iaac0d6db2854a084bcd628a0fd4f6bb9224efb58 Issue-ID: OPTFRA-440 Signed-off-by: arthur.martella.1@att.com --- .../fgps/api/exception/CipherUtilException.java | 67 ++++++ .../fgps/api/exception/MissingRoleException.java | 62 ++++++ .../java/org/onap/fgps/api/helpers/Helper.java | 58 ++++++ .../api/interceptor/AuthorizationInterceptor.java | 203 ++++++++++++++++++ .../fgps/api/interceptor/DarknessInterceptor.java | 65 ++++++ .../api/interceptor/VersioningInterceptor.java | 88 ++++++++ .../java/org/onap/fgps/api/proxy/AAFProxy.java | 232 +++++++++++++++++++++ .../main/java/org/onap/fgps/api/proxy/DBProxy.java | 215 +++++++++++++++++++ 8 files changed, 990 insertions(+) create mode 100644 valetapi/src/main/java/org/onap/fgps/api/exception/CipherUtilException.java create mode 100644 valetapi/src/main/java/org/onap/fgps/api/exception/MissingRoleException.java create mode 100644 valetapi/src/main/java/org/onap/fgps/api/helpers/Helper.java create mode 100644 valetapi/src/main/java/org/onap/fgps/api/interceptor/AuthorizationInterceptor.java create mode 100644 valetapi/src/main/java/org/onap/fgps/api/interceptor/DarknessInterceptor.java create mode 100644 valetapi/src/main/java/org/onap/fgps/api/interceptor/VersioningInterceptor.java create mode 100644 valetapi/src/main/java/org/onap/fgps/api/proxy/AAFProxy.java create mode 100644 valetapi/src/main/java/org/onap/fgps/api/proxy/DBProxy.java (limited to 'valetapi') diff --git a/valetapi/src/main/java/org/onap/fgps/api/exception/CipherUtilException.java b/valetapi/src/main/java/org/onap/fgps/api/exception/CipherUtilException.java new file mode 100644 index 0000000..5e37e4d --- /dev/null +++ b/valetapi/src/main/java/org/onap/fgps/api/exception/CipherUtilException.java @@ -0,0 +1,67 @@ +/* + * ============LICENSE_START========================================== + * ONAP - F-GPS API + * =================================================================== + * Copyright © 2019 ATT Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.fgps.api.exception; + +public class CipherUtilException extends RuntimeException { + + public CipherUtilException() { + super(); + // TODO Auto-generated constructor stub + } + + public CipherUtilException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + // TODO Auto-generated constructor stub + } + + public CipherUtilException(String arg0, Throwable arg1) { + super(arg0, arg1); + // TODO Auto-generated constructor stub + } + + public CipherUtilException(String arg0) { + super(arg0); + // TODO Auto-generated constructor stub + } + + public CipherUtilException(Throwable arg0) { + super(arg0); + // TODO Auto-generated constructor stub + } + +} diff --git a/valetapi/src/main/java/org/onap/fgps/api/exception/MissingRoleException.java b/valetapi/src/main/java/org/onap/fgps/api/exception/MissingRoleException.java new file mode 100644 index 0000000..b83f8fb --- /dev/null +++ b/valetapi/src/main/java/org/onap/fgps/api/exception/MissingRoleException.java @@ -0,0 +1,62 @@ +/* + * ============LICENSE_START========================================== + * ONAP - F-GPS API + * =================================================================== + * Copyright © 2019 ATT Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.fgps.api.exception; + +public class MissingRoleException extends RuntimeException { + + public MissingRoleException() { + super(); + } + + public MissingRoleException(String arg0) { + super(arg0); + } + + public MissingRoleException(Throwable arg0) { + super(arg0); + } + + public MissingRoleException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public MissingRoleException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + } + +} diff --git a/valetapi/src/main/java/org/onap/fgps/api/helpers/Helper.java b/valetapi/src/main/java/org/onap/fgps/api/helpers/Helper.java new file mode 100644 index 0000000..6016d7a --- /dev/null +++ b/valetapi/src/main/java/org/onap/fgps/api/helpers/Helper.java @@ -0,0 +1,58 @@ +/* + * ============LICENSE_START========================================== + * ONAP - F-GPS API + * =================================================================== + * Copyright © 2019 ATT Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.fgps.api.helpers; + +import org.json.simple.JSONObject; + +public class Helper { + @SuppressWarnings("unchecked") + public static JSONObject formatDeleteRequest(JSONObject request) { + JSONObject req = new JSONObject(), datacenter = new JSONObject() ; + datacenter.put("id", request.get("region_id")); + //datacenter.put("url", request.get("keystone_url")); + req.put("datacenter", datacenter); + if (request.get("stack_name") != null){ + req.put("stack_name", request.get("stack_name")); + }else { + req.put("stack_name", request.get("vf_module_name")); + } + if(request.get("tenant_id") != null) { req.put("tenant_id", request.get("tenant_id"));} + return req; + + } +} \ No newline at end of file diff --git a/valetapi/src/main/java/org/onap/fgps/api/interceptor/AuthorizationInterceptor.java b/valetapi/src/main/java/org/onap/fgps/api/interceptor/AuthorizationInterceptor.java new file mode 100644 index 0000000..19bc9d3 --- /dev/null +++ b/valetapi/src/main/java/org/onap/fgps/api/interceptor/AuthorizationInterceptor.java @@ -0,0 +1,203 @@ +/* + * ============LICENSE_START========================================== + * ONAP - F-GPS API + * =================================================================== + * Copyright © 2019 ATT Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.fgps.api.interceptor; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.tomcat.util.codec.binary.Base64; +import org.onap.fgps.api.annotation.AafRoleRequired; +import org.onap.fgps.api.annotation.BasicAuthRequired; +import org.onap.fgps.api.annotation.PropertyBasedAuthorization; +import org.onap.fgps.api.exception.MissingRoleException; +import org.onap.fgps.api.logging.EELFLoggerDelegate; +import org.onap.fgps.api.proxy.AAFProxy; +import org.onap.fgps.api.utils.CipherUtil; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +public class AuthorizationInterceptor implements HandlerInterceptor { + private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(AuthorizationInterceptor.class); + private boolean aafAuthFlag; + private boolean basicAuthFlag; + private AAFProxy aafProxy; + private Map credentials = new HashMap(); + private Map roles = new HashMap(); + private Map aafTags = new HashMap(); + private Map basicTags = new HashMap(); + + public AuthorizationInterceptor(AAFProxy aafProxy, boolean aafAuthFlag, boolean basicAuthFlag) { + this.aafProxy = aafProxy; + this.aafAuthFlag = aafAuthFlag; + this.basicAuthFlag = basicAuthFlag; + Properties authProperties = new Properties(); + try { + Resource fileResource = new ClassPathResource("auth.properties"); + authProperties.load(fileResource.getInputStream()); + } catch (IOException e) { + LOGGER.error(EELFLoggerDelegate.errorLogger,"Couldn't load auth.properties!"); + } + + for (Object o : authProperties.keySet()) { + String key = (String)o; + if (key.endsWith(".name")) { + String propname = key.substring(0, key.length()-5); + String user = authProperties.getProperty(key); + String encpass = authProperties.getProperty(propname + ".pass"); + String pass = CipherUtil.decryptPKC(encpass); + String plainCredentials = user + ":" + pass; + String base64Credentials = new String(Base64.encodeBase64(plainCredentials.getBytes())); + if (key.equals("valet.aaf.name")) { + aafProxy.setCredentials(base64Credentials); + } else { + credentials.put(user, base64Credentials); + } + } else if (key.endsWith(".role")) { + roles.put(key, authProperties.getProperty(key)); + } else if (key.endsWith(".aaf")) { + aafTags.put(key, authProperties.getProperty(key)); + } else if (key.endsWith(".basic")) { + basicTags.put(key, authProperties.getProperty(key)); + } + } + } + + private boolean aafOk(HttpServletRequest request, Object handler) throws Exception { + String roleRequired = null; + try { + AafRoleRequired aafAnnotation = null; + HandlerMethod hm = (HandlerMethod)handler; + aafAnnotation = hm.getMethodAnnotation(AafRoleRequired.class); + roleRequired = getRole(aafAnnotation); + } catch (RuntimeException e) { + try { + PropertyBasedAuthorization pba = null; + HandlerMethod hm = (HandlerMethod)handler; + pba = hm.getMethodAnnotation(PropertyBasedAuthorization.class); + roleRequired = aafTags.get(pba.value() + ".aaf"); + } catch (RuntimeException e2) { + // noop + } + } + + if (roleRequired!=null && aafAuthFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"AAF required: " + roleRequired); + + if (!aafProxy.userAuthenticated(request)) return false; + if (!aafProxy.userAuthorized(request, roleRequired)) return false; + } + + return true; + } + + private String getRole(AafRoleRequired aafAnnotation) { + if (aafAnnotation.roleRequired()!=null && aafAnnotation.roleRequired().length()>0) return aafAnnotation.roleRequired(); + if (roles.containsKey(aafAnnotation.roleProperty())) return roles.get(aafAnnotation.roleProperty()); + if (roles.containsKey(aafAnnotation.roleProperty() + ".role")) return roles.get(aafAnnotation.roleProperty() + ".role"); + throw new MissingRoleException("No role found for annotation: roleRequired = " + aafAnnotation.roleRequired() + ", roleProperty = " + aafAnnotation.roleProperty()); + } + + private boolean basicAuthOk(HttpServletRequest request, Object handler) { + String authRequired = null; + try { + BasicAuthRequired basicAuthAnnotation = null; + HandlerMethod hm = (HandlerMethod)handler; + basicAuthAnnotation = hm.getMethodAnnotation(BasicAuthRequired.class); + authRequired = basicAuthAnnotation.authRequired(); + } catch (RuntimeException e) { + try { + PropertyBasedAuthorization pba = null; + HandlerMethod hm = (HandlerMethod)handler; + pba = hm.getMethodAnnotation(PropertyBasedAuthorization.class); + authRequired = basicTags.get(pba.value() + ".basic"); + } catch (RuntimeException e2) { + // noop + } + } + + if (authRequired!=null && basicAuthFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Basic auth required: " + authRequired); + + if (credentials.containsKey(authRequired)) { + if (request.getHeader("Authorization")!=null && request.getHeader("Authorization").equals("Basic " + credentials.get(authRequired))) return true; + request.setAttribute("fail", "Basic auth failed Auth for " + authRequired + "."); + } else { + request.setAttribute("fail", "Basic auth not enabled for " + authRequired); + } + + return false; + } + + return true; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (!aafOk(request, handler)) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"AAF isn't ok, reason: " + request.getAttribute("fail")); + request.getRequestDispatcher("/authfail").forward(request, response); + return false; + } + if (!basicAuthOk(request, handler)) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Basic auth isn't ok, reason: " + request.getAttribute("fail")); + request.getRequestDispatcher("/authfail").forward(request, response); + return false; + } + + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + // noop + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + // noop + } + +} diff --git a/valetapi/src/main/java/org/onap/fgps/api/interceptor/DarknessInterceptor.java b/valetapi/src/main/java/org/onap/fgps/api/interceptor/DarknessInterceptor.java new file mode 100644 index 0000000..3efb3e0 --- /dev/null +++ b/valetapi/src/main/java/org/onap/fgps/api/interceptor/DarknessInterceptor.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START========================================== + * ONAP - F-GPS API + * =================================================================== + * Copyright © 2019 ATT Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.fgps.api.interceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +public class DarknessInterceptor implements HandlerInterceptor { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (request.getRequestURL().toString().endsWith("/dark")) return true; + + request.getRequestDispatcher("/dark").forward(request, response); + return false; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + // noop + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + // noop + } + +} \ No newline at end of file diff --git a/valetapi/src/main/java/org/onap/fgps/api/interceptor/VersioningInterceptor.java b/valetapi/src/main/java/org/onap/fgps/api/interceptor/VersioningInterceptor.java new file mode 100644 index 0000000..a3193ce --- /dev/null +++ b/valetapi/src/main/java/org/onap/fgps/api/interceptor/VersioningInterceptor.java @@ -0,0 +1,88 @@ +/* + * ============LICENSE_START========================================== + * ONAP - F-GPS API + * =================================================================== + * Copyright © 2019 ATT Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.fgps.api.interceptor; + +import java.util.Properties; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.fgps.api.logging.EELFLoggerDelegate; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + + +public class VersioningInterceptor implements HandlerInterceptor { + + private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(VersioningInterceptor.class); + private Properties versionProperties = null; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (versionProperties==null) { + versionProperties = new Properties(); + try { + Resource fileResource = new ClassPathResource("version.properties"); + versionProperties.load(fileResource.getInputStream()); + } catch (NullPointerException e) { + e.printStackTrace(); + LOGGER.error(EELFLoggerDelegate.applicationLogger," preHandle : Error details : "+ e.getMessage()); + LOGGER.error(EELFLoggerDelegate.errorLogger," preHandle : Error details : "+ e.getMessage()); + } + } + + response.addHeader("X-MinorVersion", versionProperties.getProperty("version.minor")); + response.addHeader("X-PatchVersion", versionProperties.getProperty("version.patch")); + response.addHeader("X-LatestVersion", versionProperties.getProperty("version.full")); + + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + // noop + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + // noop + } + +} diff --git a/valetapi/src/main/java/org/onap/fgps/api/proxy/AAFProxy.java b/valetapi/src/main/java/org/onap/fgps/api/proxy/AAFProxy.java new file mode 100644 index 0000000..43ecaf1 --- /dev/null +++ b/valetapi/src/main/java/org/onap/fgps/api/proxy/AAFProxy.java @@ -0,0 +1,232 @@ +/* + * ============LICENSE_START========================================== + * ONAP - F-GPS API + * =================================================================== + * Copyright © 2019 ATT Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.fgps.api.proxy; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.fgps.api.logging.EELFLoggerDelegate; +import org.onap.fgps.api.utils.CipherUtil; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class AAFProxy { + public static class Auth { + public String id; + public String password; + } + + public static class Item { + public String id; + public String expires; + } + + public static class User { + public List user; + } + + private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(AAFProxy.class); + private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + + private String aafUrlBase; + private String encodedPassword = null; + + public AAFProxy(String aafUrlBase) { + this.aafUrlBase = aafUrlBase; + } + + public boolean userAuthenticated(HttpServletRequest request) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"In AAFProxy.userAutheniticated"); + String user = request.getHeader("mechId"); + if (user==null || user.length()==0) { + request.setAttribute("fail", "AAF failed: mechId header not present."); + return false; + } + + String encpassword = request.getHeader("password"); + if (encpassword==null || encpassword.length()==0) { + request.setAttribute("fail", "AAF failed: password header not present."); + return false; + } + String password = CipherUtil.decryptPKC(encpassword); + + String urlStr = aafUrlBase + "/authn/validate"; + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Going to call AAF, url = " + urlStr); + + try { + RestTemplate restTemplate = new RestTemplate(); + + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Basic " + encodedPassword); + headers.add("Accept", "application/Users+json;q=1.0;charset=utf-8;version=2.0,application/json;q=1.0;version=2.0,*/*;q=1.0"); + headers.add("Content-Type", "application/json"); + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Headers = " + headers); + + Auth auth = new Auth(); + auth.id = user; + auth.password = password; + ObjectMapper mapper = new ObjectMapper(); + String body = mapper.writeValueAsString(auth); + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Call body = " + body.replaceAll("\"password\": ?\".*?\"", "\"password\": \"*****\"")); + + HttpEntity aafRequest = new HttpEntity(body, headers); + + ResponseEntity response = restTemplate.exchange(urlStr, HttpMethod.POST, aafRequest, String.class); + if (response.getStatusCode().equals(HttpStatus.OK)) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"AAF returned 200 OK"); + return true; + } else { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Unexpected status code returned from AAF? " + response.getStatusCode()); + if (response.getStatusCodeValue()>=200 && response.getStatusCodeValue()<=299) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Status code is 2XX, assuming OK"); + return true; + } else { + LOGGER.warn(EELFLoggerDelegate.applicationLogger,"Status code is not 2XX (" + response.getStatusCode() + "), assuming failed."); + request.setAttribute("fail", "AAF failed: AAF returned status code " + response.getStatusCode()); + return false; + } + } + + } catch (HttpClientErrorException e) { + if (e.getStatusCode().equals(HttpStatus.FORBIDDEN)) { + LOGGER.warn(EELFLoggerDelegate.applicationLogger,"AAF returned 403 Forbidden"); + request.setAttribute("fail", "AAF failed: user not authenticated."); + return false; + } else { + LOGGER.warn(EELFLoggerDelegate.applicationLogger,"Status code is not 2XX (" + e.getStatusCode() + "), assuming failed."); + request.setAttribute("fail", "AAF failed: AAF returned status code " + e.getStatusCode()); + return false; + } + } catch (JsonProcessingException e) { + LOGGER.error(EELFLoggerDelegate.errorLogger,"Call to AAF threw an exception: " + e); + request.setAttribute("fail", "AAF failed: Couldn't convert call body? " + e); + return false; + } catch (RestClientException e) { + LOGGER.error(EELFLoggerDelegate.errorLogger,"Call to AAF threw an exception: " + e); + request.setAttribute("fail", "AAF failed: call to AAF threw an exception " + e); + return false; + } + } + + public boolean userAuthorized(HttpServletRequest request, String roleRequired) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"In AAFProxy.userAuthorized"); + String user = request.getHeader("mechId"); + if (user==null || user.length()==0) { + request.setAttribute("fail", "AAF failed: mechId header not present."); + return false; + } + String urlStr = aafUrlBase + "/authz/users/" + user + "/" + roleRequired; + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Going to call AAF, url = " + urlStr); + + try { + RestTemplate restTemplate = new RestTemplate(); + + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Basic " + encodedPassword); + headers.add("Accept", "application/Users+json;q=1.0;charset=utf-8;version=2.0,application/json;q=1.0;version=2.0,*/*;q=1.0"); + + HttpEntity aafRequest = new HttpEntity(null, headers); + + ResponseEntity response = restTemplate.exchange(urlStr, HttpMethod.GET, aafRequest, String.class); + + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Received from AAF: " + response.getBody()); + ObjectMapper mapper = new ObjectMapper(); + User aafuser; + aafuser = mapper.readValue(response.getBody(), User.class); + if (aafuser.user==null) aafuser.user = new ArrayList(); + LOGGER.info(EELFLoggerDelegate.applicationLogger,"User is a " + aafuser + " with " + aafuser.user.size() + (aafuser.user.size()==0?"":(" items; " + aafuser.user.get(0).id + ", " + aafuser.user.get(0).expires)) ); + + Date now = new Date(); + for (Item item : aafuser.user) { + Date expiryDate = sdf.parse(item.expires); + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Comparing " + item.id +" to " + user); + if (!item.id.equals(user)) continue; + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Comparing " + now + " to " + expiryDate); + if (now.compareTo(expiryDate)>0) { + request.setAttribute("fail", "AAF failed: user role is expired."); + return false; + } + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Success! User authorized."); + return true; + } + } catch (JsonParseException | JsonMappingException e) { + e.printStackTrace(); + LOGGER.error(EELFLoggerDelegate.applicationLogger,"Exception while calling AAF: " + e.getMessage()); + LOGGER.error(EELFLoggerDelegate.errorLogger,"Exception while calling AAF: " + e); + request.setAttribute("fail", "AAF failed: invalid JSON returned from AAF? (" + e + ")"); + return false; + } catch (RuntimeException | IOException e) { + e.printStackTrace(); + LOGGER.error(EELFLoggerDelegate.applicationLogger,"Exception while calling AAF: " + e.getMessage()); + LOGGER.error(EELFLoggerDelegate.errorLogger,"Exception while calling AAF: " + e); + request.setAttribute("fail", "AAF failed: exception in call to AAF (" + e + ")"); + return false; + } catch (ParseException e) { + LOGGER.error(EELFLoggerDelegate.applicationLogger,"Exception while calling AAF: " + e.getMessage()); + LOGGER.error(EELFLoggerDelegate.errorLogger,"Exception while calling AAF: " + e); + e.printStackTrace(); + request.setAttribute("fail", "AAF failed: invalid date format returned from AAF? (" + e + ")"); + return false; + } + + request.setAttribute("fail", "AAF failed: user does not have role."); + return false; + } + + public void setCredentials(String encodedPassword) { + if (encodedPassword!=null) this.encodedPassword = encodedPassword; + } + +} diff --git a/valetapi/src/main/java/org/onap/fgps/api/proxy/DBProxy.java b/valetapi/src/main/java/org/onap/fgps/api/proxy/DBProxy.java new file mode 100644 index 0000000..d6753ad --- /dev/null +++ b/valetapi/src/main/java/org/onap/fgps/api/proxy/DBProxy.java @@ -0,0 +1,215 @@ +/* + * ============LICENSE_START========================================== + * ONAP - F-GPS API + * =================================================================== + * Copyright © 2019 ATT Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.fgps.api.proxy; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.onap.fgps.api.logging.EELFLoggerDelegate; +import org.onap.fgps.api.utils.CipherUtil; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; +import org.onap.fgps.api.utils.UserUtils; + +public class DBProxy { + private String[] server; + private RestTemplate rest; + private HttpHeaders headers; + private HttpStatus status; + private String ipAddress; + private boolean pingLogFlag; + + private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(DBProxy.class); + InputStream inputStream; + + + + public DBProxy(boolean pingFlag) { + this.pingLogFlag = pingFlag; + this.rest = new RestTemplate(); + this.headers = new HttpHeaders(); + headers.add("Content-Type", "application/json"); + Properties props = new Properties(); + String propFileName = "resources.properties"; + inputStream = getClass().getClassLoader().getResourceAsStream(propFileName); + try { + if (inputStream != null) { + props.load(inputStream); + } else { + if(pingLogFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"DBProxy : inputstream is not"); + } + } + } catch (IOException e) { + e.printStackTrace(); + LOGGER.error(EELFLoggerDelegate.applicationLogger,"DBProxy : Error details : "+ e.getMessage()); + LOGGER.error(EELFLoggerDelegate.errorLogger,"DBProxy : Error details : "+ e.getMessage()); + } + server = new String[3]; + server[0] = "http://" + UserUtils.htmlEscape(props.getProperty("musicdb.ip.1")) + ":" + UserUtils.htmlEscape(props.getProperty("music.MUSIC_DB_PORT")) + + UserUtils.htmlEscape(props.getProperty("music.MUSIC_DB_URL")); + server[1] = "http://" + UserUtils.htmlEscape(props.getProperty("musicdb.ip.2")) + ":" + UserUtils.htmlEscape(props.getProperty("music.MUSIC_DB_PORT")) + + UserUtils.htmlEscape(props.getProperty("music.MUSIC_DB_URL")); + server[2] = "http://" + UserUtils.htmlEscape(props.getProperty("musicdb.ip.3")) + ":" + UserUtils.htmlEscape(props.getProperty("music.MUSIC_DB_PORT")) + + UserUtils.htmlEscape(props.getProperty("music.MUSIC_DB_URL")); + headers.add("ns", UserUtils.htmlEscape(props.getProperty("musicdb.namespace"))); + headers.add("userId", UserUtils.htmlEscape(props.getProperty("musicdb.userId"))); + headers.add("password", CipherUtil.decryptPKC(props.getProperty("musicdb.password"))); + //keep headers userID and password for now, it works with old version + //new version of music(1810) needs userID and password as basic auth + headers.add("Authorization", CipherUtil.encodeBasicAuth(props.getProperty("musicdb.userId"), CipherUtil.decryptPKC(props.getProperty("musicdb.password")))); + + + } + + public DBProxy() { + this(true); + } + + public String retryRequest(String uri, HttpMethod operation, HttpEntity requestEntity, int n) { + try { + StringBuffer headerOut = new StringBuffer(); + HttpHeaders httpHeaders = requestEntity.getHeaders(); + for (String key: httpHeaders.keySet()) { + headerOut.append(", "); + if (key.toLowerCase().contains("pass") || key.equals("Authorization")) { + headerOut.append(key + ": PASSWORD CENSORED"); + } else { + headerOut.append(key + ": [" + httpHeaders.get(key) + "]"); + } + } + + String finalUri = this.server[n] + uri; + finalUri = finalUri.replaceAll("//", "/").replaceFirst("/", "//"); + if(pingLogFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger, "DBProxy: Sending request to DB : "+ finalUri + ", " + operation + headerOut.toString() ); + } + // System.out.println(); + ResponseEntity responseEntity = rest.exchange( finalUri, operation, requestEntity, String.class); + this.setStatus(responseEntity.getStatusCode()); + if(pingLogFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger, "DBProxy: Received response from DB: " + responseEntity.toString() + ", " + responseEntity.getStatusCode()); + } + return responseEntity.getBody(); + } catch (HttpClientErrorException e) { + if(pingLogFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"DBProxy : HttpClientErrorException in received response: " + e.getResponseBodyAsString() + ", " + e.getStatusCode()); + LOGGER.debug(EELFLoggerDelegate.applicationLogger, " Response headers: " + e.getResponseHeaders()); + } + LOGGER.info(EELFLoggerDelegate.errorLogger,"DBProxy : HttpClientErrorException in received response: " + e.getResponseBodyAsString() + ", " + e.getStatusCode()); + LOGGER.debug(EELFLoggerDelegate.errorLogger, " Response headers: " + e.getResponseHeaders()); + if (n < 2) { + if(pingLogFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying again"); + } + return retryRequest(uri, operation, requestEntity, n + 1); + } else { + LOGGER.error(EELFLoggerDelegate.applicationLogger,"Error while accessing MUSIC: "+ e.getMessage()); + LOGGER.error(EELFLoggerDelegate.errorLogger,"Error while accessing MUSIC: "); + LOGGER.error(EELFLoggerDelegate.errorLogger,"Error details: "+ e.getMessage()); + return "DBRequest Failed"; + } + } catch (Exception e) { + if (n < 2) { + if(pingLogFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"DBProxy : Exception in received response : "+ this.server[n] + ", " + e + ", retrying ..."); + } + LOGGER.info(EELFLoggerDelegate.errorLogger,"DBProxy : Exception in received response : "+ this.server[n] + ", " + e + ", retrying ..."); + return retryRequest(uri, operation, requestEntity, n + 1); + } else { + LOGGER.error(EELFLoggerDelegate.applicationLogger,"Error while accessing MUSIC: "+ e.getMessage()); + LOGGER.error(EELFLoggerDelegate.errorLogger,"Error while accessing MUSIC: "); + LOGGER.error(EELFLoggerDelegate.errorLogger,"Error details: "+ e.getMessage()); + return "DBRequest Failed"; + } + } + } + + public String post(String uri, String json) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"DBProxy : Post request sent"); + + HttpEntity requestEntity = new HttpEntity(json, headers); + // System.out.println(headers); + System.out.println("In DBProxy.post, Headers: " + requestEntity.getHeaders().toString().replaceAll("password=\\[.*?\\]", "password=CENSORED").replaceAll("Authorization=\\[Basic.*?\\]", "Authorization=Basic CENSORED")); + System.out.println("In DBProxy.post, Body: " + requestEntity.getBody().toString()); + return retryRequest(uri, HttpMethod.POST, requestEntity, 0); + } + + public String get(String uri) { + if(pingLogFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"DBProxy : Get request sent"); + } + + HttpEntity requestEntity = new HttpEntity("", headers); + if(pingLogFlag) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"Requesting : "+server + uri); + } + + return retryRequest(uri, HttpMethod.GET, requestEntity, 0); + } + + public String put(String uri, String json) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"DBProxy : Put request sent"); + + HttpEntity requestEntity = new HttpEntity(json, headers); + + return retryRequest(uri, HttpMethod.PUT, requestEntity, 0); + } + + public String delete(String uri, String json) { + LOGGER.info(EELFLoggerDelegate.applicationLogger,"DBProxy : Delete request sent"); + + HttpEntity requestEntity = new HttpEntity(json, headers); + + return retryRequest(uri, HttpMethod.DELETE, requestEntity, 0); + } + + public HttpStatus getStatus() { + return status; + } + + public void setStatus(HttpStatus status) { + this.status = status; + } +} -- cgit 1.2.3-korg