Thursday, April 2, 2015

How Java EE translates web.xml constraints to Permission instances

It's a well known fact that in Java EE security one can specify security constraints in web.xml. It's perhaps a little lesser known fact that in full profile Java EE servers those constraints are translated by the container to instances of the Permission class. The specifications responsible for this are Servlet and JACC. This article shows a simple example of what this translation looks like.

Web.xml constraints

We're putting the following constraints in web.xml:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Forbidden Pattern</web-resource-name>
        <url-pattern>/forbidden/*</url-pattern>
    </web-resource-collection>
    <auth-constraint/>
</security-constraint>

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Protected Pattern</web-resource-name>
        <url-pattern>/protected/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>architect</role-name>
        <role-name>administrator</role-name>
    </auth-constraint>
</security-constraint>

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Protected Exact</web-resource-name>
        <url-pattern>/adminservlet</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>administrator</role-name>
    </auth-constraint>
</security-constraint>

<security-role>
    <role-name>architect</role-name>
</security-role>
<security-role>
    <role-name>administrator</role-name>
</security-role>

Java Permissions

Given the above shown constraints in web.xml the following WebResourcePermission instances will be generated, in 3 collections as shown below. For brevity only WebResourcePermission is shown. The other types are omitted.

Excluded

  • WebResourcePermission "/forbidden/*"

Unchecked

  • WebResourcePermission "/:/adminservlet:/protected/*:/forbidden/*"

Per Role

  • architect
    • WebResourcePermission "/protected/*"
  • administrator
    • WebResourcePermission "/protected/*"
    • WebResourcePermission "/adminservlet"

Below is a very short explanation for the different permission types normally used for the translation. The interested reader is suggested to study the Javadoc of each type for more detailed information.


Java EE will generate 3 types of Permission instances when translating constraints expressed in web.xml; WebRoleRefPermission, WebUserDataPermission and WebResourcePermission.

WebRoleRefPermission

A web role ref permission is about mapping Servlet local roles to application roles. Especially with MVC frameworks like JSF and the upcoming JAX-RS based MVC 1.0 the use for this is perhaps questionable, as there's only one Servlet in that case that serves many different views.

WebUserDataPermission

A web user data permission is about the transport level guarantees for accessing resources (practically this almost always means HTTP vs HTTPS). This can be specified using the <user-data-constraint> element in web.xml, which we have omitted here.

WebResourcePermission

The web resource permission is about the actual access to a resource. This can be specified using the <web-resource-collection> element in web.xml, which we have used in the example above.

So let's take a look at what's going on here.

Our first web.xml constraint shown above defined so-called "excluded access", which means that nobody can access the resources defined by that pattern. In XML this is accomplished by simply omitting the auth-constraint element. This was translated to Java code by means of putting a WebResourcePermission with the pattern "/forbidden/*" in the "Excluded" collection. Although there are some differences, this is a reasonably direct translation from the XML form.

The permission shown above for the "Unchecked" collection concerns the so-called "unchecked access", which means that everyone can access those resources. This one wasn't explicitly defined in XML, although XML does have syntax for explicitly defining unchecked access. The permission shown here concerns the Servlet default mapping (a fallback for everything that doesn't match any other declared Servlet pattern).

The pattern used here may need some further explanation. In the pattern the colon (:) is a separator of a list of patterns. The first pattern is the one we grant access to, while the rest of the patterns are the exceptions to that. So unchecked access for "/:/adminservlet:/protected/*:/forbidden/*" means access to everything (e.g. /foo/readme.text) is granted to everyone, with the exception of "/adminservlet" and paths that starts with either "/protected" or "/forbidden". In this case the translation from the XML form to Java is not as direct.

The next two constraints that we showed in web.xml concerned "role-based access", which means that only callers who are in the associated roles can access resources defined by those patterns. In XML this is accomplished by putting one or more patterns together with one or more roles in a security constraint. This is translated to Java by generating {role, permission} pairs for each unique combination that appears in the XML file. It's typically most convenient then to put these entries in a map, with role the key and permission the value, as was done above, but this is not strictly necessary. Here we see that the translation doesn't directly reflect the XML structure, but the link to the XML version can surely be seen in the translation.

Obtaining the generated Permissions

There is unfortunately no API available in Java EE to directly obtain the generated Permission instances. Instead, one has to install a JACC provider that is called by the container for each individual Permission that is generated. A ready to use provider was given in a previous article, but as we saw before they are not entirely trivial to install.

Conclusion

We've shown a few simple web.xml based security constraints and saw how they translated to Java Permission instances.

There are quite a few things that we did not look at, like the option to specify one or more HTTP Methods (GET, POST, etc) with or without the deny uncovered methods feature, the option to specify a transport level guarantee, the "any authenticated user" role, combinations of overlapping patterns with different constraints, etc etc. This was done intentionally to keep the example simple and to focus on the main concept of translation without going in to too many details. In a future article we may take a look at some more advanced cases.

Arjan Tijms

1 comment: