views:

801

answers:

2

I'm trying to find a simple, flexible way to add JaaS authentication to REST. I found a post that I think leads me in the right direction (See StevenC's answer). It sounds like the servlet container is responsible for security, not the Jersey code itself. I like this idea, but need a little guidance on implementation.

Grizzly is my servlet container and I want to configure it to use JaaS for authentication. For now, a simple username/password combination would be fine, and hard-coding the username/password pairs directly in code is fine. As long as it uses JaaS, we can refine those details later.

As far as what is sent over HTTP, I'm thinking that storing a cookie would be the easiest way to make this all work. Whatever it takes to keep authentication junk away from my Jersey code.

Here's the code to start Grizzly so far:


final String baseUri = "http://localhost:9998/";
final Map initParams = new HashMap();

initParams.put("com.sun.jersey.config.property.packages", 
  "my.jersey.Service");

System.out.println("Starting grizzly...");
SelectorThread threadSelector = GrizzlyWebContainerFactory.create(baseUri, initParams);
System.out.println(String.format(
        "Jersey app started with WADL available at %sapplication.wadl\n"
  + "Try out %shelloworld\nHit enter to stop it...", baseUri, baseUri));                
System.in.read();
threadSelector.stopEndpoint();
System.exit(0);

If this whole process works, what's the best way to check permissions for the user? I would probably want my REST code to actually validate permissions at certain points. Am I even on the right track? Is there an easier way? A link to a tutorial would be a great answer. Even an answer like "I did that and it worked" would give me a warm fuzzy that I'm heading in the right direction.

Thanks for any help.

EDIT: Some clarifications for StevenC's comment:

  • Do you still want to use servlet filters to protect your resources? I'll use whatever can separate out the authentication detail from the Jersey code. It doesn't have to be servlet filters.
  • What is mean by "configure it to use JaaS"? The original plan was to protect the current API using JaaS. The next phase would be to make the entire API available online. It seemed to make sense to have a Jersey wrapper around the API calls, but keep authentication handled by Grizzly. Grizzly would have to interact with JaaS at that point I believe.
  • Are you thinking there should be some config that simply causes grizzly to protect your resources? I was considering a two-step process of authenticating the user and based on roles, authorizing the user to access resources. The idea was to have Grizzly handle authentication (using JaaS) and Jersey handle authorization.
  • "I don't see the need for the usage of cookies with a RESTful resource." It would be wonderful to remove the use of cookies, but how can the be accomplished? The system needs to know if the user is authenticated. I'd rather not ask them to pass a username/password/etc for each call. Even passing a session token as a parameter with every call seems "ugly".

Also, please note that I'm fairly new to REST. I've been doing SOAP for a couple of years, so I may have a "SOAP bias" that may be blinding me from some obvious, simple solution that everyone uses. If there's an easier way, please feel free to share. I'm just trying to learn as much as possible.

A: 

Not sure if you are asking how to secure each resource, but I found a presentation on javapassion that sounds like what you are looking for. He says to use @Context SecurityContext as a parameter.

  @Path("basket")
  // Sub-resource locator could return a different resource if a user
  // is a preferred customer:
  public ShoppingBasketResource get(@Context SecurityContext sc) {
    if (sc.isUserInRole("PreferredCustomer") {
      return new PreferredCustomerShoppingBaskestResource();
    } else {
      return new ShoppingBasketResource();
  }
}
Matthew Sowders
A: 

I'm not entirely clear what is meant by "configure it to use JaaS for authentication". If there's a simple configuration to have grizzly enforce HTTP authentication protecting URLs, I don't know about it.

I'm assuming from the other question and answer you reference that you want to use a servlet filter. Normally that's configured in the web.xml file of a servlet project. Grizzly is of course often used to start up a server from code as opposed to application config. When I used grizzly in this way I noticed that GrizzlyWebContainerFactory didn't offer any versions of create() that allowed you to specify servlet filters. However I did notice ServletAdapter [1] in the same project that does give you that ability.

As for the filter itself, I unfortunately don't know of a pre-built servlet filter that simply plugs JaaS configured login modules into your application, so you'll likely have to write a bit of code there. It's not much though, just choose the HTTP based authentication method (e.g. HTTP BASIC, DIGEST, etc.), extract credentials from the request accordingly, and login using the JaaS framework. I don't see that a cookie would specifically be needed for RESTful resources. The RESTful architectural style frowns upon keeping sessions. There are plenty of tutorials about JaaS otherwise, so I won't elaborate on that here.

Once a JaaS subject is active (consumer successfully logged in) you can simply get the current subject and check the active principals and credentials using the Subject.getSubject method.

Anyway, this answer is specifically to give a bit more of the details around doing auth with servlet filters, as you requested in the other (linked) question. This isn't necessarily the only way to do auth in a jersey webapp, but it's a fairly straightforward way to do it. I like it because it keeps me from injecting repetitive auth code in each resource that needs it.

[1] https://grizzly.dev.java.net/nonav/apidocs/com/sun/grizzly/http/servlet/ServletAdapter.html

StevenC