Applications need to prevent improper access to data and ensure that data integrity can be maintained. To guard against such compromises, developers must first have an awareness of resource sensitivity. Proper safeguards need to be in place within the workplace and development process to ensure that sensitive information isn't inadvertently made available for improper viewing and/or modification.
This article describes certain aspects of J2EE declarative security, in particular how security constraints are used within the Web tier to protect access to resources with varying levels of sensitivity. It also illustrates the use of a sample application as a tool for determining the behavior of a given application server's constraint matching. I'll also share some of the issues I encountered while developing and deploying the sample application across several application server platforms.
While the J2EE platform strives to provide an interoperable platform for developing and deploying secure Web applications, ambiguities in the early specifications have led to important implementation differences across vendors. I'll explore some of the effects these differences have on the development of secure, interoperable applications.
Authentication is the act of determining the identity of a user based on the supplied credentials. Determining whether a user should be granted access to protected resources is called authorization.
J2EE uses lazy authentication - users aren't challenged to offer proof of identity until they request access to a protected resource.
Authentication may be performed by an application using one of the following mechanisms:
The J2EE platform prescribes the use of a declarative language within the deployment descriptors of the components to implement container-managed security, also known as declarative security. Along with declarative security, the servlet and EJB specifications require a set of APIs for implementing programmatic security.
- HTTP basic authentication: User's credentials collected by a Web browser
- HTTP digest authentication: Optionally supported by J2EE vendors
- HTTP client authentication: Uses digital certificates
- HTTP form-based authentication: Uses an application form to collect credentials
The language used to declare security policy within Web applications is composed of a set of XML elements within the deployment descriptor web.xml. A typical example of the fundamental element, <security-constraint>, is given in Listing 1. The anatomy of a <security-constraint> declaration consists of a number of subelements that define the implementation of the declared piece of policy.
The Web resource element identifies the criteria from the resource request to be used in determining a match for the resource. In the case of the constraint in Listing 1, a resource, prefix-get-manager, can be identified by a request for any resource that begins with the given URL pattern, in this case a directory structure within the servletPath - in other words, anything within the directory structure /acme/widget relative to the root directory of the application.
The http-method element specifies which type of HTTP request is constrained by this declaration. In this case GET requests are constrained. In short, all HTTP GET requests for resources in the /acme/widget directory of this application are considered a match for this constraint. Four types of URL patterns may be used in the declaration of a security constraint: exact, prefix, extension, and universal. The type of URL pattern specified is important in determining the best match for a particular resource request. This is covered later in the discussion about handling overlapping constraints.
The <auth-constraint> element is used to specify the logical set of privileges required to access any resource for which this constraint is a match. It contains zero or more role-name elements; role-names are used to represent logical sets of privileges. Multiple role-name elements designate an OR relationship for access privileges. In other words, if a particular <auth-constraint> element contains two role-name elements, manager and developer, then users with manager or developer privileges may access the protected resource. In the case of Listing 1, protected resources that match this constraint are accessible only by users with manager privileges.
The <user-data-constraint> element consists of one subelement, <transport-guarantee>. This subelement is used to specify the requirements for the transport or transmission of the resource back to the client. Its value may be one of the following: NONE, INTEGRAL, or CONFIDENTIAL. INTEGRAL and CONFIDENTIAL each declare that a secure method of transport is required for access to the resource. At this time, most implementations implement this declaration by asserting that the request is being made over SSL. The Servlet 2.3 specification states that upon determining that the current transport is inadequate for accessing the requested resource, the servlet container must redirect the request to a secure mechanism - specifically SSL. At the time of this writing, some vendors implement this requirement; others simply deny access to the resource. Either approach protects the resource from inadvertent compromise.
Earlier I mentioned the four types of URL patterns that can be used to match a resource request. The fact is, these URL patterns could result in overlapping constraints - meaning there could be more than one match. This is where it's important to emphasize that the specified algorithm is one of best match, that is, the algorithm must determine which of the set of constraints matching a particular resource request is the most precise. Differences across application server platforms can be found in this area. Being unaware of your vendor's handling of overlapping constraints puts your sensitive resources at risk.
It's extremely important to understand the order of precedence for evaluating URL patterns. The algorithm is intended to be implemented such that (in descending order of precedence):
Using this description of the algorithm, we can define four constraints that would overlap for certain resource requests and describe the expected behavior. Given the constraint declarations in Listing 2, we can trace the matching behavior for a given set of resource requests.
- Exact matches take precedence over prefix and extension matches.
- Prefix matches take precedence over shorter prefix matches and extension matches.
- Extension matches take precedence over universal matches.
- Universal matches, specified with a URL pattern of "/".
First, let's describe the policy that results from the constraint declarations. All HTTP GET requests for resources that end with an .html extension require developer privileges, except for those .html files within the /acme/widget and the /acme directories. The /acme/widget directory requires manager privileges and the /acme directory allows access only to administrators and junior administrators. The /acme/widget/admin.html file is an exception in that it explicitly requires a role of administrator.
HTTP GET requests for resource access to /index.html match the extension-mapping constraint and access is constrained to users with developer privileges.
HTTP GET requests for resource access to /acme/admin.html match the prefix-mapping constraint for the /acme directory and access is granted to users with junior_administrator or administrator privileges.
HTTP GET requests for resource access to /acme/widget/index.html match the prefix-mapping constraint for the /acme/widget directory and access is granted only to users with manager privileges. This match is best because the URL pattern match is longer and therefore more precise than /acme/*.
HTTP GET requests for resource access to /acme/widget/admin.html exactly match the mapping constraint for the /acme/widget/admin.html file and access is granted only to users with administrator privileges. This match is best because it's an exact match between the requested servlet path and the URL pattern, and is therefore more precise than the extension and prefix mappings.
Differences Across Vendors
I mentioned previously some ambiguities in versions of the Servlet specification prior to 2.3 that have led to multiple interpretations of the constraint-matching algorithm and therefore differences in implementation across vendors. It's possible to encounter implementations that are closer to a first-match algorithm than to a best-match. In these cases the search for a match ends immediately on finding a match; that is, there's no attempt to find the most precise match across a set of overlapping constraints. If we look at the previous example, a request for access to /acme/widget/admin.html potentially would grant access to a junior administrator. This is clearly not what is intended by the application developer, as seen by looking at the deployment descriptor.
The provided sample application aids in determining the implementation behavior for any given J2EE application server platform. I'll discuss the development and use of this application shortly.
Compromise Through Configuration
In addition to vendor algorithm differences, it's vitally important to understand that mistakes in the declaration of policy in the deployment descriptors will lead to protected resources being inappropriately available. For instance, developers who want to protect all spreadsheets within an application may be inclined to use an extension-type URL pattern. While this pattern declares that all resources with extensions of type .xls are constrained to users with manager privileges, a prefix constraint for a directory containing spreadsheets has a less restrictive constraint. Listing 3 shows the constraint declarations for this example, which illustrates the importance of understanding the matching algorithm as well as the existing policy language within an application when adding resources to be served by the application. Without realizing that spreadsheets are protected within the application by an extension-type constraint, a developer may add a spreadsheet file to a directory with less restrictive constraints.
Sample Application Goals
The sample was initially intended as an application that would illustrate the behavior of the constraint-matching algorithm. It became clear early on in the testing of the sample that there were differences between application server platforms and that the application could be used to help discern how a given platform would behave.
The application consists of a set of JSP pages that are declared as being of varying levels of sensitivity.
The sample is designed so that it renders the actual constraint that should match to each link within the pages and the expected behavior when the user is logged in with manager privileges and not developer privileges (see Figure 1).
Deployment of Sample Application
To deploy the sample application to your environment:
1. Download the sample application, in the form of a standard WAR file.
2. Deploy the application according to your application server's deployment instructions. If you need to acquire an application server to run the sample, see the resources section at the end of the article.
3. Have a user with manager (not developer) privileges available.
Running the Sample Application
To run the sample:
1. Start the application server.
2. Initiate a request for the default welcome file with http://localhost:9090/constraintmatching, where the port is determined by the application server (HP-AS uses 9090 and Tomcat uses 8080 out of the box).
3. Log in as the user with manager privileges.
4. Use the links on the subsequent pages, observing the behavior and comparing it with the expected outcome described in the pages.
I learned a number of lessons with regard to interoperability during the development of the sample application. Since the application was developed using HP-AS 8.0, the sample deployed and ran flawlessly on this platform. It was during the testing of the application on Jakarta Tomcat and BEA WebLogic Server 6.1 that I realized changes were needed to maximize interoperability.
The most significant changes were required for deploying the application to Apache's Jakarta Tomcat environment. Given the application's initial deployment descriptor, it was obvious that the algorithm wasn't implemented as expected. A post to the Tomcat developer mailing list quickly resolved the issues.
The implementation, as expected, follows the guidelines outlined by the Servlet 2.3 expert group. Though the specification clearly reads as a best-match algorithm, the expert group agreed that the Tomcat and J2EE 1.2 and 1.3 beta reference implementations' constraint processing, being first-match, was simple and sufficient.
Tomcat's implementation of the constraint-matching algorithm requires that the constraints appear within the deployment descriptor in the order of precedence required for the different types of URL patterns, including the need to sort prefix-type constraints by URL pattern length. This is not an intuitive requirement; I'm more inclined to logically group constraints based on the URL pattern or the <auth-constraint> so as to make the policy more readable. Tomcat's implementation is a first-match algorithm rather than a best-match, and this is why the constraints need to be so ordered. It seems to me that this implementation is more error-prone than implementing the algorithm directly in the container. It does give the well-informed developer the ability to tweak the algorithm by ordering the constraints in the desired order of precedence; however, it renders the access policy nonportable.
For deployment on BEA WebLogic Server 6.1, there was a bit of annoyance in that WLS uses the realm-name element within the login-config to determine the WLS realm implementation for authentication. Once that was resolved and changed in the deployment descriptor, the application ran fine. One interesting behavior seen in WLS and not HP-AS or Tomcat was that when an authenticated user has inadequate privileges to access a resource, the user is asked to reauthenticate. The other platforms tested simply deny access.
Another difference that was uncovered results from having multiple constraints of equal type match a given request. The Servlet 2.3 specification isn't clear on how to handle this situation. The deployment descriptor of the sample application has two constraints that are identical except in the <transport-guarantee> declaration. On HP-AS and Tomcat the first of the two best-matching constraints is selected due to the algorithm implementation for each of the application servers. WLS apparently maps the constraint internally such that identical constraints, in terms of URL pattern and http-method, overwrite each other. This leads to selection of the last-matching constraint. Currently, this type of configuration should be considered programmer error; as a result, since it isn't clear what an application server should do in this event, resources may be accessible differently across application servers. The specification should specify that ambiguous constraints - even when a result of programmer error - be handled a particular way. This is likely to be addressed in an effort currently under way under the Java Community Process (JCP).
The deployment descriptor for the sample was changed to specify "filerealm\" as the realm-name, because this is the default realm for WLS out of the box, and HP-AS and Tomcat don't require anything in particular. In addition, the two prefix-type constraints that match the same request have been ordered to align with the behavior of HP-AS and Tomcat when processing multiple constraints for a given request. To make the deployment descriptor more portable, these constraints should be consolidated into one. I've left that as an exercise for the reader.
For additional fun with the sample application, change the order of the constraints in the web.xml file and observe behavior changes - especially within Tomcat.
The most important lesson learned is that, due to the differences across vendors, the development of portable applications requires specific ways of declaring policy and structuring the directories within an application.
Developers should provide resources within a flatter directory structure and place the constraints in the deployment descriptor in the order of precedence instead of having directories and subdirectories with varying levels of sensitivity, break these into separate directory structures off the application root. A directory structure such as /public/manager/administrator, for example, should be broken into three separate directories, for example, /public, /manager, and /administrator.
Ordering of constraints within the deployment descriptor should be as follows:
Also, due to the way that multiple matches for the same URL patterns and HTTP methods are handled across vendors, developers should consider the declaration of multiple constraints of the same type for a given URL pattern/http-method combination as an error in declaration. That is, until there are specific tests for these cases in the Technology Compatibility Kits (TCK) for the Servlet/J2EE specifications. J2EE 1.4 should contain rigorous tests in all these areas. Until then, developers need to ensure that there is only one constraint that will be considered the best match for any given request.
- Exact matches
- Prefix matches
- Extension matches
- Finally, universal match
As development tools for J2EE application development, assembly, and deployment mature, much of the direct editing of the deployment descriptors is eliminated - possibly making it more difficult to police these issues. Be aware of how your tool orders the constraints within the deployment descriptor so as to ensure policy portability across vendors.
A Brighter Future
An effort is under way within the JCP to formalize a contract between container vendors and authorization service providers. While this effort is focused primarily on the integration of external security providers, J2SE and J2EE, and application servers with enterprise policy infrastructure, there is an important side effect that will aid in the area of constraint processing. In order to license the technology of this effort, authorization providers and applications server vendors alike will need to pass the TCK that corresponds to the SPI contract. This TCK will also be included in the J2EE 1.4 TCK and provide rigorous tests of security constraint processing. Therefore, J2EE 1.4 will offer a more portable environment for J2EE declarative security.
The realization of a secure, interoperable Web application development platform is within reach. In the meantime, care must be taken in defining policy through the declarative language built into the J2EE platform so that portability across vendors will be maintained. In addition, careful evaluation of an application's declared policy, along with knowledge of the vendor's algorithm implementation, is required to deploy existing applications with protected resources to new application server platforms.
HP-AS 8.0 - the free J2EE Application Server: www.hpmiddleware.com
Apache Jakarta Tomcat: http://jakarta.apache.org/tomcat
BEA WebLogic Server: www.bea.com
Servlet 2.3 Specification: http://jcp.org/aboutJava/communityprocess/first/jsr053/index.html
Larry McCay, a senior architect for Hewlett-Packard, has been designing and developing software for over 10 years. Larry has been a major contributor to the Hewlett-Packard Application Server and Netaction Platform and is active within the JCP in the area
Download Source Files (~ 10.2 KB ~Zip File Format)