Carry forward honolulu fixes 14/123814/2
authorDan Timoney <dtimoney@att.com>
Mon, 22 Mar 2021 13:45:16 +0000 (09:45 -0400)
committerDan Timoney <dtimoney@att.com>
Thu, 2 Sep 2021 14:25:07 +0000 (10:25 -0400)
This change carries forward the following fixes from Honolulu to master

Update to allow ranges for ccsdk.sli.version

Update to allow ccsdk.sli.version to be passed with a range as a value

Change-Id: Ibb37082bf8162300ae2de37f33b0e4672b796293
Issue-ID: CCSDK-3209
Signed-off-by: Dan Timoney <dtimoney@att.com>
(cherry picked from commit c3e800149c947ecc9b76a2e3b990664fc5d41ce1)

Minor Refactoring of sliboot pom

Issue-ID: CCSDK-3343
Change-Id: I66d4e2840ff86e092a23453384d02ce49b7048ac
Signed-off-by: Singal, Kapil (ks220y) <ks220y@att.com>
Use CadiFilter instead of shiro

Microservices should use CadiFilter rather than shiro to integrate
with AAF

Change-Id: I95b9a844b7ac868f864134de7345013001357352
Issue-ID: SDNC-1523
Signed-off-by: Dan Timoney <dtimoney@att.com>
(cherry picked from commit a90eecf70419ec4acba6f5a8425300eef7f45290)

Minor Refactoring of sliboot pom

Updating docker-maven-plugin to 0.34.0 and
removing docker image build goal (it was there twice)

Issue-ID: CCSDK-3343
Signed-off-by: Singal, Kapil (ks220y) <ks220y@att.com>
Change-Id: I26401befaf235ddfe694c6206cbd547cbc56cc03
(cherry picked from commit 108a13c20757f4a437aea22880f019e6e6043841)

missing logs

Add filters for audit and request/response log
Add filters for audit and request/response log

Issue-ID: CCSDK-3367
Signed-off-by: lalena.aria <lalena.aria@att.com>
Change-Id: Id292c1f5109f0c3846a0357d0618f607011825a4

Add code to handle content type plain/text

Add code to handle content type plain/text

Issue-ID: CCSDK-3378
Signed-off-by: lalena.aria <lalena.aria@att.com>
Change-Id: Id4a30ad5ca81db0e7e3a328cc5d2496c42c9e150
Signed-off-by: Dan Timoney <dtimoney@att.com>
1201 sanity test

Add bean for IpAddressTool plugin
Add missing import
Add bean for IpAddressTool plugin
Add missing import
Fx typo (text/plain instead of plain/text)

Issue-ID: CCSDK-3379
Signed-off-by: lalena.aria <lalena.aria@att.com>
Change-Id: I208a6eaf462f86c2a3015af9bf9026ad11efa14b
Signed-off-by: Dan Timoney <dtimoney@att.com>
Use version 1.1.8 of parent

Use version 1.1.8 of parent in order to use APL-licensed version
of liquibase

Issue-ID: CCSDK-3423
Signed-off-by: Dan Timoney <dtimoney@att.com>
Change-Id: I1db475fa8991d617d22536ce38d51f96c7806f85

ms/neng/pom.xml
ms/pom.xml
ms/sliboot/pom.xml
ms/sliboot/src/main/java/org/onap/ccsdk/apps/ms/sliboot/SlibootApp.java
services/pom.xml
services/src/main/java/org/onap/ccsdk/apps/filters/AuditLogFilter.java [new file with mode: 0644]
services/src/main/java/org/onap/ccsdk/apps/filters/ContentTypeFilter.java
services/src/main/java/org/onap/ccsdk/apps/filters/PayloadLoggingFilter.java [new file with mode: 0644]
services/src/main/java/org/onap/ccsdk/apps/services/SvcLogicFactory.java

index b9a16ff..84b9cc5 100644 (file)
@@ -18,7 +18,6 @@
  * limitations under the License.
  * ============LICENSE_END=========================================================
   -->
-
 <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>
 
index 836a4b5..94cd841 100644 (file)
@@ -18,7 +18,6 @@
  * limitations under the License.
  * ============LICENSE_END=========================================================
  -->
-
 <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>
 
index a9ffec0..783e7fd 100644 (file)
             <version>${aaf.cadi.version}</version>
             <scope>runtime</scope>
         </dependency>
+        <!-- Needed by logging-analytics payload logging filter -->
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
+            <version>3.4.4</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.aaf.authz</groupId>
+            <artifactId>aaf-cadi-client</artifactId>
+            <version>${aaf.cadi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.aaf.authz</groupId>
+            <artifactId>aaf-cadi-core</artifactId>
+            <version>${aaf.cadi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.aaf.authz</groupId>
+            <artifactId>aaf-auth-client</artifactId>
+            <version>${aaf.cadi.version}</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.aaf.authz</groupId>
+            <artifactId>aaf-misc-env</artifactId>
+            <version>${aaf.cadi.version}</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.aaf.authz</groupId>
+            <artifactId>aaf-misc-rosetta</artifactId>
+            <version>${aaf.cadi.version}</version>
+            <scope>runtime</scope>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>services</artifactId>
index beab256..2bca1db 100644 (file)
@@ -50,8 +50,6 @@ public class SlibootApp {
     SpringApplication.run(SlibootApp.class, args);\r
   }\r
 \r
-\r
-\r
   @Bean\r
   @ConditionalOnProperty("cadi.properties.path")\r
        @Order(1)\r
index 5328b55..c3f1e91 100644 (file)
@@ -22,6 +22,7 @@
         <ccsdk.project.version>${project.version}</ccsdk.project.version>
         <ccsdk.build.timestamp>${maven.build.timestamp}</ccsdk.build.timestamp>
         <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
+        <logging.analytics.version>1.6.9</logging.analytics.version>
     </properties>
 
     <dependencies>
@@ -90,7 +91,7 @@
         <dependency>
             <groupId>org.onap.logging-analytics</groupId>
             <artifactId>logging-filter-spring</artifactId>
-            <version>1.6.6</version>
+            <version>${logging.analytics.version}</version>
         </dependency>
         <dependency>
             <groupId>javax.ws.rs</groupId>
diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/AuditLogFilter.java b/services/src/main/java/org/onap/ccsdk/apps/filters/AuditLogFilter.java
new file mode 100644 (file)
index 0000000..b6d52c5
--- /dev/null
@@ -0,0 +1,43 @@
+package org.onap.ccsdk.apps.filters
+;
+
+import javax.servlet.http.HttpServletRequest;
+import org.onap.logging.filter.base.AuditLogServletFilter;
+import org.onap.logging.ref.slf4j.ONAPLogConstants;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AuditLogFilter extends AuditLogServletFilter {
+    private static final String MDC_HTTP_METHOD_KEY = "HttpMethod";
+
+    @Override
+    protected void additionalPreHandling(HttpServletRequest httpServletRequest) {
+        // Don't overwrite service instance id if it was set outside of this automated method
+        if (MDC.get(ONAPLogConstants.MDCs.SERVICE_INSTANCE_ID) == null) {
+            String serviceInstanceId = getServiceInstanceId(httpServletRequest.getRequestURI());
+            if (serviceInstanceId != null) {
+                MDC.put(ONAPLogConstants.MDCs.SERVICE_INSTANCE_ID, serviceInstanceId);
+            }
+        }
+        MDC.put(MDC_HTTP_METHOD_KEY, httpServletRequest.getMethod());
+    }
+
+    // restconf URLs follow a pattern, this method attempts to extract the service instance id according to that pattern
+    protected String getServiceInstanceId(String path) {
+        int idx = path.indexOf("service-list");
+        if (idx != -1) {
+            // chomp off service-list/
+            String str = path.substring(idx + 13);
+            idx = str.indexOf("/");
+            //if there is another forward slash with more information chomp it off
+            if (idx != -1) {
+                return str.substring(0, idx);
+            } else {
+                return str;
+            }
+        }
+        return null;
+    }
+
+}
\ No newline at end of file
index 41c71a4..20f9ec4 100644 (file)
@@ -3,6 +3,7 @@ package org.onap.ccsdk.apps.filters;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -14,6 +15,8 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.core.Ordered;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
@@ -24,33 +27,84 @@ public class ContentTypeFilter implements Filter {
 
     String DEFAULT_CONTENT_TYPE = "application/json";
 
+
     @Override
     public void doFilter(ServletRequest httpReq, ServletResponse httpResp, FilterChain chain)
             throws IOException, ServletException {
                 String defaultContentType = System.getProperty("ccsdk.defaults.content-type", DEFAULT_CONTENT_TYPE);
-
                 chain.doFilter(new DefaultContentTypeHttpRequest((HttpServletRequest) httpReq, defaultContentType), httpResp);
 
     }
 
     private class DefaultContentTypeHttpRequest extends HttpServletRequestWrapper {
         HttpServletRequest httpRequest;
-        String defaultContentType;
-        boolean hasContentType;
+        String contentType;
+        List<String> acceptList;
 
         List<String> headerNames; 
 
         public DefaultContentTypeHttpRequest(HttpServletRequest httpRequest, String defaultContentType) {
             super(httpRequest);
+
             this.httpRequest = httpRequest;
-            this.defaultContentType = defaultContentType;
+            this.contentType = defaultContentType;
+            this.acceptList = null;
+
+            boolean hasContentType = false;
             headerNames = new LinkedList<String>();
             Enumeration<String> headerNameEnum = httpRequest.getHeaderNames();
-            hasContentType = false;
             while (headerNameEnum.hasMoreElements()) {
                 String curHeaderName = headerNameEnum.nextElement();
                 if ("Content-Type".equalsIgnoreCase(curHeaderName)) {
                     hasContentType = true;
+                    contentType = super.getContentType();
+                    if ("application/yang-data+json".equalsIgnoreCase(contentType)) {
+                        contentType = "application/json";
+                    } else if ("application/yang-data+xml".equalsIgnoreCase(contentType)) {
+                        contentType = "application/xml";
+                    } else if (contentType.startsWith("text/plain")) {
+                        // Use Accept header, if present, to determine content type.
+                        boolean acceptsXml = false;
+                        boolean acceptsJson = false;
+                        for (Enumeration<String> e = getHeaders("Accept") ; e.hasMoreElements() ;) {
+                            String curAcceptValue = e.nextElement();
+                            if ("application/json".equalsIgnoreCase(curAcceptValue)) {
+                                acceptsJson = true;
+                            } else if ("application/yang-data+json".equalsIgnoreCase(curAcceptValue)) {
+                                acceptsJson = true;
+                            } else if ("application/xml".equalsIgnoreCase(curAcceptValue)) {
+                                acceptsXml = true;
+                            } else if ("application/yang-data+xml".equalsIgnoreCase(curAcceptValue)) {
+                                acceptsXml = true;
+                            }
+                        }
+                        if (acceptsJson) {
+                            contentType = "application/json";
+                        } else if (acceptsXml) {
+                            contentType = "application/xml";
+                        } else {
+                            // If Accept does not specify XML or JSON (could be Accept is missing), use default content type
+                            contentType = defaultContentType;
+                        }
+                    }
+                } else if ("Accept".equalsIgnoreCase(curHeaderName)) {
+                    acceptList = new LinkedList<String>();
+                    for (Enumeration<String> e = getHeaders("Accept") ; e.hasMoreElements() ;) {
+                        String acceptValue = e.nextElement();
+                        if ("application/yang-data+json".equalsIgnoreCase(acceptValue)) {
+                            if (!acceptList.contains("application/json")) {
+                                acceptList.add("application/json");
+                            }
+                        } else if ("application/yang-data+xml".equalsIgnoreCase(acceptValue)) {
+                            if (!acceptList.contains("application/xml")) {
+                                acceptList.add("application/xml");
+                            }
+                        } else {
+                            if (!acceptList.contains(acceptValue)) {
+                                acceptList.add(acceptValue);
+                            }
+                        }
+                    }
                 }
                 headerNames.add(curHeaderName);
             }
@@ -69,6 +123,17 @@ public class ContentTypeFilter implements Filter {
             }
         }
 
+        
+
+        @Override
+        public Enumeration<String> getHeaders(String name) {
+            if ("Accept".equalsIgnoreCase(name) && (acceptList != null)) {
+                return Collections.enumeration(acceptList);
+            } else {
+                return super.getHeaders(name);
+            }
+        }
+
         @Override
         public Enumeration<String> getHeaderNames() {
             return(Collections.enumeration(headerNames));
@@ -76,11 +141,7 @@ public class ContentTypeFilter implements Filter {
 
         @Override
         public String getContentType() {
-            if (hasContentType) {
-                return super.getContentType();
-            } else {
-                return defaultContentType;
-            }
+           return contentType;
         }
         
     }
diff --git a/services/src/main/java/org/onap/ccsdk/apps/filters/PayloadLoggingFilter.java b/services/src/main/java/org/onap/ccsdk/apps/filters/PayloadLoggingFilter.java
new file mode 100644 (file)
index 0000000..e53c50a
--- /dev/null
@@ -0,0 +1,322 @@
+package org.onap.ccsdk.apps.filters;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ReadListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.WriteListener;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import org.onap.logging.filter.base.AbstractServletFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PayloadLoggingFilter extends AbstractServletFilter implements Filter {
+
+       private static final Logger log = LoggerFactory.getLogger(PayloadLoggingFilter.class);
+
+       @Override
+       public void init(FilterConfig filterConfig) throws ServletException {
+       }
+
+       @Override
+       public void destroy() {
+       }
+
+       @Override
+       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+               RequestWrapper req = new RequestWrapper((HttpServletRequest) request);
+               Request requestData = req.getMessageRequest();
+               
+               StringBuilder requestHeaders = new StringBuilder("REQUEST|");
+           requestHeaders.append(requestData.method);
+           requestHeaders.append(":");
+           requestHeaders.append(requestData.uri);
+           requestHeaders.append("|");
+           mapstr(requestHeaders, requestData.headers);
+
+           log.info(requestHeaders.toString());
+           log.info("REQUEST BODY|{}", requestData.body);
+
+               ResponseWrapper res = new ResponseWrapper((HttpServletResponse) response);
+
+               chain.doFilter(req, res);
+
+               Response responseData = res.getMessageResponse();
+               
+               StringBuilder responseHeaders = new StringBuilder();
+        responseHeaders.append("RESPONSE HEADERS|");
+        mapstr(responseHeaders, responseData.headers);
+        responseHeaders.append("Status:").append(responseData.code);
+        responseHeaders.append(";IsCommitted:").append(res.isCommitted());
+
+        log.info(responseHeaders.toString());
+               log.info("RESPONSE BODY|{}", responseData.body);
+
+               res.writeBody();
+       }
+
+       private static class Request {
+
+               public String method;
+               public String uri;
+               public Map<String, Object> headers;
+               public Map<String, Object> param;
+               public String body;
+
+               @Override
+               public String toString() {
+                       StringBuilder ss = new StringBuilder();
+                       ss.append("REQUEST|").append(method).append(":").append(uri).append("|");
+                       ss.append("Headers: ");
+                       mapstr(ss, headers);
+                       if (param != null && !param.isEmpty()) {
+                               ss.append("Parameters: ");
+                               mapstr(ss, param);
+                       }
+                       ss.append("REQUEST BODY|\n");
+                       ss.append(body);
+                       return ss.toString();
+               }
+       }
+
+       private static class Response {
+
+               public int code;
+               public String message;
+               public Map<String, Object> headers;
+               public String body;
+
+               @Override
+               public String toString() {
+                       StringBuilder ss = new StringBuilder();
+                       ss.append("HTTP Response: ").append(code).append(" ").append(message).append("\n");
+                       ss.append("Headers:\n");
+                       mapstr(ss, headers);
+                       ss.append("Body:\n");
+                       ss.append(body);
+                       return ss.toString();
+               }
+       }
+
+       private static class RequestWrapper extends HttpServletRequestWrapper {
+
+               private final String body;
+
+               public RequestWrapper(HttpServletRequest request) throws IOException {
+                       super(request);
+
+                       StringBuilder stringBuilder = new StringBuilder();
+                       InputStream inputStream = request.getInputStream();
+                       if (inputStream != null) {
+                               try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
+                                       char[] charBuffer = new char[128];
+                                       int bytesRead = -1;
+                                       while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
+                                               stringBuilder.append(charBuffer, 0, bytesRead);
+                                       }
+                               }
+                       }
+                       body = stringBuilder.toString();
+               }
+
+               @Override
+               public ServletInputStream getInputStream() throws IOException {
+                       final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
+                       ServletInputStream servletInputStream = new ServletInputStream() {
+
+                               @Override
+                               public int read() throws IOException {
+                                       return byteArrayInputStream.read();
+                               }
+
+                               @Override
+                               public boolean isFinished() {
+                                       return byteArrayInputStream.available() == 0;
+                               }
+
+                               @Override
+                               public boolean isReady() {
+                                       return true;
+                               }
+
+                               @Override
+                               public void setReadListener(ReadListener listener) {
+                               }
+                       };
+                       return servletInputStream;
+               }
+
+               @Override
+               public BufferedReader getReader() throws IOException {
+                       return new BufferedReader(new InputStreamReader(getInputStream()));
+               }
+
+               public String getBody() {
+                       return body;
+               }
+
+               public Request getMessageRequest() {
+                       Request r = new Request();
+                       r.method = getMethod();
+                       r.uri = getRequestURI();
+                       r.param = getParamMap();
+
+                       r.headers = new HashMap<>();
+                       Enumeration<String> headerNames = getHeaderNames();
+                       while (headerNames.hasMoreElements()) {
+                               String name = headerNames.nextElement();
+
+                               if (name.equalsIgnoreCase("authorization")) {
+                                       r.headers.put(name, "***REDACTED***");
+                                       continue;
+                               }
+
+                               Enumeration<String> values = getHeaders(name);
+                               List<String> valueList = new ArrayList<>();
+                               while (values.hasMoreElements()) {
+                                       valueList.add(values.nextElement());
+                               }
+                               if (valueList.size() > 1) {
+                                       r.headers.put(name, valueList);
+                               } else if (valueList.size() > 0) {
+                                       r.headers.put(name, valueList.get(0));
+                               }
+                       }
+
+                       r.body = getBody();
+
+                       return r;
+               }
+
+               private Map<String, Object> getParamMap() {
+                       Map<String, String[]> parameterMap = getParameterMap();
+                       Map<String, Object> paramMap = new HashMap<>();
+                       if (parameterMap != null) {
+                               for (Entry<String, String[]> entry : parameterMap.entrySet()) {
+                                       String name = entry.getKey();
+                                       String[] values = entry.getValue();
+                                       if (values != null && values.length > 0) {
+                                               if (values.length == 1) {
+                                                       paramMap.put(name, values[0]);
+                                               } else {
+                                                       paramMap.put(name, Arrays.<String> asList(values));
+                                               }
+                                       }
+                               }
+                       }
+                       return paramMap;
+               }
+       }
+
+       public class ResponseWrapper extends HttpServletResponseWrapper {
+
+               private CharArrayWriter writer = new CharArrayWriter();
+
+               private String statusMessage;
+
+               public ResponseWrapper(HttpServletResponse response) {
+                       super(response);
+               }
+
+               @Override
+               public PrintWriter getWriter() {
+                       return new PrintWriter(writer);
+               }
+
+               @Override
+               public ServletOutputStream getOutputStream() {
+                       return new ServletOutputStream() {
+
+                               @Override
+                               public void write(int b) throws IOException {
+                                       writer.write(b);
+                               }
+
+                               @Override
+                               public void setWriteListener(WriteListener listener) {
+                               }
+
+                               @Override
+                               public boolean isReady() {
+                                       return true;
+                               }
+                       };
+               }
+
+               @SuppressWarnings("deprecation")
+               @Override
+               public void setStatus(int sc, String sm) {
+                       super.setStatus(sc, sm);
+                       statusMessage = sm;
+               }
+
+               public Response getMessageResponse() {
+                       Response r = new Response();
+                       r.code = getStatus();
+                       r.message = statusMessage == null ? "" : statusMessage;
+
+                       r.headers = new HashMap<>();
+                       Collection<String> headerNames = getHeaderNames();
+                       for (String name : headerNames) {
+
+                               if (name.equalsIgnoreCase("authorization")) {
+                                       r.headers.put(name, "***REDACTED***");
+                                       continue;
+                               }
+
+                               Collection<String> values = getHeaders(name);
+                               List<String> valueList = new ArrayList<>(values);
+                               if (valueList.size() > 1) {
+                                       r.headers.put(name, valueList);
+                               } else {
+                                       r.headers.put(name, valueList.get(0));
+                               }
+                       }
+
+                       r.body = writer.toString();
+
+                       return r;
+               }
+
+               public void writeBody() throws IOException {
+                       String body = writer.toString();
+                       setContentLength(body.length());
+                       super.getWriter().write(body);
+               }
+       }
+
+       private static void mapstr(StringBuilder ss, Map<String, Object> m) {
+               if (m != null) {
+                       for (Entry<String, Object> entry : m.entrySet()) {
+                               ss.append(entry.getKey()).append(": ").append(entry.getValue()).append(";");
+                       }
+               }
+       }
+}
\ No newline at end of file