From 14345a8e2cb17d002bcea294130ac9fb64b6b83e Mon Sep 17 00:00:00 2001 From: vempo Date: Wed, 4 Apr 2018 15:59:32 +0300 Subject: Fixed proxy instead of resource type in audit Change-Id: I1b3c22105f27e9d3dee0947815d32eb453a56831 Issue-ID: SDC-1190 Signed-off-by: vempo --- .../servlet/jaxrs/LoggingRequestFilter.java | 62 ++++++++++++++- .../servlet/jaxrs/LoggingRequestFilterTest.java | 90 ++++++++++++++++++---- 2 files changed, 138 insertions(+), 14 deletions(-) (limited to 'openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api') diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilter.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilter.java index 06660f35f4..498587414a 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilter.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilter.java @@ -19,6 +19,8 @@ package org.openecomp.sdc.logging.servlet.jaxrs; import static org.openecomp.sdc.logging.LoggingConstants.DEFAULT_PARTNER_NAME_HEADER; import static org.openecomp.sdc.logging.LoggingConstants.DEFAULT_REQUEST_ID_HEADER; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.UUID; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; @@ -26,6 +28,8 @@ import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.Context; import javax.ws.rs.ext.Provider; import org.openecomp.sdc.logging.api.ContextData; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; import org.openecomp.sdc.logging.api.LoggingContext; import org.openecomp.sdc.logging.servlet.HttpHeader; @@ -60,6 +64,8 @@ public class LoggingRequestFilter implements ContainerRequestFilter { static final String START_TIME_KEY = "audit.start.time"; + private static final Logger LOGGER = LoggerFactory.getLogger(LoggingRequestFilter.class); + private ResourceInfo resource; private HttpHeader requestIdHeader = new HttpHeader(DEFAULT_REQUEST_ID_HEADER); @@ -79,6 +85,7 @@ public class LoggingRequestFilter implements ContainerRequestFilter { * Configuration parameter for request ID HTTP header. */ public void setRequestIdHeaders(String requestIdHeaders) { + LOGGER.debug("Valid request ID headers: {}", requestIdHeaders); this.requestIdHeader = new HttpHeader(requestIdHeaders.split(MULTI_VALUE_SEPARATOR)); } @@ -86,6 +93,7 @@ public class LoggingRequestFilter implements ContainerRequestFilter { * Configuration parameter for partner name HTTP header. */ public void setPartnerNameHeaders(String partnerNameHeaders) { + LOGGER.debug("Valid partner name headers: {}", partnerNameHeaders); this.partnerNameHeader = new HttpHeader(partnerNameHeaders.split(MULTI_VALUE_SEPARATOR)); } @@ -95,6 +103,12 @@ public class LoggingRequestFilter implements ContainerRequestFilter { if (resource == null) { // JAX-RS could not find a mapping this response, probably due to HTTP 404 (not found), // 405 (method not allowed), 415 (unsupported media type), etc. with a message in Web server log + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("No matching resource was found for URI '{}' and method '{}'", + containerRequestContext.getUriInfo().getPath(), containerRequestContext.getMethod()); + } + return; } @@ -103,7 +117,7 @@ public class LoggingRequestFilter implements ContainerRequestFilter { LoggingContext.clear(); ContextData.ContextDataBuilder contextData = ContextData.builder(); - contextData.serviceName(resource.getResourceClass().getName() + "." + resource.getResourceMethod().getName()); + contextData.serviceName(getServiceName()); String partnerName = partnerNameHeader.getAny(containerRequestContext::getHeaderString); if (partnerName != null) { @@ -115,4 +129,50 @@ public class LoggingRequestFilter implements ContainerRequestFilter { LoggingContext.put(contextData.build()); } + + private String getServiceName() { + + Class resourceClass = resource.getResourceClass(); + Method resourceMethod = resource.getResourceMethod(); + + if (Proxy.isProxyClass(resourceClass)) { + LOGGER.debug("Proxy class injected for JAX-RS resource"); + return getServiceNameFromJavaProxy(resourceClass, resourceMethod); + } + + return formatServiceName(resourceClass, resourceMethod); + } + + private String getServiceNameFromJavaProxy(Class proxyType, Method resourceMethod) { + + for (Class interfaceType : proxyType.getInterfaces()) { + + if (isMatchingInterface(interfaceType, resourceMethod)) { + return formatServiceName(interfaceType, resourceMethod); + } + } + + LOGGER.debug("Failed to find method '{}' in interfaces implemented by injected Java proxy", resourceMethod); + return formatServiceName(proxyType, resourceMethod); + } + + private String formatServiceName(Class resourceClass, Method resourceMethod) { + return resourceClass.getName() + "#" + resourceMethod.getName(); + } + + private boolean isMatchingInterface(Class candidateType, Method requestedMethod) { + + try { + + Method candidate = candidateType.getDeclaredMethod(requestedMethod.getName(), + requestedMethod.getParameterTypes()); + return candidate != null; + + } catch (NoSuchMethodException ignored) { + // ignore and move on to the next + LOGGER.debug("Failed to find method '{}' in interface '{}'", requestedMethod, candidateType); + } + + return false; + } } diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilterTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilterTest.java index 0e0be017df..579f41c3e6 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilterTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/servlet/jaxrs/LoggingRequestFilterTest.java @@ -21,6 +21,7 @@ import static org.easymock.EasyMock.anyString; import static org.openecomp.sdc.logging.servlet.jaxrs.LoggingRequestFilter.START_TIME_KEY; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.UUID; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ResourceInfo; @@ -44,13 +45,19 @@ import org.testng.annotations.Test; @PrepareForTest({LoggingContext.class, ContextData.class}) public class LoggingRequestFilterTest extends PowerMockTestCase { - private static final Class RESOURCE_CLASS = MockResource.class; - private static final Method RESOURCE_METHOD = MockResource.class.getDeclaredMethods()[0]; - private static final String RESOURCE_NAME = RESOURCE_CLASS.getName() + "." + RESOURCE_METHOD.getName(); + private static final Class DEFAULT_RESOURCE_CLASS = MockResource.class; + private static final Method DEFAULT_RESOURCE_METHOD = MockResource.class.getDeclaredMethods()[0]; + private static final String DEFAULT_SERVICE_NAME = + formatServiceName(DEFAULT_RESOURCE_CLASS, DEFAULT_RESOURCE_METHOD); private static final String RANDOM_REQUEST_ID = UUID.randomUUID().toString(); + private static final String RANDOM_PARTNER_NAME = UUID.randomUUID().toString(); + private static String formatServiceName(Class resourceClass, Method resourceMethod) { + return resourceClass.getName() + "#" + resourceMethod.getName(); + } + /** * Verify all mocks after each test. */ @@ -74,9 +81,9 @@ public class LoggingRequestFilterTest extends PowerMockTestCase { } @Test - public void serviceNamePopulatedWhenThereIsMatchingResource() { + public void serviceNamePopulatedWhenThereIsMatchingResourceAndConcreteType() { - mockContextDataBuilder(null, RESOURCE_NAME, null); + mockContextDataBuilder(null, DEFAULT_SERVICE_NAME, null); mockLoggingContext(); LoggingRequestFilter filter = new LoggingRequestFilter(); @@ -87,10 +94,55 @@ public class LoggingRequestFilterTest extends PowerMockTestCase { new PartnerHeader(null))); } + @Test + public void serviceNamePopulatedWhenThereIsMatchingResourceAndJavaProxyType() throws NoSuchMethodException { + + Object proxyResource = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), + new Class[] {MockResource.class}, (proxy, method, arguments) -> null); + + final String serviceName = formatServiceName(MockResource.class, DEFAULT_RESOURCE_METHOD); + + mockContextDataBuilder(null, serviceName, null); + mockLoggingContext(); + + LoggingRequestFilter filter = new LoggingRequestFilter(); + + Class proxyClass = proxyResource.getClass(); + Method proxyMethod = + proxyClass.getMethod(DEFAULT_RESOURCE_METHOD.getName(), DEFAULT_RESOURCE_METHOD.getParameterTypes()); + + filter.setResource(mockResource(proxyClass, proxyMethod)); + + filter.filter(mockContainerRequestContext( + new RequestIdHeader(null), + new PartnerHeader(null))); + } + + @Test + public void serviceNameIncludesProxyClassnameWhenJavaProxyTypeAndNoMatchingInterface() { + + Object proxyResource = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), + new Class[] {Comparable.class}, (proxy, method, arguments) -> null); + + final String serviceName = formatServiceName(proxyResource.getClass(), DEFAULT_RESOURCE_METHOD); + + mockContextDataBuilder(null, serviceName, null); + mockLoggingContext(); + + LoggingRequestFilter filter = new LoggingRequestFilter(); + + Class proxyClass = proxyResource.getClass(); + filter.setResource(mockResource(proxyClass, DEFAULT_RESOURCE_METHOD)); + + filter.filter(mockContainerRequestContext( + new RequestIdHeader(null), + new PartnerHeader(null))); + } + @Test public void partnerNamePopulatedWhenPresentInDefaultHeader() { - mockContextDataBuilder(null, RESOURCE_NAME, RANDOM_PARTNER_NAME); + mockContextDataBuilder(null, DEFAULT_SERVICE_NAME, RANDOM_PARTNER_NAME); mockLoggingContext(); LoggingRequestFilter filter = new LoggingRequestFilter(); @@ -105,7 +157,7 @@ public class LoggingRequestFilterTest extends PowerMockTestCase { public void partnerNamePopulatedWhenPresentInCustomHeader() { final String partnerHeader = "x-partner-header"; - mockContextDataBuilder(null, RESOURCE_NAME, RANDOM_PARTNER_NAME); + mockContextDataBuilder(null, DEFAULT_SERVICE_NAME, RANDOM_PARTNER_NAME); mockLoggingContext(); LoggingRequestFilter filter = new LoggingRequestFilter(); @@ -120,7 +172,7 @@ public class LoggingRequestFilterTest extends PowerMockTestCase { @Test public void requestIdPopulatedWhenPresentInDefaultHeader() { - mockContextDataBuilder(RANDOM_REQUEST_ID, RESOURCE_NAME, null); + mockContextDataBuilder(RANDOM_REQUEST_ID, DEFAULT_SERVICE_NAME, null); mockLoggingContext(); LoggingRequestFilter filter = new LoggingRequestFilter(); @@ -135,7 +187,7 @@ public class LoggingRequestFilterTest extends PowerMockTestCase { public void requestIdPopulatedWhenPresentInCustomHeader() { final String requestIdHeader = "x-request-id"; - mockContextDataBuilder(RANDOM_REQUEST_ID, RESOURCE_NAME, null); + mockContextDataBuilder(RANDOM_REQUEST_ID, DEFAULT_SERVICE_NAME, null); mockLoggingContext(); LoggingRequestFilter filter = new LoggingRequestFilter(); @@ -148,10 +200,14 @@ public class LoggingRequestFilterTest extends PowerMockTestCase { } private ResourceInfo mockResource() { + return mockResource(DEFAULT_RESOURCE_CLASS, DEFAULT_RESOURCE_METHOD); + } + + private ResourceInfo mockResource(Class resourceType, Method resourceMethod) { ResourceInfo resource = EasyMock.mock(ResourceInfo.class); //noinspection unchecked - EasyMock.expect(resource.getResourceClass()).andReturn(RESOURCE_CLASS); - EasyMock.expect(resource.getResourceMethod()).andReturn(RESOURCE_METHOD); + EasyMock.expect(resource.getResourceClass()).andReturn(resourceType); + EasyMock.expect(resource.getResourceMethod()).andReturn(resourceMethod); EasyMock.replay(resource); return resource; } @@ -252,11 +308,19 @@ public class LoggingRequestFilterTest extends PowerMockTestCase { } } - private static class MockResource { + private interface MockResource { @SuppressWarnings("EmptyMethod") - void process() { + void process(); + } + + private static class MockResourceImpl implements MockResource { + + @Override + public void process() { // no-op } } + + } \ No newline at end of file -- cgit 1.2.3-korg