I don't know the lifecycle of the doFilter() method in a java filter.
I am wondering if I were to set a start time in the request at the beginning of the method, is there a way or place to set a stop time in the method that would give me the total elapsed time from the beginning of the request to the time the response is given?
I've seen a doFilter() method with a finally block in it, and I was wondering if setting a stop time in the response in there would be appropriate?
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class ResponseTimerFilter implements Filter {
protected FilterConfig config;
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
long elapsed = System.currentTimeMillis() - startTime;
String name = "servlet";
if (request instanceof HttpServletRequest) {
name = ((HttpServletRequest) request).getRequestURI();
}
config.getServletContext().log(name + " took " + elapsed + " ms");
}
}
web.xml
<filter>
<filter-name>Timing Filter</filter-name>
<filter-class>com.omh.filters.ResponseTimerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Timing Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Related
I am trying to systematically address HTTP response splitting. I have developed a wrapper class for HttpServletResponse called HardenedHttpServletResponse that mitigates splitting attempts.
Regrettably, I cannot get Jersey to call my resource method with my HardenedHttpServletResponse. I get nulls when I try.
Here is a contrived JAX-RS resource with a HTTP response splitting vulnerability which is exploitable by putting percent-encoded CRLFs (%0d%0a) in the filename query parameter:
AttachmentResource.java:
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
#Path("/attachment")
#Produces(MediaType.APPLICATION_JSON)
public final class AttachmentResource {
#GET
#Path("/file")
public StreamingOutput getAttachment(
#Context HttpServletResponse response,
#QueryParam("filename") String filename
) throws Exception {
response.setHeader(
"content-disposition",
"attachment; filename=" + filename
);
return new DummyStreamingOutput();
}
}
Here is a dummy implementation of StreamingOutput to make it a somewhat full example:
DummyStreamingOutput.java:
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
private static DummyFileStreamingOutput implements StreamingOutput {
#Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
String message = "Hello, World!";
byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
outputStream.write(bytes);
outputStream.flush();
outputStream.close();
}
}
Here is the HttpServletResponse wrapper class that mitigates HTTP response splitting by throwing an exception if it detects CR or LF characters in header names or values:
HardenedHttpServletResponse.java:
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.ws.rs.core.Context;
final class HardenedHttpServletResponse extends HttpServletResponseWrapper {
#Inject
HardenedHttpServletResponse(#Context HttpServletResponse response) {
super(response);
}
#Override
public void setHeader(String name, String value) {
mitigateResponseSplitting(name);
mitigateResponseSplitting(value);
super.setHeader(name, value);
}
#Override
public void addHeader(String name, String value) {
mitigateResponseSplitting(name);
mitigateResponseSplitting(value);
super.setHeader(name, value);
}
#Override
public void setIntHeader(String name, int value) {
mitigateResponseSplitting(name);
super.setIntHeader(name, value);
}
#Override
public void setDateHeader(String name, long date) {
mitigateResponseSplitting(name);
super.setDateHeader(name, date);
}
private void mitigateResponseSplitting(String value) {
if (value != null && (value.contains("\r") || value.contains("\n"))) {
throw new HttpResponseSplittingException();
}
}
}
Jersey supplies the actual response object if the response parameter has type #Context HttpServletResponse, but null if the response parameter has type #Context HardenedHttpServletResponse.
How do I get Jersey to call a resource method with an HttpServletResponse wrapper?
You can just make it injectable by adding it the DI system.
resourceConfig.register(new AbstractBinder() {
#Override
public void configure() {
bindAsContract(HardenedHttpServletResponse.class)
.proxy(false)
.proxyForSameScope(false)
.in(RequestScoped.class);
}
});
You will need to make the class public and also its constructor public, so that the DI system can create it. This will allow you to inject HardenedHttpServletResponse
See also:
Dependency injection with Jersey 2.0
I am having trouble getting a very basic implementation of a singleton class off the ground with Jersey 2 (2.7) and only Jersey's built-in HK2 dependency injection. I am running this on Tomcat.
My goal is to create a singleton instance of a support class that will be used by various web service methods. I don't have a strong preference between constructor injection, method injection, and annotating a class member (as I do below).
Here is my to-be-singleton class:
package singletest;
import javax.inject.Singleton;
#Singleton
public class JustOne {
private int secretNumber = 0;
public void hitMe(int input) {
secretNumber += input;
}
#Override
public String toString() {
return String.format("{ \"secretNumber\": %s }", secretNumber);
}
}
Here is my application class:
package singletest;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
#ApplicationPath("/*")
public class MainApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(TestResource.class);
return classes;
}
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
singletons.add(new JustOneProvider());
return singletons;
}
}
Here is my Provider/ContextResolver class:
package singletest;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
#Provider
public class JustOneProvider implements ContextResolver<JustOne> {
private static JustOne justOne = new JustOne();
#Override
public JustOne getContext(Class<?> type) {
return justOne;
}
}
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>singletest.MainApplication</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>singletest.MainApplication</param-value>
</init-param>
<!-- pass to next filter if Jersey/App returns 404 -->
<init-param>
<param-name>jersey.config.servlet.filter.forwardOn404</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>singletest.MainApplication</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
The resource where I intend to inject the singleton instance of my JustOne class:
package singletest;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#Path("/test")
public class TestResource {
#Inject
private JustOne justOne;
#GET
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_JSON)
#Path("/func1/{input}")
public Response func1(#PathParam("input") int input) {
justOne.hitMe(input);
String responseData = justOne.toString();
return Response.ok(responseData).build();
}
}
This warning is raised when the war is deployed/initialized in Jersey:
Apr 28, 2014 11:48:25 AM org.glassfish.jersey.server.ApplicationHandler initialize
INFO: Initiating Jersey application, version Jersey: 2.7 ${buildNumber}...
Apr 28, 2014 11:48:25 AM org.glassfish.jersey.internal.inject.Providers checkProviderRuntime
WARNING: A provider java.lang.Class registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider java.lang.Class will be ignored.
And the error I get when I call this web service:
type Exception report
message A MultiException has 3 exceptions. They are:
description The server encountered an internal error that prevented it from fulfilling this request.
exception
javax.servlet.ServletException: A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=JustOne,parent=TestResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,58952407)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of singletest.TestResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on singletest.TestResource
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:333)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
So, I get it: hk2 isn't getting enough information to create/bind a JustOne instance and/or find/use my JustOneProvider. I'm sure I'm missing something basic. Any guidance would be appreciated.
bind(JustOne.class).to(JustOne.class).in(Singleton.class);
is the most important part. Without "in(Singleton.class)" multiple instances of JustOne will be created.
Okay, after spending a very healthy chunk of time on this, I got it working.
I used an HK2 AbstractBinder and JAX-RS Feature (javax.ws.rs.core.Feature).
It turned out that no Provider/ContextResolver was required.
Application:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
#ApplicationPath("/*")
public class MainApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(TestResource.class);
classes.add(JustOneFeature.class);
return classes;
}
}
To-be-singleton class:
public class JustOne {
private int secretNumber = 0;
public int getSecretNumber() {
return secretNumber;
}
public void bumpSecretNumber() {
secretNumber += 1;
}
}
Binder:
import org.glassfish.hk2.utilities.binding.AbstractBinder;
public class JustOneBinder extends AbstractBinder {
#Override
protected void configure() {
bind(new JustOne()).to(JustOne.class);
}
}
Feature:
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
public class JustOneFeature implements Feature {
#Override
public boolean configure(final FeatureContext context) {
context.register(new JustOneBinder());
return true;
}
}
Resource that gets singleton injected:
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#Path("/test")
public class TestResource {
#Inject
private JustOne justOne;
#GET
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_JSON)
#Path("/func1/{input}")
public Response func1(#PathParam("input") int input) {
justOne.bumpSecretNumber();
String responseData = String.format("{ \"result\": %s }", input + justOne.getSecretNumber());
return Response.ok(responseData).build();
}
}
This question already has answers here:
i18n with UTF-8 encoded properties files in JSF 2.0 application
(3 answers)
Closed 7 years ago.
In my Application I made it to have it in two languages. English and French.
In English, its all right. But while Reading the Properties file for French Language it ends up showing mojibake.
I have in my properties file like this:
example.french.char=é
but it does not show properly in the application. I am viewing my app in Windows. I dont want to replace the French characters by Unicode characters. I want them to be read from properties file as they normally appear.
How can I make it work?
Please suggest. Can I make it happen to view the French Characters without using Unicodes?
My properties file is encoded in UTF-8.
Please suggest!
I tried the following too..
public class CharacterEncodingFilter implements Filter{
private FilterConfig config;
#Override
public void destroy() {
setConfig(null);
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filter) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=UTF-8");
filter.doFilter(request, response);
}
#Override
public void init(FilterConfig config) throws ServletException {
setConfig(config);
}
public FilterConfig getConfig() {
return config;
}
public void setConfig(FilterConfig config) {
this.config = config;
}
}
and added this in web.xml
<filter>
<filter-name>charEncoding_Filter</filter-name>
<filter-class>com.edfx.tum.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>charEncoding_Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
but still it shows mojibake.
Did you try to set request/response encoding type to UTF-8, with servlet filter class.
Here is an example:
import java.io.IOException;
import java.io.Serializable;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class SetCharacterEncodingFilter implements Filter, Serializable {
private static final long serialVersionUID = -4518853484989127891L;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
Then you register the filter in web.xml
<filter>
<filter-name>UTF8Charset</filter-name>
<filter-class>your.package.name.SetCharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UTF8CharSet</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
If your properties file is in UTF-8 you may have an issue as it should be in ISO-8859-1 in the load(InputStream). You will have to load your properties using the load(Reader) where you specify the encoding when constructing the reader.
I have a CustomOpenIDAuthenticationFilter extends org.springframework.security.openid.OpenIDAuthenticationFilter. I want to define the response url after the authentication is successful, but do not know how to do it. Any help you might have would be very much appreciated.
I have the following code at the moment:
public class CustomOpenIDAuthenticationFilter extends OpenIDAuthenticationFilter{
protected static Logger logger = Logger.getLogger("service");
public CustomOpenIDAuthenticationFilter(){
super();
ProxyProperties proxyProps = new ProxyProperties();
proxyProps.setProxyHostName(PROXYNAME);
proxyProps.setProxyPort(PROXYPORT);
HttpClientFactory.setProxyProperties(proxyProps);
}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException {
//i think the response url should be defined here.
Authentication au = super.attemptAuthentication(request, response);
return au;
}
}
Edit
Sorry for your time, i did not explain my problem correctly.
So, when my login page is sending authentication request to openid provider, the request contains a returnToUrl, where is "The URL on the Consumer site where the OpenID Provider will return the user after generating the authentication response. ". On a non-spring application, i would do
AuthRequest authRequest = manager.authenticate(discovered, returnToUrl);
My question is how could I specify this returnToUrl at my CustomOpenIDAuthenticationFilter.
To specify the returnToUrl you can override the String buildReturnToUrl(HttpServletRequest request) method. An example of making this an arbitrary URL is given below:
public class CustomOpenIDAuthenticationFilter extends OpenIDAuthenticationFilter {
...
protected String buildReturnToUrl(HttpServletRequest request) {
// this URL needs to be processed by CustomOpenIDAuthenticationFilter to validate
// the OpenID response and authenticate the user
return "https://example.com";
}
}
As the comment mentions this URL should be a URL that CustomOpenIDAuthenticationFilter will process since it is what validates the OpenID response.
This can also be achieved by creating a custom filter an place it before OPENID_FILTER
</http>
...
<custom-filter before="OPENID_FILTER" ref="myBeforeOpenIDFilter" />
</http>
<beans:bean id="myBeforeOpenIDFilter"class="com.example.provider.openid.MyBeforeOpenIdFilter" />
And below there is my implementation of this custom filter
package com.example.provider.openid;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyBeforeOpenIdFilter implements Filter{
static Logger logger = LoggerFactory.getLogger(MyBeforeOpenIdFilter.class);
static class FilteredRequest extends HttpServletRequestWrapper {
public FilteredRequest(HttpServletRequest request) {
super(request);
}
#Override
public java.lang.StringBuffer getRequestURL(){
String baseUrl = (String) super.getSession().getServletContext().getAttribute("applicationBaseUrl");
StringBuffer sb = super.getRequestURL();
int index = sb.indexOf("/j_spring_openid_security_check");
if(index != -1){
// here replace the host etc with proper value
if(baseUrl.endsWith("/")){
baseUrl = baseUrl.substring(0, baseUrl.length()-1);
}
logger.debug("Changing the getRequestURL to inject the correct host so openid login could work behind proxy");
logger.debug("Original getRequestURL: "+sb.toString());
logger.debug("Replacing the baseUrl with: "+baseUrl);
sb.replace(0, index, baseUrl);
logger.debug("New getRequestURL: "+sb.toString());
}
return sb;
}
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
//No need to init
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new FilteredRequest((HttpServletRequest) request), response);
}
#Override
public void destroy() {
//No need to destroy
}
}
In this way you can define your openid provider using the default namespace
and have the filter plugin out if you need it. In my implementation I'm taking the baseUrl from the servlet context but it can be simply hardcoded
Hope this will help someone
Cheers
Szymon
Very strange error I have, I am getting request as null when I try to access it. I always used the same method to get it, but now I am having this error.
My Action look like this:
package com.deveto.struts.actions;
import com.deveto.hibernate.mappings.Slider;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.util.ServletContextAware;
/**
*
* #author denis
*/
public class ContentAction extends ActionSupport implements ServletContextAware {
HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);
HttpServletResponse response = (HttpServletResponse) ActionContext.getContext().get(ServletActionContext.HTTP_RESPONSE);
ActionContext ac = ActionContext.getContext();
ServletContext sc = (ServletContext) ac.get(ServletActionContext.SERVLET_CONTEXT);
#Override
public String execute() throws Exception {
System.out.println("request: " + request);
return SUCCESS;
}
public ActionContext getAc() {
return ac;
}
public void setAc(ActionContext ac) {
this.ac = ac;
}
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletResponse getResponse() {
return response;
}
public void setResponse(HttpServletResponse response) {
this.response = response;
}
public ServletContext getSc() {
return sc;
}
public void setSc(ServletContext sc) {
this.sc = sc;
}
public void setServletContext(ServletContext sc) {
this.sc = sc;
}
}
And now I can't do nothing, the request is always null
request: null
Implement the ServletRequestAware Interface and set your request variable there instead of doing that during construction.
But normally you don't need access to the request as the params interceptor of struts does all the work the request object is needed for.
From the documentation of the ServletRequestAware-Interface:
All Actions that want to have access to the servlet request object must implement this interface.
This interface is only relevant if the Action is used in a servlet environment.
Note that using this interface makes the Action tied to a servlet environment, so it should be avoided if possible since things like unit testing will become more difficult.