jersey icon indicating copy to clipboard operation
jersey copied to clipboard

Injecting HttpServletRequest into ContainerRequestFilter causes exception

Open jerseyrobot opened this issue 9 years ago • 14 comments

I have the following JAX-RS Filter which implements the ContainerRequestFilter:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    @Context
    HttpServletRequest request;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

      // ...
    }
}

Upon trying to run the Jetty server where the Servlet is deployed, I receive the following MultiException:

... Caused by: A MultiException has 4 exceptions. They are: 1. java.lang.IllegalArgumentException: interface org.glassfish.hk2.api.ProxyCtl is not visible from class loader 2. java.lang.IllegalArgumentException: While attempting to create a Proxy for javax.servlet.http.HttpServletRequest in scope org.glassfish.jersey.process.internal.RequestScoped an error occured while creating the proxy 3. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of resteasy.AuthenticationFilter errors were found 4. java.lang.IllegalStateException: Unable to perform operation: resolve on resteasy.AuthenticationFilter

As far as I have been able to tell, this used to be a bug in Jersey <2.4, which should have been fixed. However, every newer Jersey version I have tried has yielded the same result, and I cannot implement a token-based authentication method as a result (i.e. no request.login() ).

Additional details:

pom.xml entry:

<dependency>
  <groupId>org.glassfish.jersey.containers<groupId>
  <artifactId>jersey-container-servlet</artifactId>
  <version>2.23.1</version>
</dependency>

Server start up and deployment:

public class JettyServer {

        public static void main(String[] args) throws Exception {

WebAppContext webapp = new WebAppContext();
webapp.setDescriptor("./src/webapp/WEB-INF/web.xml");
webapp.setWar("/tmp/resteasy.war");
webapp.setSessionHandler(new SessionHandler());
Server server = new Server(20080);

HashLoginService loginService = new HashLoginService("DefaultRealm");
loginService.setConfig("./src/webapp/default-realm.txt");

server.addBean(loginService);

server.setHandler(webapp);

ServletHolder jerseyServlet = webapp.addServlet(ServletContainer.class, "/v1/*");
jerseyServlet.setInitOrder(0);

Map<String, String> params = new HashMap<String, String>();
params.put("jersey.config.server.provider.packages", "resteasy");
jerseyServlet.setInitParameters(params);

try {
        server.start();
        server.join();
}
catch (Exception e) {
        e.printStackTrace();
}
finally {
        server.destroy();
}

        }
}

Environment

JAX-RS 3.0.18.Final Jersey Servlet Container 2.23.1 Jetty 9.3.11.v20160721 JDK 8 Debian 8.5 Jessie

Affected Versions

[2.23.1]

jerseyrobot avatar Aug 03 '16 15:08 jerseyrobot

  • Issue Imported From: https://github.com/jersey/jersey/issues/3422
  • Original Issue Raised By:@glassfishrobot
  • Original Issue Assigned To: @mpotociar

jerseyrobot avatar Apr 20 '18 08:04 jerseyrobot

@glassfishrobot Commented Reported by fpanovski

jerseyrobot avatar Aug 03 '16 15:08 jerseyrobot

@glassfishrobot Commented fpanovski said: Update: I found a very similar situation outlined in a SO question and answer here: http://stackoverflow.com/questions/29974887/jersey-containerrequestfilter-does-not-get-context-servletrequest

However, delegating the injection to a Provider implementing DynamicFeature, registering the Filter to featureContext, and passing the request to the AuthenticationFilter still yields the exact same exception.

jerseyrobot avatar Aug 03 '16 16:08 jerseyrobot

@glassfishrobot Commented @pavelbucek said: What do you mean by "JAX-RS 3.0.18.Final"? Aren't you by any chance using RESTEasy?

jerseyrobot avatar Aug 03 '16 17:08 jerseyrobot

@glassfishrobot Commented fpanovski said: Hello Pavel,

Thanks for the response and for fixing the tags. Yes, I am in fact using RESTEasy together with Swagger (with my server resource stubs having been generated using Swagger Codegen for JAX-RS/RESTEasy). If it is of any help, here is my full pom.xml (I am using the latest non-milestone versions of every dependency, as far as I know):

<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>
  <groupId>resteasy</groupId>
  <artifactId>resteasy</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>

    <properties>
      <jersey.version>2.23.1</jersey.version>
      <jetty.version>9.3.11.v20160721</jetty.version>
    </properties>

  <dependencies>

    <dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>jaxrs-api</artifactId>
      <version>3.0.12.Final</version>
    </dependency>
        <!-- RESTEasy Servlet Initializer -->
    <dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-servlet-initializer</artifactId>
      <version>3.0.18.Final</version>
    </dependency>

    <!-- Jersey Servlet Container -->
    <dependency>
      <groupId>org.glassfish.jersey.containers</groupId>
      <artifactId>jersey-container-servlet</artifactId>
      <version>${jersey.version}</version>
    </dependency>

    <!-- Swagger -->
    <dependency>
      <groupId>com.wordnik</groupId>
      <artifactId>swagger-jaxrs_2.10</artifactId>
      <version>1.3.13</version>
    </dependency>
    <!-- Swagger core -->
    <dependency>
      <groupId>io.swagger</groupId>
      <artifactId>swagger-jaxrs</artifactId>
      <version>1.5.9</version>
    </dependency>

        <!-- Jetty Server core -->
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-server</artifactId>
      <version>${jetty.version}</version>
    </dependency>

    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-servlet</artifactId>
      <version>${jetty.version}</version>
    </dependency>
    <!-- Jetty Web app plugin-->
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-webapp</artifactId>
      <version>${jetty.version}</version>
    </dependency>
    <!-- Jetty JMX -->
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-jmx</artifactId>
      <version>${jetty.version}</version>
    </dependency>

    <!-- Logging  -->
        <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.21</version>
    </dependency>

    <!-- Google Gson -->
        <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.7</version>
      <scope>compile</scope>
    </dependency>

    <!-- memcached client -->
        <dependency>
      <groupId>com.whalin</groupId>
      <artifactId>Memcached-Java-Client</artifactId>
      <version>3.0.2</version>
    </dependency>

    <!-- genson JSON converter -->
        <dependency>
      <groupId>com.owlike</groupId>
      <artifactId>genson</artifactId>
      <version>1.4</version>
    </dependency>

        <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.0</version>
    </dependency>

  </dependencies>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.3</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <warSourceDirectory>WebContent</warSourceDirectory>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <modules>
        <module>?</module>
  </modules>
</project>

jerseyrobot avatar Aug 03 '16 17:08 jerseyrobot

@glassfishrobot Commented fpanovski said: Update: In case anyone is following this report and looking for a solution as well, I have found a workaround in the meantime that accomplishes the exact same thing that I wanted to do by injecting the HttpServletRequest. It works by implementing the javax.servlet.Filter interface:

public class AuthenticationFilter implements Filter {

    public void init(...) {...}
    public void destroy(...) {...}

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        // Get request and response objects, we will need to pass them down the filter chain later on
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        if(!request.getRequestURI().equals("/auth")) {
// Check Authorization header and return a 401 if invalid
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);

try {
        if(authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
response.setStatus(401);
return;
            }
// Get username, either from custom header or elsewhere... 
validateToken(username, authToken);

request.login(username, password);
chain.doFilter(req, res);

        } catch (Exception e) {
response.setStatus(401);
return;
        }
        }

        chain.doFilter(req, res);

    }
}

The filter also needs to be declared in web.xml, but there are already many examples for that. I hope this helps others in the meantime until there is a solution for the original issue.

jerseyrobot avatar Aug 04 '16 14:08 jerseyrobot

@glassfishrobot Commented This issue was imported from java.net JIRA JERSEY-3150

jerseyrobot avatar Apr 25 '17 05:04 jerseyrobot

@visadb Commented This is causing some trouble for me, I hope this gets fixed soon.

jerseyrobot avatar Jul 25 '17 11:07 jerseyrobot

@mrerhuo Commented This is causing some trouble for me, I hope this gets fixed soon.

jerseyrobot avatar Jan 09 '18 08:01 jerseyrobot

@mrerhuo Commented @glassfishrobot http://www.cnblogs.com/mrer/p/8267266.html

jerseyrobot avatar Jan 11 '18 02:01 jerseyrobot

I am getting the same exception while trying to override Jersey libraries in WebLogic 12c. Any updates on the fix for this issue?

rvkamath avatar May 29 '19 14:05 rvkamath

This sounds like a classloading issue. When HK2 creates a proxy to an interface that is to be injected, such as HttpServletRequest in this case, it uses JDK Proxy#newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h), and it adds HK2 ProxyCtl interface to the list of interfaces. For the classloader, the classloader from the interface (HttpServletRequest in this case) is being used, and Proxy calls the following:

interfaceClass = Class.forName(intf.getName(), false, loader);
if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }

but if the injected interface (HttpServletRequest) is loaded by a different classloader then ProxyCtl class, the Class.forName uses the classloader from the interface, a new ProxyCtl class is loaded and the IAE is being thrown.

This can happen for instance when the WAR application contains Jersey, HK2, (perhaps the servlet api, too) in the WEB-INF/lib, all the app is loaded by an app classloader, but javax.servlet.http.HttpServletRequest is not defined to be used by the same classloader. While it looks like an issue with ProxyCtl, it actually is the HttpServletRequest that uses a different classloader than the rest of the application.

jansupol avatar May 30 '19 09:05 jansupol

@jansupol Thanks for clarifying. I have the exact same situation as you describe with jersey/hk2 in the webapp. I ran into the issue after upgrading from jersey 2.14 to 2.29.1 Is there any fix for this issue?

sweco-dkjesh avatar Apr 29 '20 23:04 sweco-dkjesh

Anybody managed to resolve this issue?

itavramov avatar Mar 19 '25 17:03 itavramov