How to Log HttpRequest and HttpResponse in a file? - spring

Can anyone explain any techniques to log HttpRequest and HttpResponse in a file.
We are using Spring MVC/Spring Rest.
What we want is to intercept the request before it is processed and log it.
Same way intercept the response before it is sent and log it.
Thanks a lot in advance.

For logging the request Spring has the AbstractRequestLoggingFilter class (well actually one of the subclasses). This can be used to log the incoming request (before and after processing).
Depending on the configuration this can include the payload, client information and full URL (including erquest parameters). All these three are disabled by default but can be enabled through configuration (see the javadoc for more information).
<filter>
<filter-name>requestLoggingFilter</filter-name>
<filter-class>org.springframework.web.filter.CommonsRequestLoggingFilter</filter-class>
<init-param>
<param-name>includeClientInfo</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>includePayload</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>includeQueryString</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>requestLoggingFilter</filter-name>
<servlet-name>dispatcherServlet</servlet-name>
</filter-mapping>
The filter will now log everything using a Commons Logging logger to a logfile.

Accepted answer is already correct, adding annotation based configuration. Add following bean to your config.
#Bean
public CommonsRequestLoggingFilter requestLoggingFilter() {
CommonsRequestLoggingFilter loggingFilter = new CommonsRequestLoggingFilter();
loggingFilter.setIncludeClientInfo(true);
loggingFilter.setIncludeQueryString(true);
loggingFilter.setIncludePayload(true);
return loggingFilter;
}

Related

What is the purpose of Spring CharacterEncodingFilter

I'm working on an existing project in the configuration file I found this filter that I didn't understand the the purpose of this filter Spring CharacterEncodingFilter I read some documentation but still i didn't understand how it's work :
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
Any help Thank you
I think documentation is pretty clear: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/filter/CharacterEncodingFilter.html
"Servlet Filter that allows one to specify a character encoding for requests. This is useful because current browsers typically do not set a character encoding even if specified in the HTML page or form."

Using Jetty's proxy in standalone Jetty application

I'm investigating using Jetty 9 as a proxy, using standalone Jetty, not embedded Jetty. I've looked for help in many places:
Most of these are related to embedded Jetty:
How to create Proxy Server using jetty8?
Jetty ProxyServlet with SSL support
This question is along the same lines:
Can stand-alone Jetty be used as a reverse proxy (without Apache mod-proxy)
...but the only answer is a link to a page that covers some parameters for the proxy, but no examples or other helpful hints.
On to the question...
I've created an extension to Jetty's ProxyServlet, which overrides the rewriteURI() method to actually change the request to a different URL. This custom proxy works when running Jetty embedded, but when I use a web.xml file and the jetty-maven-plugin to create a war to deploy, it no longer works.
When I make a request, I can debug the application and see that it gets into the rewriteURI() method, it then calls Jetty's ProxyServlet's service() method, which runs to completion, but then nothing happens. The page remains blank, and eventually ProxyServlet's onResponseFailure() is called with a TimeoutException, "Total timeout elapsed". Dev tools shows the request receiving a 504 Gateway Timeout.
It seems as though something is missing in how things are connected, but I can't tell what it might be. Any help would be greatly appreciated. I've included web.xml and the custom proxy (ProxyServletExtension) below.
web.xml
<servlet>
<servlet-name>proxy</servlet-name>
<servlet-class>org.example.ProxyServletExtension</servlet-class>
<init-param>
<param-name>maxThreads</param-name>
<param-value>1</param-value>
</init-param>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>proxy</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
ProxyServletExtension.java
...
import org.eclipse.jetty.proxy.ProxyServlet;
...
public class ProxyServletExtension extends ProxyServlet {
#Override
protected URI rewriteURI(HttpServletRequest request) {
// Forward all requests to another port on this machine
String uri = "http://localhost:8060";
// Take the current path and append it to the new url
String path = request.getRequestURI();
uri += path;
// Add query params
String query = request.getQueryString();
if (query != null && query.length() > 0) {
uri += "?" + query;
}
return URI.create(uri).normalize();
}
}
I found the hints I needed to solve this with jetty transparent proxy always returns 403 forbidden. The question didn't exactly pertain to my question, but the code snippet provided showed me what I needed in the <servlet> in web.xml.
Updated web.xml
<servlet>
<servlet-name>proxy</servlet-name>
<servlet-class>org.example.ProxyServletExtension$Transparent</servlet-class>
<init-param>
<param-name>maxThreads</param-name>
<param-value>1</param-value>
</init-param>
<init-param>
<param-name>proxyTo</param-name>
<param-value>http://localhost:8060</param-value>
</init-param>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>proxy</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Required changes
Set the <servlet-class> to ProxyServletExtension$Transparent, previously I wasn't using a trasparent proxy.
Use an <init-param> of proxyTo using the address you would like to proxy the requests to. This also means that the ProxyServletExtension.java class above (in the question) is completely unnecessary.
Also, it is worth mentioning that there is a prefix <init-param> as well, which can be used to remove part of the incoming request before proxying to the proxied request.

Spring HiddenHttpMethodFilter and blocking HTTP methods

I am only allowing GET and POST methods in my Spring 3.2 application.
Though I use Spring's HiddenHttpMethodFilter which uses _method parameter to support various PUT, DELETE controller request mappings.
But security is saying that our servers allow various insecure methods like OPTIONS , TRACE and others since they can see the Allow header in response when they manipulate the _method value.
Is it really a security threat ?
And is it possible to use _method for only PUT and DELETE ?
In Spring MVC by default the OPTIONS and TRACE methods are not dispatched to controllers, even if you configure controllers to handle those methods. So by default Spring MVC protects prevents those methods from being used,even though the Accept header shows them as available.
These defaults can be changed in the following way if needed:
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/your-mvc-dispatcher-servlet.xml</param-value>
</init-param>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>dispatchTraceRequest</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
If needed the contents of the Accept header can be customized like this:
#RequestMapping(value = "/someurl", method = RequestMethod.GET)
public ResponseEntity tryOptions(HttpSession session) throws Exception {
... controller logic ...
HttpHeaders headers = new HttpHeaders();
headers.set("Allow","POST, GET");
return new ResponseEntity(headers, HttpStatus..SOME_STATUS_CODE);
}

Endless redirect loop after ticket validation

I'm using the Liferay Portal 6.1.1 CE GA2.
After hours of research I got the following things to work:
Import from a LDAP-Server and custom mapping of an attribute to an usergroup.
Redirect to a specific page after login (based on the usergroup).
Authentication via CAS. This means getting a ServiceTicket and logging in the corresponding user.
Now I'm trying to obtain ProxyTickets so I can proxy to other applications behind the same CAS-Server.
I'm not really getting any error, but Mozilla gives me a redirection error, e.g. the page is redirected in such a way that it can never be loaded.
I googled a lot and tried different approaches but nothing helped.
My web.xml is configured as follows (I snipped out urls. If they're important I can hand them in later):
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>* snip */cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>* snip *</param-value>
</init-param>
</filter>
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>* snip */cas/</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>* snip *</param-value>
</init-param>
<init-param>
<param-name>proxyCallbackUrl</param-name>
<param-value>https://* snip */pgtCallback</param-value>
</init-param>
<init-param>
<param-name>proxyReceptorUrl</param-name>
<param-value>/pgtCallback</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/c/portal/login</url-pattern>
</filter-mapping>
I tried various combinations of the filter-mappings but nothing helped.
The output of the console in Eclipse hints that multiple consecutive requests are done. Each gets me a TGT, PGTIOU and PGT but after the ST is validated a new validation request is fired. This goes until Mozilla ends the redirect loop.
I also tried specifying service instead of serverName but all remains the same.
Setting the param redirectAfterValidation to false but then I get a MalformedURLException.
Hopefully I didn't forget any information, please help me.
Thanks in advance.

Special Characters in Request Parameter

I am developing services in spring and the services were deployed in JBOSS 7.1.0.
Sample code for request mapping:
#RequestMapping(value=/state, method=RequestMethod.GET)
public ResponseEntity<ListStatesResponseVO> getListOfStates(#RequestParam(required=false) Long id,
#RequestParam(required=false) Long page,
#RequestParam(required=false) Long pagesize);
My problem is when I pass special characters in request parameter, it’s returning me a valid xml response, but as per my understanding it should return “400 BAD REQUEST”.
Sample URI:
http://localhost:8080/location-services/location/api/state?id=$%^$^$#$%^$%
I also added
<property name="org.apache.catalina.connector.URI_ENCODING" value="UTF-8"/>
<property name="org.apache.catalina.connector.USE_BODY_ENCODING_FOR_QUERY_STRING" value="true"/>
Inside JBOSS’s standalone.xml.
And also
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<!-- set forceEncoding to true if you want to override encoding of servlet -->
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
Inside web.xml.
But these doesn’t solved the problem.
Is there any solution available for this.
Thanks in advance.
You should not allow your users to enter the values in the query string themselves. It's a bad practice and is very risky for your web application security. To avoid such attacks and restrict your users from url tampering you should implement HDIV framework in your application.
Once you implement that no one can mess with your urls. And if someone tries to do so then "bad request" errors will be shown to them.
Hope this helps you. Cheers.

Resources