Skip to main content

Jesey writing an authentication filter

It seems there are two ways to add authentication to Jersey REST apis

1) You can add a servlet filter.
public class RestAuthenticationFilter implements Filter {
    @Override
    public void destroy() {
        // TODO Auto-generated method stub        
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {     
    try {
           User user = BasicAuthHelper.authenticateUser(request);
            if (user == null) {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            } else {
                request.setAttribute("user", user);
                chain.doFilter(request, response);
            }
     } catch (ApplicationException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
     }
    }
    @Override
    public void init(FilterConfig config) throws ServletException {
    } 
} 


2) You can do it using the jersey filter. You have to implement a ResourceFilterFactory and handle the auth in ContainerRequestFilter. The detailed code is below.  I like the approach 1 as it give complete lifecycle control. However if you need more specifc things like accessing QueryParams or PathParams then approach 2 is the way to go


public class RestAuthFilterFactory implements ResourceFilterFactory {
    private static final AppLogger logger = AppLogger
            .getLogger(RestAuthFilterFactory.class);

    @Context
    private UriInfo uriInfo;

    @Override
    public List create(AbstractMethod method) {
        return Collections.singletonList((ResourceFilter) new Filter());
    }

    private class Filter implements ResourceFilter, ContainerRequestFilter {
        protected Filter() {
        }

        public ContainerRequestFilter getRequestFilter() {
            return this;
        }

        public ContainerResponseFilter getResponseFilter() {
            return null;
        }

        public ContainerRequest filter(ContainerRequest request) {
            logger.info("Url invoked is {}", uriInfo.getPath());
            String authHeader = request.getHeaderValue("Authorization");
            if (authHeader != null && authHeader.startsWith("Basic ")) {
                   User user = BasicAuthHelper.authenticateUser(request);
               if (user == null) {
                  throw new WebApplicationException(Response.Status.UNAUTHORIZED);
               }
            return request;
            }
              throw new WebApplicationException(Response.Status.UNAUTHORIZED);
        }
        }
}

Comments

  1. Thank you, your article save me :)

    ReplyDelete
  2. Do you have a complete code example of your approach which you can publish?

    ReplyDelete
    Replies
    1. John unfortunately the code has some internal details of the company I work for and I cant publish those. I would be though happy to answer any spefic questions you have.

      Delete
    2. Hi. How do you get session from ContainerRequest

      Delete
    3. You have to inject the httpServletRequest in your authfilterfactory and then get session from it.

      @Context
      private HttpServletRequest httpServletRequest;

      Delete
  3. Thanks for posting this article.It really saved my day. Also I have found this article here describe the usage of jersey resource filter .

    http://goo.gl/Pm7ls

    ReplyDelete
  4. what library need to be imported for BasicAuthHelper?

    ReplyDelete
  5. BasicAuthHelper is just a class written by me, the intent of the code was to just demonstrate the strucuture of writing a filter. Instead of BasicAuthHelper you can plug in your own class to authenticate the user.

    ReplyDelete
  6. Hi, thank you very much for sample code. May i question, why are you using new instance of Filter for each resource method? Are there some thread-safe issues here? Thank you very much in advance

    ReplyDelete
    Replies
    1. in this e.g. you could get away by reusing same filter but what if someone tomorrow comes and adds instance variables in the class then in that case there can be concurrency issues. so like ServletFilter even here I am creating a new instance.

      Delete
    2. Thank you very much for your response. Sorry for being so precise, but as far as i know there is only one instance of ServletFilter in JVM loaded (it's according to Servlet 2.4 Spec 6.2.1 https://jira.sakaiproject.org/secure/attachment/16135/servlet-2_4-fr-spec.pdf)
      therefore perhaps there is a request scope variable in jersey that contains invoked abstact method information. Once again thank you for your help

      Delete
    3. you dont really need to create a new instance for e.g. this url here the author is not create a new instance http://anismiles.wordpress.com/2012/03/02/securing-versioning-and-auditing-rest-jax-rs-jersey-apis/ of SecurityContextFilter in the factory. But I guess I had to use uriInfo that I was injecting in the factory and thats why I might have done it. I could have injected that in the filter also but not sure if its doable, will have to try it out.

      Delete

Post a Comment

Popular posts from this blog

RabbitMQ java clients for beginners

Here is a sample of a consumer and producer example for RabbitMQ. The steps are
Download ErlangDownload Rabbit MQ ServerDownload Rabbit MQ Java client jarsCompile and run the below two class and you are done.
This sample create a Durable Exchange, Queue and a Message. You will have to start the consumer first before you start the for the first time.

For more information on AMQP, Exchanges, Queues, read this excellent tutorial
http://blogs.digitar.com/jjww/2009/01/rabbits-and-warrens/

+++++++++++++++++RabbitMQProducer.java+++++++++++++++++++++++++++
import com.rabbitmq.client.Connection; import com.rabbitmq.client.Channel; import com.rabbitmq.client.*; public class RabbitMQProducer { public static void main(String []args) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setUsername("guest"); factory.setPassword("guest"); factory.setVirtualHost("/"); factory.setHost("127.0.0.1"); factory.setPort(5672); Conne…

What a rocky start to labor day weekend

Woke up by earthquake at 7:00 AM in morning and then couldn't get to sleep. I took a bath, made my tea and started checking emails and saw that after last night deployment three storage node out of 100s of nodes were running into Full GC. What was special about the 3 nodes was that each one was in a different Data centre but it was named same app02.  This got me curious I asked the node to be taken out of rotation and take a heap dump.  Yesterday night a new release has happened and I had upgraded spymemcached library version as new relic now natively supports instrumentation on it so it was a suspect. And the hunch was a bullseye, the heap dump clearly showed it taking 1.3G and full GCs were taking 6 sec but not claiming anything.



I have a quartz job in each jvm that takes a thread dump every 5 minutes and saves last 300 of them, checking few of them quickly showed a common thread among all 3 data centres. It seems there was a long running job that was trying to replicate pending…

Logging to Graphite monitoring tool from java

We use Graphite as a tool for monitoring some stats and watch trends. A requirement is to monitor impact of new releases as build is deployed to app nodes to see if things like
1) Has the memcache usage increased.
2) Has the no of Java exceptions went up.
3) Is the app using more tomcat threads.
Here is a screenshot

We changed the installer to log a deploy event when a new build is deployed. I wrote a simple spring bean to log graphite events using java. Logging to graphite is easy, all you need to do is open a socket and send lines of events.
import org.slf4j.Logger;import org.slf4j.LoggerFactory; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.Socket; import java.util.HashMap; import java.util.Map; public class GraphiteLogger { private static final Logger logger = LoggerFactory.getLogger(GraphiteLogger.class); private String graphiteHost; private int graphitePort; public String getGraphiteHost() { return graphiteHost; } public void setGraphite…