Using iron to Encapsulate Cookies

Eran Hammer has recently created iron, a cryptographic procedure and tool to seal arbitrary data in a way so that it cannot be read and also cannot be changed without being noticed.

Besides its intended use in combination with Oz it can also be used in other scenarios. One of them being encapsulated HTTP cookies. While it is in no way a new thing to pass state to Web clients in encrypted form so they cannot read it or tamper with it, doing it right is relatively hard. Hence, it is great to now have a quasi-standard and sound definition.

Update: Looking something up in Theo Schlossnagle‘s Building Scalable Internet Architectures I found a passage Addressing Security and Integrity in chapter 7, p.130 that resembles the topic of this post.

To bring iron into the Java world, I have created jiron and an example project to illustrate how to use iron for HTTP cookie authentication with encapsulated tokens.

First, let’s see, how to use jiron to seal and unseal data:

import net.jalg.jiron.Jiron;
 
String data = "Some secret stuff we want protected";
 
String sealed = Jiron.seal(data, "sealing-password",
                                        Jiron.DEFAULT_ENCRYPTION_OPTIONS,
                                        Jiron.DEFAULT_INTEGRITY_OPTIONS);
 
String unsealed = Jiron.unseal(sealed, "sealing-password",
					Jiron.DEFAULT_ENCRYPTION_OPTIONS,
					Jiron.DEFAULT_INTEGRITY_OPTIONS);

The String sealed is what you can pass around and be sure that nobody can read or modify it, unless in possession of the sealing password.

Suppose you have a Web site that employs cookie-based authentication and suppose you have some data you want to store in that cookie directly so you do not have to go to a database shared by all server instances for looking up that data. For example the user’s login, her real name and information when the cookie expires and re-authentication is enforced.

Initially, a user not in possession of the cookie will be redirected to a login form and the cookie will be issued upon submission of valid credentials. Here is an excerpt of the form processing JAX-RS resource:

String data = login + "|" + expires + "|" + realname;
String cookieValue = Jiron.seal(data, ApplicationConfig.ENCRYPTION_KEY,
					Jiron.DEFAULT_ENCRYPTION_OPTIONS,
					Jiron.DEFAULT_INTEGRITY_OPTIONS);
 
NewCookie c = new NewCookie(AuthFilter.COOKIE_NAME, cookieValue);
return Response.seeOther(redirectUri).cookie(c).build();

In the HTTP response the cookie will look something like (line breaks added for clarity):

Set-Cookie:authtoken=Fe26.1**7A6A689DEC9563773B1264CF4CC585CFC9CF84403EE9143650D2EC2EE
24E36A3*k9yW1ZlC5Tr1a5o2Os_QMQ*sxZkQJfHsfyZE_0DI3ugHKdQ3IXwy1jySoz7GrKiTWU*9C58B956A11
81D1F1E3A1A7A1B67D2CF7738B0BFB16C5EB4B381151CAEEC4C6C*3PxSsg5aThLGvU2e8ItXfep-hpMw5x96
L_PbelhnU84;Version=1

To protect a resource class by enforcing cookie auth, we bind a JAX-RS 2.0 filter to that class using a new annotation:

//...
@TokenAuthProtected
public String getDashboard(@Context SecurityContext sc) { ... }

The auth enforcing filter class extracts the cookie, checks expiration time and puts the data contained in the cookie in a place where it can be accessed by the resource class.

Cookie cookie = context.getCookies().get(COOKIE_NAME);
// Redirect to form if no cookie
String data = Jiron.unseal(cookie.getValue(), ApplicationConfig.ENCRYPTION_KEY,
					Jiron.DEFAULT_ENCRYPTION_OPTIONS,
					Jiron.DEFAULT_INTEGRITY_OPTIONS);
// ...
String[] fields = data.split("\\|");
final String username = fields[0];
final long expires = Long.parseLong(fields[1]);
final String realname = fields[2];
// ...
if (now > expires) {
  context.abortWith(Response.temporaryRedirect(loginFormUri).build());
  return;
}
 
context.setSecurityContext(new TokenSecurityContext(username, realname));

Using the security context and a custom Principal, the resource class is provided access to the user’s login and realname.

(There is currently discussion in the JAX-RS 2 expert group to enable passing information from filters to resource classes using properties on the filter chain. That would be the better solution than the SecurityContext/Principal ‘hack’).

Please have a look at the source code for the code details.

Beyond OAuth

Eran Hammer‘s noisy departure from OAuth 2 woke me up to finally engage in that HTTP security investigation that had been buried in my todo list for years. Thanks a bunch for that, Eran!

Starting from close-to-zero security knowledge it took some time to understand the points he is making but finally it all came together: Yep – sadly he’s spot on with his criticism. If in doubt, look at the OAuth 2.0 Threat Model or the bloating OAuth related I-Ds.

Regarding his IETF criticism, I can see where he is coming from, given the amount of Big Co representatives in that WG, but I don’t think the IETF is to blame in general. Personally I like written standards and I like the process to be slow to buffer change. In the end, it depends on the staffing I’d say, not the organization as such.

Suggestions? Steer clear of OAuth 2, it’s a waste of time. Stick to OAuth 1 if you need something right now, or, much better, follow the new thing…

Fortunately Eran resumed productivity and started work on a set of the-code-is-the-specification modules for node.js that each cover a distinct aspect of what really smells like a useful successor of OAuth: iron, Hawk, and Oz.

iron implements a cryptographic procedure for encrypting arbitrary data and ensuring the integrity of the result. In the context of coming up with an OAuth successor it serves as a tool to provide a stateless way of authenticating a request and checking authorization. “Stateless” as in “no shared state between hundreds of scaled-out auth-checking servers”. That in itself is big.

Hawk implements an HTTP HMAC-based authentication scheme. It builds upon the work Eran has done on this in the OAuth 2 context and addresses the requirement of doing authentication without passing passwords around the Web.

Finally, Oz addresses the use case of delegated authorization, the stuff you have in mind when you are looking for an OAuth successor. Oz builds upon iron and Hawk to solve some of the statefulness problems of OAuth 1 and to employ a mandatory, sound, yet simpler-than-OAuth-1 signature mechanism.

Over the past months I have been sort of reengineering the procedures implicitly defined by the three modules to create implementations of them in Java and C. I also work on creating written specs for them to reduce the impact of programming language specifics on the procedures. This should help to create interoperable implementations in other languages. For example, there is quite some implicit encoding stuff going on in the node.js implementation that needs to be nailed down when you do the Java thing.

So far, I have a Java implementation of iron ready, called jiron and one in C called ciron.

There is also an implementation of Hawk in Java, named hawkj and I am working on example JAX-RS 2 filter implementations to show how to use it.

The situation regarding Oz is a bit difficult because Eran has not yet produced a writeup of his ideas and I do not feel capable of extracting these ideas from the existing node.js module code base. AFAIU his ideas are still not completely stable either So I will put this on hold for now. He’s activelu on it so it won’t be too long.

Another thing is that, while I am excited with what you can see in Oz already, I have use cases in mind for an OAuth successor myself. While Eran is explicitly focussing on mobile and steering clear of typical enterprise use cases (“boss wants to grant secretary access to his calendar” , “Report generator client must have read-access to all calendars of all users”) I am interested in a solution that covers all the use cases you can think of for RESTful APIs. Public-facing as well as intra-enterprise.

I think I have something there that addresses arbitrary use cases in the HTTP-API space and is not just an essentially meaningless framework and also doesn’t end up being an enterprisey, complexity-bloated monster. I am not yet clear whether it can be an evolution of Oz or needs to be a competitor. We’ll see about that.

In any case, it is a fascinating space to explore once you get over the initial crypto-confusion barrier.

Getting Started Playing Around with JAX-RS 2.0 in an EE Container

Trying out the latest JAX-RS API advancements in an EE container is a bit of a pain because pulling in the latest JAX-RS 2.0 libraries into a Java EE environment creates conflicts with the EE-shipped JAX-RS version. Ah yes, and of course you want your IDE to pick up the correct libs for code completion.

After trying and tweaking a bit the most workable solution for me was to download the latest Glassfish 4 build. It uses a Jersey version that is usually only a couple of days behind the JAX-RS API Snapshot.

Here is what I do:

First, go to the lastest Glassfish builds and download the file named glassfish-4.0-bxx.zip with xx having the highest number (as of Nov 19th this is glassfish-4.0-b63.zip).

This will unzip to a glassfish3/ directory, so to start the server do

glassfish3/glassfish/bin/asadmin start-domain

To find the JAX-RS version included in the Glassfish you just downloaded do something like the following:

jar -xf glassfish3/glassfish/modules/javax.ws.rs-api.jar META-INF/MANIFEST.MF; grep Bundle-Version META-INF/MANIFEST.MF

(This will leave a META-INF directory behind you might want to clean up afterwards)

For the b63 version this yields:

Bundle-Version: 2.0.0.m12

The next step is to create a project to test things out. I am using the following archetype, but any other EE Web profile archetype should work similarly:

mvn archetype:generate \
  -DarchetypeGroupId=org.codehaus.mojo.archetypes \
  -DarchetypeArtifactId=webapp-javaee6 \
  -DgroupId=org.example \
  -DartifactId=test \
  -DinteractiveMode=false

Now let’s edit the POM to pull in the JAX-RS 2.0-Version used by the Glassfish. First, add the proper repository.

 <repository>
 <id>snapshot-repository.java.net</id>
 <name>Java.net Snapshot Repository for Maven</name>
 <url>https://maven.java.net/content/repositories/snapshots/</url>
 <layout>default</layout>
 </repository>

Then add the dependency to the specific release (note that the version is not literally the same as the bundle version you extracted above):

<dependency>
  <groupId>javax.ws.rs</groupId>
  <artifactId>javax.ws.rs-api</artifactId>
  <version>2.0-m12</version>
  <scope>provided</scope>
</dependency>

UPDATE: It seems you have to make sure you include this dependency before the dependency to the Java EE Web API. Otherwise, maven insists on trying to use the JAX-RS API version of the Java EE Web API.

You should now be able to mvn package and deploy to the Glassfish instance any 2.0-m12 based source code.

The final step will be to cd into your project folder and set up your IDE project. E.g. with Eclipse run

mvn eclipse:eclipse

and import as existing Maven project into Eclipse.

Code completion should now suggest you the 2.0-m12 API.

If you want to have code completion work with the SNAPSHOT, simply change the POM dependency and rerun mvn eclipse:eclipse. This will likely break when deployed in the container (if you use a SNAPSHOT-only API feature) but still it is nice to play around with the very latest API changes.

This focusses on JAX-RS 2.0 latest features. Keep in mind that for the rest of Java EE we referenced the EE6 Web API profile. This is not for testing latest EE7 features in general.

UPDATE: You can find the releases, including the apidoc jars here.

JAX-RS 2.0 Essential Bookmarks

In my JAX-RS 2.0 talk at DEVOXX 2012 I promised to write down the useful links to play around with 2.0. Here they come:

JAX-RS 2.0

Jersey + glassfish

RESTEasy

Blogs

JAX-RS 2.0 MVC

It is not unusual for services that expose a technical REST API to also need human-targeted UI for configuration, status checks or reporting.

What I have seen a couple of times is that developers naturally use some form of REST framework (for example JAX-RS) for the technical API but then make use of yet another API technology (for example Spring or JSF) for the human-targeted UI.

This not only increases the technology mix (something I personally strive to avoid as much as possible), but it also introduces a distinction between technical and human API that should not be made in my opinion. From an API point of view an HTTP interface that serves HTML and AJAX-targeted JSON is as much a REST-API as is one that serves XML or ‘technical’ JSON.

Instead, you should treat both as aspects of one and the same API. For one you will likely find resources in both API-’parts’ that serve representations of the same concepts (for example calendar events, shopping carts or contract information). Such repesentations of should be produced by one and the same resource. This reduces the amount of code and will help you, for example, to apply corresponding cacheability properties to both representations.

In addition, it will encourage you to treat the human-targeted API-parts with the same care as the technical ones. For example, you should allow introspection into them using some form of home document. Above all, you’ll never know in which ways clients re-use those HTML pages or snippets you serve.

Having said that, what might – besides just habits – be the reason that developers do not think ‘REST-API’ when they think ‘GUI’? Is it because many REST frameworks out there have very poor support for serving document-oriented representations such as HTML pages?

While some JAX-RS implementations have proprietary support for templating, the new JAX-RS 2.0 filter API lets you roll your own with a couple of lines of code.

Instead of the ‘Web-container-only’-setup I used in the last blog I would like full Java EE6 support this time. Fortunately, Arun Gupta has provided an example of how get JAX-RS 2.0 to work in a Java EE 6 container.

First I created a project based on the archetype Arun uses:

mvn archetype:generate \
   -DarchetypeGroupId=org.codehaus.mojo.archetypes \
   -DarchetypeArtifactId=webapp-javaee6 \
   -DgroupId=net.jalg \
   -DartifactId=mvc \
   -DinteractiveMode=false

and then added the neccessary repository and dependencies the way he describes. Because JAX-RS 2.0 and Jersey currently undergo some sort of last minute changes I have changed the Jersey dependencies to be on 2.0-SNAPSHOT to get the latest developments.

The templating support I have in mind would let me return any object from a JAX-RS resource method. In addition it would let me annotate the resource method to specify a template to use for constructing the representations. Like so:

@Path("user/{userId}/account")
public class Facade {
 
  @PathParam("userId") String userId;
 
  @GET
  @Produces("text/html")
  @Path("contract-details")
  @Template("templates/contract.vm")
  public Contract getContractDetails() {
    return new Contract("123456", userId, "new");
  }
}

The problem here is that the JAX-RS runtime will pick the MessageBodyWriter implementation based on the returned type. It will not, magically, invoke some sort of templating engine. So, how can we trick the runtime into choosing a different MessageBodyWriter? And how can we pass to that not only the returned object but also the path of the desired template?

Here the filter API comes in. We can use the @Template annotation to also act as a binding for a particular filter. This is done with the @NameBinding annotation from the new filter API:

@NameBinding
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Template {
  String value() default "";
}

Now the runtime will invoke all filters annotated with @Template when our getContractDetails() method is called and we can work the magic in a filter.

What happens in the filter below is that we replace the response entity with a wrapper object that holds the template path and the original response entity. The template path we can extract from the annotation, the original response entity we extract from the response context.

@Provider
@Template
public class EntityToModelAndViewWrapper implements ContainerResponseFilter {
 
  @Override
  public void filter(ContainerRequestContext requestContext,
      ContainerResponseContext responseContext) throws IOException {
 
    for (Annotation a : responseContext.getEntityAnnotations()) {
      if (a.annotationType() == Template.class) {
        String templatePath = ((Template) a).value();
        ModelAndView mav = new ModelAndView(responseContext.getEntity(),templatePath);
        responseContext.setEntity(mav,
          responseContext.getEntityAnnotations(),
          responseContext.getMediaType());
        break;
      }
    }
  }
}

By changing the type of the response entity, we gain control over the MessageBodyWriter selection. And the runtime will now invoke the MessageBodyWriter we have provided for ModelAndView instances:

@Provider
...
public class ModelToViewMBR implements MessageBodyWriter<ModelAndView> {
   ...
  @Override
  public void writeTo(ModelAndView mav, Class<?> arg1, Type arg2,
        Annotation[] arg3, MediaType arg4,
        MultivaluedMap<String, Object> arg5, OutputStream output)
        throws IOException, WebApplicationException {
    Map<String, Object> map = new HashMap<String,Object>();
    map.put("entity", mav.getModel());
    engine.merge(mav.getView(),output,map);
  }
   ...
}

In the writeTo() method we make the original response entity available to a templating engine under the name ‘entity’ and invoke the merge of template and entity.

The engine member is an instance of a template engine wrapper. You can see the details in the TemplateEngine class in the example source code.

In addition to the response entity it should not be too hard to make available to the template engine all the managed beans of the container runtime’s current session (the request). That way one would have the full power of EJB 3.1 and CDI at one’s disposal.

Declarative Cache Control with JAX-RS 2.0

UPDATE: The Maven/IDE setup below turned out not to work properly in all cases. Try this for better results.

The final release of JAX-RS 2.0 is nearing. Time for a closer look at the new features.

As JAX-RS 2.0 isn’t yet part of any standard release, some up front work is inevitable. Fortunately, Marek has some excellent write ups to get us started using the JAX-RS 2.0 reference implementation Jersey 2.

I am currently working with Eclipse a lot and here is how you quick-start a JAX-RS 2.0 project with Jersey 2:

In Eclipse, choose New -> Other -> Maven Project and create an archetype-based project. For this you first need to add the archetype Marek is mentioning in his post (I am using the Grizzly version here):

Then, create a project with that archetype:

Now you are all set and ready to explore JAX-RS 2.0.

Making JAX-RS responses cacheable isn’t exactly elegant in 1.1. If you want caching, you need to return a Response object and manually add Cache-Control headers to it. Far from ideal. (And it gets even uglier if you try to unit test your resource classes just to find out that you cannot do so if you return Response objects because the idiomatic invocation of build() demands a JAX-RS runtime).

What, if we instead could annotate a resource method to decorate the response with a Cache-Control header? Turns out, that this is straight forward in JAX-RS 2.0 thanks to the new Filter API.

All we need is a filter and an annotation to selectively bind that filter to any resource method of our liking. Here is the annotation which takes a Cache-Control header value as an argument:


package net.jalg.ccdecor;
import java.lang.annotation.*;
import javax.ws.rs.NameBinding;

@NameBinding
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Cacheable {
  String cc() default "public, must-revalidate";
}

The new @NameBinding annotation tells a JAX-RS 2.0 runtime that our annotation should be used to match filters to resource methods.

Here is the filter:


package net.jalg.ccdecor;

import java.io.IOException;
import java.lang.annotation.Annotation;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;

@Provider
@Cacheable
public class CacheControlDecorator implements ContainerResponseFilter {

  @Override
  public void filter(ContainerRequestContext requestContext,
        ContainerResponseContext responseContext) throws IOException {
    for (Annotation a : responseContext.getEntityAnnotations()) {
      if (a.annotationType() == Cacheable.class) {
        String cc = ((Cacheable) a).cc();
        responseContext.getHeaders().add("Cache-Control", cc);
      }
    }
  }
}

Don’t worry too much about that code for a minute but look at how the filter can be bound to a resource method:


  @GET
  @Cacheable(cc="public, maxAge=3600")
  @Produces(MediaType.TEXT_PLAIN)
  public String getIt() {
    return "Got it!";
  }

The binding is achieved using our @Cacheable annotation.

Using annotation arguments it is possible to pass usage information to the filter. The annotations of the resource method are available in the filter by way of the getEntityAnnotations() method of the passed ContainerResponseContext argument (see above).

We just need to extract the cache control information from the annotation and add the Cache-Control header to the response.

You can download the example project from github.

Death by JBoss 6 Classloading

During the last week I have spent hour after hour to debug some strange behavior shown by some of my JAX-RS provider classes in two JavaEE6 projects. When I deployed the WARs of the two projects suddenly in one of the projects all providers from both projects where available and in the other none, … zero, zip.

Naturally, I only saw this by accident, after an extensive two-day search in one of the projects for a potential bug caused by myself. Dang! – When I, frustrated as I was, re-deployed the other project I saw the providers I had been looking for in the first deployed app.

Yes, I know now, that I should have thought about the interference between the two right away…but you know how these things go.

When it finally dawned on me that I fell victim to some default configuration in JBoss that (at least to me) is totally counter intuitive the search went reasonably well. (Though documentation at jboss.org is still way to hard to find for my taste)

I figured I had to isolate my class loaders with something like this:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<class-loading>
      <loader-repository>com.example:archive=myapp-1.war
        <loader-repository-config>java2ParentDelegation=false</loader-repository-config>
      </loader-repository>
   </class-loading>
</jboss-web>

The crappy thing about this is that apparently the reason for the non-intuitive default is that versions prior to JBoss 5 exhibit not-isolated class loading. The designers of JBoss 5+ desired to make the old configurations work in the newer JBosses without adjustments. Makes me shiver.

Edit: Turns out you also need to set java2ParentDelegation=false in the example above to make it work.

Edit: Nope – the above also did not do the trick. After a wasted week of digging around, I give up now, simply installing another JBoss (unable to switch to Glassfish due to external forces :-(.

Useful references:
https://community.jboss.org/wiki/ClassLoadingConfiguration
https://community.jboss.org/wiki/JBossClassLoadingUseCases

ESI Facelift

Recently Mark described why Edge-Side-Includes are still a relevant technology and presented some ideas regarding an overhaul of ESI 1.0.

Coincidentally, I ran into an interesting use case for ESI at about the same time and our requirements seem to overlap quite a bit.

Before I go into the details of what I would like to see in ESI 2.0 (yes, the major version number change indicates incompatibility) here are the aspects that need to be considered during the design process:

Language Syntax

ESI 1.0 is an XML language. While this was the obvious choice ten years ago when XML was the proverbial hammer to every nail times have changed. To be a good citizen, ESI 2.0 would need to be friendly to non-XML formats such as JSON and certain plain text species, too.

This isn’t too much of a change, given that none of the ESI implementations I have looked at actually parse ESI tags as XML. Which makes sense, because the surrounding (X)HTML is almost guaranteed to choke an XML parser anyhow.

Functionality

This aspect covers two issues, really: what new functionality should ESI 2.0 support and which of the older features can be dropped? Mark mentions (among others) templating capabilities for the latter and <esi:inline> and the alt-attribute for the former.

Cacheability

Given that the major advantage of integrating services at the edge is leveraging the existing caching architecture the design process of ESI 2.0 requires a close eye on how well the language features can benefit from caching.

Implementability

Whatever the result of an ESI 2.0 design effort, its implementation must be possible using the given architectures of the common open source and non-open source caching products. For example, ESI 2.0 features must not get in the way of an asynchronous request processing model.

An ESI 2.0 Use Case

Yesterday I described an integration scenario where articles in a content management system (CMS) reference (via URIs) company information maintained in another system (CIMS). The articles are published as Web pages and somewhere in the Web page delivery process the company information references are resolved and the returned information is included in the delivered page. The purpose of this setup is twofold: On the one hand the intention is to deliver up to date company information (maybe the stock price is included). On the other hand a clear separation of concerns is achieved, facilitating independent operation and evolution of the two systems.

There are traditionally two approaches for assembling the article Web page from the data provided by the two services: Server Side Templating (e.g. JSPs or Server-Side-Includes) and Client Side Templating (e.g. AJAX or iframes). However, and here is where the topic of this posting comes in again, there is also a third option: assembling the content on the edge, in short: Edge Side Templating.

And this is where Mark’s ideas overlap with mine. (Which I am thankful for because I wasn’t entirely sure until our paths crossed, whether embedding a templating mechanism in a Web cache was actually as useful as I thought)

Regarding the discussion about the pros and cons of doing the templating on the edge please refer to Mark’s posting – in the comments there are a bunch of arguments made already for either side.

Having said all that, let me now talk about what I would like to see in ESI 2.0.

Language Syntax

While in my scenario the including entity (the article referencing the company information) would likely be HTML I have said above that we need something more non-XML friendly. One way would be to reuse the existing ESI XML-tags but explicitly allowing them in non-XML content:

GET /article/123
Host: cms.example.org
 
200 Ok
Content-Type: text/plain
 
ACME in the News
 
<esi:include src="http://cims.example.org/company/acme"/>

(I am deliberately excluding any ESI headers from all the examples)

As far as I can tell at the moment, this would work for non-XML and still allow XML-friendly embedding in XML response entities. If <esi:…> is too likely to overlap with actual content more ‘mangled tags’ would need to be used, e.g. (<% … %>).

Obsolete ESI 1.0 Functionality

There are a number of more or less sophisticated features in ESI 1.0 that are seldom used and in addition are not implemented by many products. Among these are

  • The alt-attribute on <esi:inline>
  • <esi:choose>,<esi:when>,<esi:otherwise>: it is likely that this branching construct can be replaced with functionality that will be in the templating language anyway (as Mark suggests in his posting, showing a dynamicly assembled include target URI: <esi:include src=”/{user_prefs.top_left_module}”/>)
  • <esi:vars>: would likely be changed; I agree with Mark’s suggestions regarding variable handling by the templating language as well as with his ideas on providing better access to the request and response via predefined objects
  • <esi:inline> when you first look at it, it appears rather weired and it took me a while to figure out how inline works. But I think <esi:inline> is pretty useful for emulating batch retrievals. However, what I do not like about it is that it couples the referencing and the referenced systems: they need to agree on where to place the inline elements and that is pure out-of-band information coupling hell. I’d rather like to see the combination of pipelining and caching to handle batch retrieval requirements.

Besides the above, the list of features to drop should of course be driven by what people actually implemented and use today.

But it is time now to turn to the most interesting aspect of all this: new functionality.

Edge-Side-Templating

This is also #1 on Mark’s list and he refers to it as the ability “to source variables from a URI”. The basic idea is this: an ESI element (say <esi:load>) tells the ESI processor to initiate a request to a target resource and make the response entity available as a variable. That variable could then be used in expressions to assemble the overall Web page.

GET /article/123
Host: cms.example.org
 
200 Ok
Content-Type: text/html
 
<html>
 
<h1>ACME in the News</h1>
<p>
<esi:load href="http://cims.example.org/company/acme" var="acme"/>
Yesterday, ${acme.name} (${acme.stock.symbol}) had a closing stock price of ${acme.stock.price}.
</p>
</html>

However, there are two problems with this.

The first problem is that there is code in the ESI processor that needs to parse the response entity of the load-request and make it accessible under the variable name. What syntax would this parser expect? Should JSON be mandatory? Or better: XML and JSON because they can both be turned in a generic fashion into the same variable structure? What if both are not feasible because we do not want to change the server of the loaded resource? I can hear a plugin mechanism or code-on-demand knocking at the door. Welcome complexity and feature bloat…

The second problem is that the code that uses the variable makes assumptions about its structure – apparently based on out-of-band knowledge. This makes my REST alarm bells go off immediately!

A solution to this issue would be to add an accept attribute to <esi:load> that would directly translate to the Accept header of the load-request.

GET /article/123
Host: cms.example.org
 
200 Ok
Content-Type: text/html
 
<html>
 
<h1>ACME in the News</h1>
<p>
<esi:load
  href="http://cims.example.org/company/acme"
  accept="application/company+json"
  var="acme"/>
Yesterday, ${acme.name} (${acme.stock.symbol}) had a closing stock price of ${acme.stock.price}.
</p>
</html>

Ah, yes. That immediately looks nice and RESTful.

Caveat: Do you see the next feature bloat? We could have all sorts of stuff fiddling with the request via more attributes: accept-language,… and then branching based on the response: onContentType=”..” do this or onError=”406″ do that. User Agent scripting, sort of.

It will be a real challenge to pick those features that add real value and maintain simplicity at the same time.

Regarding problem #1 above this might be one of the rare true use cases for the +json and +xml media type suffixes because they provide an elegant way for the ESI processor to pick parsers based on the Content-Type header without entity introspection.

Request- and Response Objects

Mark proposes the addition of prepopulated request- and response objects to obtain request information and set response parameters. I agree that this would be extremely useful (and be far more consistent compared to the current ESI variable set).

However, the same warning applies here: This can end up pretty quickly in a means to script the ESI processor in all sorts of ways and clever balance is required between feature set, and processing performance and implementability.

After all, we want to improve ESI, not put a Java EE container into an HTTP cache…

Timeout and Error Handling

This is also from Mark’s list and pretty important. I wonder whether the cache itself would be allowed to override an timeout attribute on <esi:load> or <esi:include>.

I’ll skip error handling for now – the post has grown far too long already.

Templating Language Functionality

This one though needs particular attention. A templating mechanism immediately raises the question of how much functionality one wants to offer. Variable souring and access is an inherent requirement. Mark also mentions string manipulation functions. For example:

 
<esi:load href="http://cims.example.org/company/acme" var="acme"/>
Yesterday, ${substr(acme.name,0.10)} (${toUpper(acme.stock.symbol)}) had a closing stock price of ${acme.stock.price}.

I think branching and looping constructs also make sense but they might conflict with the intermdiary processing model and request handling performance.

The further new functionality is taken, the closer we get to a full blown scripting engine (e.g. a JavaScript engine) and this sounds definitely not like what we want for ESI 2.0 (..or do we??)

Either way, it is again a tradeoff to be made between the size of the feature set, and implementability and performance.

One additional thing to consider with regard to the feature set is the effect on service independence. If the feature set is too small there might be requirements on the service that manages the loaded resource. For example, if there is no string function to uppercase a string that service owner might receive a request to change to service implementation to also include certain data in uppercase form (because that cannot be done in the ESI processor).

I think that this is the line to draw because it does not make sense to do RESTbased integration to achieve maximal service independence and then let an <esi:include>ing service determine aspects of the implementation of other services. (See the criticism on <esi:inline> above).

That is my take on ESI 2.0 so far.

I would be happy to hear who else is interested in pursuing this further.

UPDATE

Here is a list of issues that come to my mind as I play around with reworking ESI:

  • When ESI elements are not defined to be XML anymore, should the ESI processor apply any encoding found in the XML preamble or should it in any case only apply the one found in the HTTP headers?

A key design aspect that made the very success of the World Wide Web possible was the removal of the referential integrity constraint from the hypermedia paradigm. In a system of the scale of the Web the problem of ensuring that no hyperlink would ever be broken cannot be solved and the only way to make the system work was to relax the constraint.

Instead, the constraint was replaced by a best practice, namely that Cool URIs Don’t Change. Meaning that an origin server that exposes a given URI should continue to do so forever. (This really only applies to URIs that serve as application entry points, aka bookmarkable URIs, but that is a different discussion).

Looking at the title, you might wonder what this has to do with integration? Well, here is the story:

Suppose an integration scenario with two systems, a content management system (CMS) and a system that manages information about companies (let’s call that system CIMS). Authors create article pages in the CMS to be published on the Web as part of a financial news site. Whenever an article talks about a certain company the authors search the CIMS for that company and a reference to the company information in the CIMS is placed in the article. When the article is published, the reference is resolved and some HTML fragment with the company information is embedded in the Web page.

Since the company implementing this scenario does cutting edge integration the CIMS exposes an HTTP interface and the obtained company information references naturally are URIs.

The bottom line: URIs obtained at some point in time are remembered to be dereferenced in the future. This is what is commonly called a bookmark.

The designers of this system, as well as its users, make the assumption that any of the embedded URIs will continue to be the URI of the same company information it was when obtained from the CIMS. In other words, that the mapping of URI to company information will remain stable. This assumption is backed by the aforemetioned best practice of keeping URIs cool.

The consequence is an implicit (you could equally well argue: explicit) obligation on the owner of the origin server (the CIMS in this case) to maintain the URIs – well – indefinitely. And this is something service designers and service owners need to be aware of, especially in an enterprise integration context.

The obligation even exceeds the (probably limited) lifetime of the referenced concept itself (in our case the company information) because the service needs to inform potential clients when there is currently no information available (404 Not Found) or when the information ceased to exist at all (410 Gone). The former case yields a requirement for the client to work around the missing information the latter indicates that the client system should remove the bookmark (here likely indicating a need to rewrite the article).

This last paragraph, BTW, touches only briefly on the topic of how even HTTP error responses are useful (and essential) to the integration quality. (As opposed to a tightly coupled integration style where the client just goes berserk if some piece of information is missing).

Agency Boundary

A central aspect of the problem space that REST is designed for is that the communicating components are typically not owned by a common authority and that therefore change must be enabled to happen without coordinating the change between the authorities. For example, for Amazon it is simply impossible to ask any of its customers whether such and such a change ‘would be ok’.

In my recent presentation on RESTful HTTP I used the term ‘administrative boundary’. Today, I came across the much better term Agency Boundary coined by Rohit Khare and Richard N. Taylor in their ICSE’04 paper Extending the REpresentational State Transfer (REST) Architectural Style for Decentralized Systems:

An agency boundary denotes the set of components operating on behalf of a common (human) authority, with the power to establish agreement within that set and the right to disagree beyond it it.