how to implement custom http session in java? - java

I will need to implement my own version of HttpSession in Java. I have found very little information which explains how achieve such a feat.
I guess my problem is - how do I override the existing HttpSession no matter the application server's implementation?
I did run across a quality but rather old read which helps me achieve my goal - http://java.sun.com/developer/technicalArticles/Servlets/ServletControl/
Are there any other approaches?

Its two ways.
"Wrapping" the original HttpSession in your own HttpServletRequestWrapper implementation.
I made this a short time ago for clustering distributed sessions with Hazelcast and Spring Session.
Here is explained pretty well.
First, implement your own HttpServletRequestWrapper
public class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {
public SessionRepositoryRequestWrapper(HttpServletRequest original) {
super(original);
}
public HttpSession getSession() {
return getSession(true);
}
public HttpSession getSession(boolean createNew) {
// create an HttpSession implementation from Spring Session
}
// ... other methods delegate to the original HttpServletRequest ...
}
After, from your own Filter, wraps the original HttpSession, and put it inside the FilterChain provided by your Servlet Container.
public class SessionRepositoryFilter implements Filter {
public doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
SessionRepositoryRequestWrapper customRequest =
new SessionRepositoryRequestWrapper(httpRequest);
chain.doFilter(customRequest, response, chain);
}
// ...
}
Finally, set your Filter at the beginning in the web.xml to ensure it performs before any other.
The second manner to achieve it is providing to your Servlet Container your custom SessionManager.
For example, in Tomcat 7.

Create a new class, and implement HttpSession:
public class MyHttpSession implements javax.servlet.http.HttpSession {
// and implement all the methods
}
Disclaimer: I have not tested this myself:
Then write a filter with a url-pattern of /* and extend HttpServletRequestWrapper. Your wrapper should return your custom HttpSession class in getSession(boolean).
In the filter, use your own HttpServletRequestWrapper.

It doesn't seem like it's easily doable in a portable fashion that would work among different containers, since the HttpSession implementation is provided by the J2EE container.
However, to achieve a similar result, you can implement a javax.servlet.Filter and javax.servlet.HttpSessionListener and in your filter, wrap the ServletRequest and ServletResponse, such as described in Spring Boot with Hazelcast and Tomcat.

Related

Is ServletRequest::setAttribute safe in terms of web service security?

Short Version
Is javax.servlet.ServletRequest's method setAttribute(<key>, <Object>) only used as a means of passing objects between methods in Java code?
Long version
Let's say I have a javax.servlet.Filter implementation to handle all logged in users' authentication using cookies:
in Spring Boot
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class AuthFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
Cookie[] cookies = null;
if (request instanceof HttpServletRequest) {
cookies = ((HttpServletRequest) request).getCookies();
}
Optional<User> user = mySessionAuthMethod(cookies);
if (user.isPresent()) {
request.setAttribute("user", user.get());
}
chain.doFilter(request, response);
}
}
Then later, I can avoid manual authentication in all of the Web API methods, and just check the user attribute. Example of a #RestController's method:
#RequestMapping(value = "/profile")
#CrossOrigin(origins = {MyProperties.ORIGIN}, allowCredentials = "true")
public ResponseEntity getProfile(HttpServletRequest request, HttpServletResponse response) {
String user = request.getAttribute("user");
if (user != null) {
return myGetProfileResponse(user);
}
return myNotLoggedInResponse();
}
My questions are:
Is this form of authentication secure? What I mean is, are the attributes in the ServletRequest only added and used in Java for communication between methods, or could they be added to the request already before reaching the server?
Is this way of authentication using Filters a good practice to avoid duplicate code?
Additional Explanation
The real reason of doing this is not only authentication. I have also Filters which need to process each and every request and pass objects to the Controllers. What I definitely want is that none of these objects and information can be forged even by a person who knows the implementation of the system.
I think I have found the answer from the documentation of getAttribute
Attributes can be set two ways. The servlet container may set attributes to make available custom information about a request. For example, for requests made using HTTPS, the attribute javax.servlet.request.X509Certificate can be used to retrieve information on the certificate of the client. Attributes can also be set programatically using ServletRequest#setAttribute. This allows information to be embedded into a request before a RequestDispatcher call.
So according to this (if there is no missing information), it should be completely safe to pass custom objects and know that they were always created by the server.

Understanding request object in servlet-api. Is it a singleton?

I read the servlet-3.0 specification and have got one question about the ServletRequest object. Currenctly I have a filter chain
public class MyFilter implements Filter{
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
//do filter
}
}
after doing filters the javax.servlet.Servlet's
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
comes into play. Is it reliable that both in the filter's method and the service method operate on the same object reference? The servlet specification said this:
Each request object is valid only within the scope of a servlet’s
service method, or within the scope of a filter ’s doFilter
method, unless the asynchronous processing is enabled for the
component and the startA sync method is invoked on the request object
But it;s not obvious to me that the ServletRequest object is a singleton per one request handling.
Upd: To be more specific, I need to return the HttpSession instance within Filter's doFilter method and Servlet's do_HttpMethod_ method. Is it always the same? I mean httpServletRequest.getSession()
A container uses a single request object for a given request. However any filter can wrapper the request object so your filter or servlet may be getting a wrapper depending on what other filters do. Usually as an app developer you would know if this is the case. If no wrappers are used the filter and servlets get the same request object.
For info on request wrappers see:
http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequestWrapper.html
So when you call getSession() you may get the container implementation of the method or that provided by a wrapper. However note that an HttpServletRequestWrapper object provides a getRequest() method which returns the request object it wraps so you can recurse through wrappers until you get the original and then call it. Lots of examples how to do this on the web.
ServletRequest is an interface and the same is used in doFilter method as well as service method. So both are going to return the same session object (if you call getSession()).
Servlet as well as Filter uses same interface so it's going to behave same way. I am not sure why you are curious to know if it's singleton ? May be you can check servlet specification to know more about it.

Spring MVC: default view objects

I use ModelAndView objects as all people do:
ModelAndView result = new ModelAndView("view");
result.addObject("requests", requestsService.getListByBackoffice(filter, page, Config.RECORDS_PER_PAGE));
But I noticed that I have a couple of objects that I use always in most of the views.. So the question is - is there any solutions to create some kind of default assigned objects that are passed to view automatically?
Thank you
You can register a HandlerInterceptor with your DispatcherServlet. You then implement the postHandle() method:
public class CustomInterceptor extends HandlerInterceptorAdapter /* which implements HandlerInterceptor */ {
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
modelAndView.addObject("myObject", new Object());
// add as many as you wish
}
}
NOTE: The ModelAndView object may be null. This may occur if your handler method was writing to the response body directly, for example with #ResponseBody.
Depending on the url pattern you used when registering the Interceptor, the postHandle() will get called and populate your model with any objects you want.
You can also register a servlet Filter (in web.xml or WebApplicationInitializer). The filter simply adds the request attributes before dispatching to the servlet.
public class CustomFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setAttribute("myObject", new Object());
chain.doFilter(request, response);
}
// ... init and destroy methods
}
NOTE: At some point during the request lifecycle, Spring adds all attributes in the model to your request attributes.
The disadvantage here is that you add the attributes whether or not your #Controller worked, as the Filter is called before Spring's DispatcherServlet. Also, the Filter is managed by your servlet container (workarounds exist) and therefore it's difficult to inject Spring beans into it.
first solution:
I have not tried such but can do like creating ModelAndView object in Constructor or somewhere which you call always, set object which you always want to pass as default there only.
call setViewName() in respective methods and add respective objects which you want to set.
second solution:
write one method which is adding that default object and call that method wherever you need (nothing but what interceptor do).

Difference between handleRequestInternal and handleRequest

I have just started spring, I found that somewhere we are using handlerequest() method in controller and somewhere we are using handlerequestinternal() method.
I have tried google-ing this, but did not find any specific point.
Can any one explain what is the difference between these two functions and when we should implement each of them?
As I know spring framework will call by default handlerequest() function, so we can put our service layer there itself.
I am sure handlerequestinternal() must be providing some extra feature, but not sure.
Please help me to understand this.
Both handleRequest and handleRequestInternal are used by the old Spring 2.0 controller framework.
handleRequestInternal is used when you're extending one of the pre-supplied base support classes (e.g. AbstractController, SimpleFormController, etc). These use the Template design pattern, and you supply your business logic in that method.
handleRequest is the method specified on the Controller interface itself. If you directly implement that interface, rather than extending one of the above base classes, then you need to implement handleRequest directly.
Both are obsolete, and not used in controllers written for Spring 2.5 and later.
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.checkAndPrepare(request, response, this instanceof LastModified);
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
return this.handleRequestInternal(request, response);
}
}
}
return this.handleRequestInternal(request, response);
}
protected abstract ModelAndView handleRequestInternal(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
if in controller template classes like AbstractController and ParameterizableViewConterollers in this it will the child classes of Controller interface so spring peoples internally override the handleRequest method and call the abstract handleRequestInternal method so whenever we are using template classes we use this method otherwise we use the handleRequest() method only this the difference i think!.

Logging response body (HTML) from HttpServletResponse using Spring MVC HandlerInterceptorAdapter

I am trying to log (just to console write now for simplicity sake) the final rendered HTML that will be returned by the HttpServletResponse. (i.e. the body) To this end, I am using the HandlerInterceptorAdapter from Spring MVC like so:
public class VxmlResponseInterceptor extends HandlerInterceptorAdapter {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(response.toString());
}
}
This works as expected and I see the HTTP response headers in the console. My question is if there is a relatively simple way to log the entire response body (i.e. final rendered HTML) to the console without having to resort to doing jumping jacks with PrintWriters, OutputStream's and the like.
Thanks in advance.
This would be better done using a Servlet Filter rather than a Spring HandlerInterceptor, for the reason that a Filter is allowed to substitute the request and/or response objects, and you could use this mechanism to substitute the response with a wrapper which logs the response output.
This would involve writing a subclass of HttpServletResponseWrapper, overriding getOutputStream (and possibly also getWriter()). These methods would return OutputStream/PrintWriter implementations that siphon off the response stream into a log, in addition to sending to its original destination. An easy way to do this is using TeeOutputStream from Apache Commons IO, but it's not hard to implement yourself.
Here's an example of the sort of thing you could do, making use of Spring's GenericFilterBean and DelegatingServletResponseStream, as well as TeeOutputStream, to make things easier:
public class ResponseLoggingFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse responseWrapper = loggingResponseWrapper((HttpServletResponse) response);
filterChain.doFilter(request, responseWrapper);
}
private HttpServletResponse loggingResponseWrapper(HttpServletResponse response) {
return new HttpServletResponseWrapper(response) {
#Override
public ServletOutputStream getOutputStream() throws IOException {
return new DelegatingServletOutputStream(
new TeeOutputStream(super.getOutputStream(), loggingOutputStream())
);
}
};
}
private OutputStream loggingOutputStream() {
return System.out;
}
}
This logs everything to STDOUT. If you want to log to a file, it'll get a big more complex, what with making sure the streams get closed and so on, but the principle remains the same.
If you're using (or considering) logback as your logging framework, there is a nice servlet filter already available that does exactly that. Checkout the TeeFilter chapter in the documentation.
I've been looking for a way to log full HTTP Request/Response for a while and discovered it has been solved for me in the Tomcat 7 RequestDumperFilter. It works as advertised from a Tomcat 7 container. If you want to use it in Jetty, the class works fine stand-alone or, as I did, copied and adapted to the specific needs of my environment.
I made a small library spring-mvc-logger available via maven central.
Add to pom.xml:
<dependency>
<groupId>com.github.isrsal</groupId>
<artifactId>spring-mvc-logger</artifactId>
<version>0.2</version>
</dependency>
Add to web.xml:
<filter>
<filter-name>loggingFilter</filter-name>
<filter-class>com.github.isrsal.logging.LoggingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Add to log4j.xml:
<logger name="com.github.isrsal.logging.LoggingFilter">
<level value="DEBUG"/>
</logger>
the code pasted below works with my tests and can be downloaded from my github project, sharing after applying a solution based on that on a production project
#Configuration
public class LoggingFilter extends GenericFilterBean {
/**
* It's important that you actually register your filter this way rather then just annotating it
* as #Component as you need to be able to set for which "DispatcherType"s to enable the filter
* (see point *1*)
*
* #return
*/
#Bean
public FilterRegistrationBean<LoggingFilter> initFilter() {
FilterRegistrationBean<LoggingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new LoggingFilter());
// *1* make sure you sett all dispatcher types if you want the filter to log upon
registrationBean.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
// *2* this should put your filter above any other filter
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
ContentCachingRequestWrapper wreq =
new ContentCachingRequestWrapper(
(HttpServletRequest) request);
ContentCachingResponseWrapper wres =
new ContentCachingResponseWrapper(
(HttpServletResponse) response);
try {
// let it be ...
chain.doFilter(wreq, wres);
// makes sure that the input is read (e.g. in 404 it may not be)
while (wreq.getInputStream().read() >= 0);
System.out.printf("=== REQUEST%n%s%n=== end request%n",
new String(wreq.getContentAsByteArray()));
// Do whatever logging you wish here, in this case I'm writing request
// and response to system out which is probably not what you wish to do
System.out.printf("=== RESPONSE%n%s%n=== end response%n",
new String(wres.getContentAsByteArray()));
// this is specific of the "ContentCachingResponseWrapper" we are relying on,
// make sure you call it after you read the content from the response
wres.copyBodyToResponse();
// One more point, in case of redirect this will be called twice! beware to handle that
// somewhat
} catch (Throwable t) {
// Do whatever logging you whish here, too
// here you should also be logging the error!!!
throw t;
}
}
}

Categories