Decentralized Auth Ideas

7 Comments

Distributed workflow has to be the most complex use case to secure.  In it you could have multiple participants being coordinated both synchronously and asynchronously.  All forwarding and distributing information and data in between each other.  All needing to trust one another.  If you could define a relatively scalable and simple solution for workflow, you’d have something that would work in less complex scenarios.

The hub and spoke model that seems to be popular involves a central identity management provider (IDP) that participants ping to authenticate requests and to receive security information.  The biggest problem I foresee with this approach is that the IDP becomes a central point of failure.  The IDP needs to be available for applications to work.  It needs to be on the same network.  There’s a lot of extra distributed requests that need to be made.

All these problems bring me to thinking about the stateless principle of REST.  RESTful services can have state, but not session state.  The idea is that session state travels with the request.  Could we do something similar with security information?  Sure why not!  How could you trust the integrity of such information?  Digital Signatures.  I’m sure there are protocols out there that have thought of similar ideas, but its cool to think things out for yourself.  If your ideas match a particular existing protocol or specification you know you’re on the right track.  The idea have have works as follows.

Let’s pretend we have a User named Bill that wants to interact with a Travel Agent service that will buy a ticket for him on an airline, reserve an airport taxi, and reserve a hotel room.  So, Bill is interacting with the Travel Agent directly.  The Travel Agent is acting on behalf of Bill when it interacts with the airline, taxi, and hotel services.  The airline, tax, and hotel have to trust both the travel agent and Bill.

Step 1: Bill authenticates with an IDP saying he wants to interact with the Travel Agent.  The IDP returns metadata that specifies both Bill’s and the Travel Agent’s permissions for all the interactions that must take place.  It also returns the public keys for Bill and the Agent.  The IDP digitally signs all this information using its private key.

Step 2:  Bill sends a reservation request to the Travel Agent service.  Bill signs the request including the signed permissions and keys provided by the IDP.  Here’s what the request might look like:

POST /travel
Host: travelagent.com
Content-Type: application/reservation+xml
Authorization: doseta-auth user=bill;h=Visa:Permissions:Public-Keys:Host;verb=POST;path=/travel;bh=...;b=...
Visa: initiator=bill;h=Permissions:Public-Keys;d=idp.com;b=...
Permissions: bill="agent hotel airline taxi"; agent="reserve-hotel reserve-taxi reserve-flight"
Public-Keys: bill=23412341234;agent=3423412341234

<reservation>...</reservation>

Step 3: The Travel Agent authenticates and authorizes Bill’s request.  The Authorization header contains metadata that is signed by Bill.  The metadata signed by bill is the HTTP verb and path of the request (POST and /travel), and the hash of the XML posted by the request, as well as the Visa, Permissions, and Public-Key headers included within the request.  The Travel Agent verifies this signed metadata by finding and using Bill’s public key in the transmitted Public-Keys header.  If the signature passes, then the Travel Agent knows that Bill sent the request.  But….It does not know yet if Bill is a trusted identity.

Step 4: How does the Travel Agent know Bill is a valid person?  How does it know that Bill is allowed to make a reservation?  To answer these questions, the Travel Agent first looks at the transmitted Visa header.  What it boils down to is that the Travel Agent only trusts the IDP.  The Visa header was generated by the IDP and  is a digital signing of the Permissions and Public-Keys header.  The IDP  through the Visa header tells the Agent the permissions involved with the request and who will participate in the overall interaction.   The Agent only needs to know the IDP’s public key prior to the request being initiated.  So, the Agent verifies the digital signed Visa header using the stored public key of the IDP.  A successful verification also means that the Agent can trust that Bill initiated the request.  It can then look at the Permissions header to determine whether or not Bill is allowed to perform the action.

Step 5:  Next the Travel Agent needs to interact with the Airline, Hotel and Taxi services on behalf of Bill.  Here’s what a request to the Airline might look like.

POST /flights/tickets
Host: airline.com
Content-Type: application/ticket-purchase+xml
Authorization: doseta-auth user=agent;h=Visa:Permissions:Public-Keys:Host;verb=POST;path=/flights/tickets;bh=...;b=...
Visa: initiator=bill;h=Permissions:Public-Keys;d=idp.com;b=...
Permissions: bill="agent hotel airline taxi"; agent="reserve-hotel reserve-taxi reserve-flight"
Public-Keys: bill=23412341234;agent=3423412341234
<purchase>...</purchase>

You’ll notice that the Visa, Permissions, and Public-Keys headers are the same values as the original request made by Bill.  The Authorization header is different as the Travel Agent is making the request.  The airline services does authentication and authorization of the Agent’s request the same exact way the Agent did for Bill’s request.  Again, the key part of this is that only the IDP is trusted and only the IDP’s public key needs to be known ahead of time.

Vulnerabilities

Disclaimer, I’m new to security so dealing and thinking about attacks is new to me.  Generally a lot of attacks can be prevented by specifying a timestamp and expiration with each sign piece of data.  Services can refuse to honor old requests.  Nonces could also be included within signature metadata to avoid replays.

User’s Private Key is compromised

User’s authentication with the IDP doesn’t have to be key based.  It could be TOTP based where the user has to login through his browser providing a password along with a device-generated time-based key.  The IDP could then return a temporary private key the client uses to sign requests.

IDP’s Private Key is compromised

This is a scary one.  Maybe it could be prevented by requiring and acquiring Visa’s from multiple IDPs?  A service would verify signatures from two or more IDPs.  The probability of more than one IDP’s private key being compromised becomes less and less the more IDPs you have involved with the interadtion.

Summary

So here’s a summary of this brainstormed protocol:

  • The Public-Keys header’s purpose is two-fold.  First, its a list of public keys.  More importantly it is a list of principles that are involved with the interaction.
  • The Permissions header is a list of permissions of each principle involved for each service they will interact with.
  • The Visa header is a digital signature of the Public-Keys and Permissions header.  It also will probably have a timestamp and an expiration as well (all digitally signed of course).
  • The Authorization header exists to verify the integrity of the HTTP request of the entity sending the request.  It is a digital signature of the HTTP verb, path, host, message body, Visa, Permissions, and Public-Keys headers.
  • The IDP is the only trusted entity in the whole multi-tier distributed interaction.
  • Each service must have the IDP’s public key stored at deployment time prior to servicing any requests
  • There is no communication to the IDP by any service.  Even the initiating client’s first interaction with the IDP to obtain a Visa could be done ahead of time and re-used for multiple interactions.

This is just a rough outline, but there’s probably other things that could be added.  Like nonce’s for instance.  Its just a matter of implementing it and getting people to use it.  The real question is, is there an existing protocol already out there that does this sort of thing?

Brainstorming REST Security Part I

6 Comments

If you went to my presentations at JUDCon/JBossWorld/RHS 2011 or read my recent blog posting you’ve probably noticed that I’m starting to focus on REST+Security.  This will be the start of a series of blogs that attempts to solidify a common vision around Security+REST and spec out what we’re going to do for RESTEasy and JBoss.

Internet Security is A Ghetto

One thing I’ve noticed is what a ghetto Internet security is, or even security in general.  There are old and new specifications, various industry collaborations efforts that succeed sort of (OpenID), start to succeed then have mutinies (OAuth), WS-* specs trying to bleed into the Web space (SAML), and promising specs that have had success in the email world (DKIM).  That’s just the small list of examples.  Its a freakin mess!  One common thread seems to be that most of them focus on providing security for the Internet (Internet with a capital ‘I’) and most have their roots in providing security for browser based apps.  Enterprise apps, while they can build off of security specs defined for the Internet, can often have very different requirements.  Web services can also have different requirements as well as a human (browser) may not be involved with client/server interactions.  In summary, I guess what I’m saying is that there are too many specs, no clear winners, too browser focused, and very little Enterprise focused.

What I’m trying to do with this and subsequent blogs is to brainstorm what high-level requirements for security enterprise apps should have, how can we make deployment of a security solution easier, what existing specs are applicable, what existing specs are open to input, what new specs have to be implemented, how can we make the protocols as easy to implement as possible in multiple languages, and finally, how can we design security services to make it as easy as possible to deploy to our Enterprise applications.

If I had to deploy a security solution…

A security solution I’d like to have would take enterprise as well as the difference between browser and non-browser clients in mind.  Its gotta balance strong security with ease of deployment, ease of use, and ease of implementation.  Many of these will be obvious, but I want to write it down.

  • For browser based clients I’d to authenticate using a user password and a one-time-password (OTP) generated by a soft or hard token generator.  Plain passwords are just not viable.   I myself have had both my GMail and World of Warcraft accounts hacked.  A combo of password + random key allows users to have simple to remember passwords yet be secure enough not to get hacked.  With smart phones like iPhone and Android, its easy to acquire a soft key generator (or implement one) without paying RSA an arm and a leg.
  • After authentication, the browser client should obtain an expirable cookie that it forwards with each request that contains authentication information the server will use to authenticate subsequent requests.
  • For non-browser clients,  I like the idea of digitally signed requests.  Verification of a digitally signed request would be the authentication mechanism.  What’s good about this (like the OTP of browser-based clients) is that credentials are different per request in that they are part of the attached signature.  A nonce and/or an expiration can be included within the digital signature to avoid replay attacks.
  • I foresee the need for non-browser clients to make requests on behalf of other services to other services.  Attaching multiple signatures to a request might be the way here.
  • It would be really cool to have a decentralized way to to both authenticate and authorize.  The hub and spoke approach that Picketlink STS uses creates a bit of a single point of failure and can require extra network round trips.  This decentralized mechanism should be able to work in an environment where services are making requests to other services on behalf of one or more identities.
  • A user had a really interesting case where they wanted to provide access to content through signed URLs.  The idea is that they would generate a signed URL and email it to a user to click on.  Very interesting.

Applicable Specs

Here’s some specs that I thought of off the top of my head that could be useful.  If anybody has ideas of others, let me know.

  • Time-based One Time Password Algorithm (TOTP).  Anil already did some work in Picketlink to implement this protocol.  We still need to integrate it as a Authenticator Valve in JBossWeb.  There’s also a nice iPhone app that supports TOTP.  I actually forked and re-implemented a lot of it on my own when I was learning Objective C a few months ago.  We’re looking at creating an Apple App Store account to distributed this forked implementation so we can brand it Red Hat.
  • SAML.  This may be what we need to do decentralized authorization.  I’m not fully versed in the spec, but I have read up on their HTTP bindings.  I’m not sure if there is any way to tunnel assertions through an HTTP header. (We don’t want to send SOAP requests).  If we can use SAML, we can piggyback off of a lot of the efforts already done in the Picketlink project.
  • Doseta.  I’ve already blogged about this protocol.  Using DNS to distribute keys is a little weird, but cool.  I’m asking that working group for this spec to break out Doseta into a few different specifications so that we can re-use the signature calculation algorithm in a standard way and to also make DNS public key publication optional and maybe also to provide an HTTP way to distribute keys.
  • Amazon REST Authentication.  Specs out how to sign URLs.  Maybe this could be standardized at IETF.
  • OpenID.  OpenID seems interesting for decentralized authentication, but I’m not sure if it can be used as a mechanism to do decentralized authorization.  OpenID is also more of a browser-based technology.
  • OAuth.  OAuth has both browser and non-browser bindings.  OAuth 2.0 pretty much leaves out what a token looks like.  I also don’t really want a token based system for non-browser clients

Possible Middleware Services

Here’s some ideas for services/integration we would implement.

  • HTTP Identity Proxy.  While implementing just an HTTP Proxy Cache is boring what might make these feasible is applying Identity to the mix.  This would delegate authentication and even authorization to an outside service.  Requests would be authenticated/authorized through the proxy, digitally signed, then forwarded to the target service.  The target service then only need to verify the signed request using the public key of the proxy.  While there’s obvious performance drawbacks, what’s interesting about this is that the application doesn’t have to think much about security and it could possibly be added even after the service is deployed.
  • TOTP Authenticator Valve.  Nuff said…I tihnk Anil already has this.
  • Better Auth integration with JBossWeb and the JBoss Security Domain abstraction.  Right now there’s just too many steps to enable things.
  • Various auth plugins for JBossWeb to realize our vision here.

RESTEasy 1.0.2.GA Released

Leave a comment

More bugs found by our users. See our release notes on 1.0.2.GA for more details.

Next release will be 1.1-RC1 beginning of March which will introduce client and server side interceptors. Client side “Browser” caching. Server side cache support. GZIP encoding support

RESTEasy 1.0.1.GA released, Minor Bug Fixes

2 Comments

Users found a few minor bugs with 1.0.GA.  See our release notes on 1.0.1.GA for more details.  Unless there is a critical bug reported, no releases until March.

Writing RESTFul Java Book

16 Comments

I’ve contracted with O’Reilly to write a “RESTFul Java” book about REST, Java, and JAX-RS.  Should be out sometime this summer.

RESTEasy 1.0.0.GA Released!

2 Comments

See more info on blogs.jboss.com.

Web Apps vs. Web Sites

4 Comments

I’ve been excited for awhile now about going retro.  Going retro to the days of 3-tiered GUI applications and substituting VB+DCE/CORBA+DB with AJAX+REST+DB.  We got to talking about this quite extensively today in a Red Hat internal mailing list after the announcement of Red Hat’s participation in the Google GWT project.

One problem I had problems reconciling with was the search engine problem.  If your web application is rendered dynamically through AJAX and GWT-controlled pages how will a search engine index your site?  Michael Neale came to the rescue with:

If you want search engine crawling – then its not a web app, its a web site.

This statement is simple but profound.  It makes sense because a web app is highly interactive, dynamic, and usally un-indexable.  He’s on to something.  He talks a little more in detail about it here.  Thanks Mike!

RESTEasy Beta 9 Released

5 Comments

Follow documentation and download links from our main project page.  View our full release notes from JIRA.  Special thanks goes out to Solomon Duskis for helping me nail down the Spring integration and for implementing the Spring MVC bridge.  This is a pretty extensive release with a lot of new features:

  • Asynchronous HTTP (Comet) support via Tomcat 6, JBoss Web, or Servlet 3.0 (Jetty 7).  This is a tiny, but simple abstraction over these APIs
  • Expanded Multipart support.  You can now marshal collections(Maps and Lists) of objects to and from multipart/mixed and multipart/form-data.
  • Atom + JAXB support.  I wrote a few JAXB annotated classes to represent the Atom format.  You can embed JAXB classes within Atom content as well as marshall Atom to and from XML, JSON, and Fastinfoset.
  • Atom support via Apache Abdera
  • Arrays and Collections of JAXB objects marshalled automatically.
  • Enhanced Spring support.  We now support autoproxied beans as well as some nice Spring MVC support and the ability to output ModelAndView objects.  Thanks Solomon!!!

This will hopefully be the last beta.  I’ve been waiting patiently (since October 1st) for Red Hat and Sun to hammer out the licensing terms so I can download the JAX-RS TCK and get RESTEasy certified.  I should be getting it any day now and so the next release of RESTEasy will be RC1 and certified.  I’m not sure how long the TCK will take as I don’t have my hands on it yet, but I’m hoping around 6-8 weeks.  Shortly after RC1 will be 1.0.

JAX-RS Atom Support with Resteasy

3 Comments

I have implemented Atom support which will be available with the next release of RESTEasy.

Although the Atom format is used primarily for the syndication of blogs and news, many are starting to use this format as the envelope for Web Services, for example, distributed notifications, job queues, or simply a nice format for sending or receiving data in bulk from a service.

RESTEasy has defined a simple object model in Java to represent Atom and uses JAXB to marshal and unmarshal it. The main classes are in the org.jboss.resteasy.plugins.providers.atom package and are Feed, Entry, Content, and Link. If you look at the source, you’d see that these are annotated with JAXB annotations. The distribution contains the javadocs for this project and are a must to learn the model. Here is a simple example of sending an atom feed using the Resteasy API.

import org.jboss.resteasy.plugins.providers.atom.Content;
import org.jboss.resteasy.plugins.providers.atom.Feed;
import org.jboss.resteasy.plugins.providers.atom.Link;
import org.jboss.resteasy.plugins.providers.atom.Person;

@Path("atom")
public class MyAtomService
{

   @GET
   @Path("feed")
   @Produces("application/atom+xml")
   public Feed getFeed()
   {
      Feed feed = new Feed();
      feed.setId(new URI("http://example.com/42"));
      feed.setTitle("My Feed");
      feed.setUpdated(new Date());
      Link link = new Link();
      link.setHref(new URI("http://localhost"));
      link.setRel("edit");
      feed.getLinks().add(link);
      feed.getAuthors().add(new Person("Bill Burke"));
      Entry entry = new Entry();
      entry.setTitle("Hello World");
      Content content = new Content();
      content.setType(MediaType.TEXT_HTML_TYPE);
      content.setText("Nothing much");
      feed.getEntries().add(content);
      return feed;
   }
}

Because Resteasy’s atom provider is JAXB based, you are not limited to sending atom objects using XML. You can automatically re-use all the other JAXB providers that Resteasy has like JSON and fastinfoset. All you have to do is have “atom+” in front of the main subtype. i.e. @Produces(“application/atom+json”) or @Consumes(“application/atom+fastinfoset”)

Using JAXB with the Atom Provider

The org.jboss.resteasy.plugins.providers.atom.Content class allows you to unmarshal and marshal JAXB annotated objects that are the body of the content. Here’s an example of sending an Entry with a Customer object attached as the body of the entry’s content.

@XmlRootElement(namespace = "http://jboss.org/Customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer
{
   @XmlElement
   private String name;

   public Customer()
   {
   }

   public Customer(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return name;
   }
}

@Path("atom")
public static class AtomServer
{
   @GET
   @Path("entry")
   @Produces("application/atom+xml")
   public Entry getEntry()
   {
      Entry entry = new Entry();
      entry.setTitle("Hello World");
      Content content = new Content();
      content.setJAXBObject(new Customer("bill"));
      entry.setContent(content);
      return entry;
   }
}

The Content.setJAXBObject() method is used to tell the content object you are sending back a Java JAXB object and want it marshalled appropriately. If you are using a different base format other than XML, i.e. “application/atom+json”, this attached JAXB object will be marshalled into that same format.

If you have an atom document as your input, you can also extract JAXB objects from Content using the Content.getJAXBObject(Class clazz) method. Here is an example of an input atom document and extracting a Customer object from the content.

@Path("atom")
public class AtomServer
{
   @PUT
   @Path("entry")
   @Produces("application/atom+xml")
   public void putCustomer(Entry entry)
   {
      Content content = entry.getContent();
      Customer cust = content.getJAXBObject(Customer.class);
   }
}

JAX-RS Multipart support with RESTEasy

7 Comments

I just finished implementing some “multipart/*” and multipart/form-data support within RESTEasy.  It will be out with the next release.  Highlights?

A JAX-RS compatable API

Our current support for multipart is through the MimeMultipart classes within the Java Mail library.  They are limited because they do not use the MessageBodyReader/Writers available in JAX-RS.  I have written two parallel APIs that provide multipart support in a JAX-RS way:

package org.jboss.resteasy.plugins.providers.multipart;

public interface MultipartInput {
   List<InputPart> getParts();
   String getPreamble();
}

public interface InputPart {
   MultivaluedMap<String, String> getHeaders();
   String getBodyAsString();
   <T> T getBody(Class<T> type, Type genericType) throws IOException;
   <T> T getBody(org.jboss.resteasy.util.GenericType<T> type) throws IOException;
   MediaType getMediaType();
}

MultipartInput is a simple interface that allows you to get access to each part of the multipart message. Each part is represented by an InputPart interface. Each part has a set of headers associated with it.  You can unmarshall the part by calling one of the getBody() methods. The Type genericType parameter can be null, but the Class type parameter must be set. Resteasy will find a MessageBodyReader based on the media type of the part as well as the type information you pass in. The following piece of code is unmarshalling parts which are XML into a JAXB annotated class called Customer.

   @Path("/multipart")
   public class MyService   {
      @PUT
      @Consumes("multipart/mixed")
      public void put(MultipartInput input)
      {
         List<Customer> customers = new ArrayList...;
         for (InputPart part : input.getParts())
         {
            Customer cust = part.getBody(Customer.class, null);
            customers.add(cust);
         }
      }
   }

There’s a similar API for outputing multipart.

Multipart with vanilla Lists and Maps

Another feature I’ve added is the ability to use regular instances of java.util.List(any multipart format) or Map (form-data only) to represent multipart data.  Its only usable when your parts are uniform though.

Here’s an example of using it:

parameter of the List type declaration. Here’s an example again of unmarshalling a list of customers.

   @Path("/multipart")
   public class MyService
   {
      @PUT
      @Consumes("multipart/mixed")
      public void put(List<Customer> customers)
      {
         ...
      }
   }

That’s using input.  The problem with output is that RESTEasy has no idea what mime type you want to marshal or List or Map into.  So, the @PartType annotation is used.  Here’s an example of outputing multipart/form-data with a map:

@Path("/multipart")
   public class MyService
   {
      @GET
      @Produces("multipart/form-data")
      @PartType("application/xml")
      public Map<String, Customer> get()
      {
         ...
      }

Multipart-Formdata with POJOs

Finally, I added the ability to map POJO form classes to multipart/form-data.  You re-use @FormParam on fields and/or properties of a user-provided POJO.  Here’s an example:

   public class CustomerProblemForm {
      @FormData("customer")
      @PartType("application/xml")
      private Customer customer;

      @FormData("problem")
      @PartType("text/plain")
      private String problem;

      public Customer getCustomer() { return customer; }
      public void setCustomer(Customer cust) { this.customer = cust; }
      public String getProblem() { return problem; }
      public void setProblem(String problem) { this.problem = problem; }
   }

After defining your POJO class you can then use it to represent multipart/form-data. Here’s an example of sending a CustomerProblemForm using the RESTEasy client framework

   @Path("portal")
   public interface CustomerPortal {

      @Path("issues/{id}")
      @Consumes("multipart/form-data")
      @PUT
      public void putProblem(@MultipartForm CustomerProblemForm,
                             @PathParam("id") int id);
   }

   {
       CustomerPortal portal = ProxyFactory.create(CustomerPortal.class, "http://example.com");
       CustomerProblemForm form = new CustomerProblemForm();
       form.setCustomer(...);
       form.setProblem(...);

       portal.putProblem(form, 333);
   }

You see that the @MultipartForm annotation was used to tell RESTEasy that the object has @FormParam and that it should be marshalled from that. You can also use the same object to receive multipart data. Here is an example of the server side counterpart of our customer portal.

   @Path("portal")
   public class CustomerPortalServer {

      @Path("issues/{id})
      @Consumes("multipart/form-data")
      @PUT
      public void putIssue(@MultipartForm CustoemrProblemForm,
                           @PathParm("id") int id) {
         ... write to database...
      }
   }

Older Entries

%d bloggers like this: