The article continues the series discussing J2EE Security and its related concepts. The following brings together the numerous concepts discussed in the past articles.
Hidden-details not directly related to understanding J2EE Security concepts are not discussed here, but rather will considered reference material introduced earlier in the series.
This article discussed Web Application (WAR file) security–EJBs will not be considered. EJBs will be the focus of a future Thinkmiddleware.com effort.
This article is assuming a single J2EE Container with no clustering. Such a configuration provides a whole new dimension of complexity.
We’ll start of with a quick introduction to what J2EE Security is supposed to do for a Web Application. But, first, a few simplifying assumptions are needed:
- Form-based authentication will be used
- OpenLdap will act as the User Repository
- The Declarative Security model will be used.
At a high-level, J2EE Security protecting a web application does the following:
- An (unauthenticated) web client makes a call to a protected resource in a Web Application deployed to a J2EE-compliant Web Container.
- The request is intercepted by the container and the authentication process begins.
The Request is redirected to a login form.
Credentials are submitted by user to the j_security_check servlet
Container authenticates user against OpenLdap
Container builds a JAAS Subject to represent an authenticated user containing User Principal name and Security Attributes.
- The Web Container makes an authorization decision for the requested resource.
An authorization decision is based upon Role membership determined by security attributes associated with the principal during authentication in the last step.
- If the user is authorized, the Container redirects the user to the originally requested resource.
- The user can make calls to authorized EJBs.
In practice, there could be many other technologies used besides EJBs–for example, Web Services.
As such, J2EE Security provides for the authentication and authorization of users attempting to access secured components of a Web Application.
The articles in this series have introduced the constructs J2EE Security needs. The concepts needed to deliver this presentation are briefly reviewed.
Represent something that can be authenticated. This could be a user sitting in front a computer with a web browser opened or it could be an automated system presenting an SSL Client Certificate.
A group is a collection of users or other groups that exist in LDAP. The concept of a group isn’t strictly necessary here, but it is much easier to map a single group to a J2EE Role than it is to map N users.
It should also be noted that we are making an assumption that Groups and Principals are represented by objects in an OpenLdap database. This doesn’t necessary have to be the case, but is a very common use-case and the one being presented here.
A J2EE Developer tasked with assembling a Web Application or a Security Administrator will be responsible for mapping Web Resources in the WAR file to Roles. These Roles are given semantic meaning by the User Repository or Role Mapping mechanism at work in the background. Roles are defined in a web.xml file; they are also referenced in an EAR application.xml file.
A Web Resource is essentially any item in a WAR file that can be called by a web client. Examples include:
- Web Service
- Image file
- HTML file
For our purposes, Authentication is the process by which a calling client proves its identity to the container. This can be done in one of three ways with J2EE Security:
This mechanism relies upon a standard HTML form with specific field names to submit a userid and password is performed by filling out an HTML form and submitting credentials to the j_security_check Servlet (a spec defined servlet that is available through every Web Application).
This authentication mechanism relies upon functionality built into the HTTP Protocol that allows a client to pass a userid and password to a server using the AUTHORIZATION HTTP Header.
SSL Client Certificate
This authentication mechanism is only available to clients communicating with the server via SSL. If the listening endpoint used to access the server requires client authentication (i.e., a client certificate must be presented), then the container must be able to map the certificate DN to a userid. The requirements for how this can be done are somewhat vague. Every J2EE Container implementation has its implementation quirks.
Authorization is the process by which a container determines if an authenticated user has access to a resource based upon information obtained from the User Repository during authentication. In terms of J2EE Security, this means the container determines if the user is a member of the J2EE Role mapped to the requested resource.
Making authorization decisions based upon Role membership is known as Role Based Access Control–or RBAC.
J2EE Security mechanisms are provided by the J2EE Container. This comes in two forms.
Using Declarative Security, security is expressed (or declared) in deployment descriptors (web.xml and application.xml) and enforced by the container. This approach has the benefit of abstracting the security implementation away from the application; however, it still requires having the configuration details in the WAR/EAR file.
Declarative Security is used by the example presented in this series.
There are limits to what J2EE Security’s Declarative Security can accomplish. So, at times, it may be necessary to implement a custom security model or augment the Declarative Security Model by using the Programmatic Security model. For example, perhaps the application requirements call for a limited number of attempted logins when using Form-Based Authentication–Declarative Security alone could not accomplish this.
Programmatic Security allows for security decisions to be made by the application or a module that can be access by the application. The J2EE API provides four methods (two for Servlets, two for EJBs) to aid in implementing custom security solutions, but still make use of the underlying J2EE Security mechanisms:
Bringing It All Together
So, to protect the Subject Application created earlier, we are going provide authentication and authorization of users using J2EE Security.
For the Authentication step, Form-based authentication will be used. The Userid and password will be checked against information in OpenLdap. If authentication is successful, Security Attributes(namely, LDAP Groups) will be associated with the user’s principal that the container can later use in authorization decisions.
For the Authorization step, the container has looked at the application’s deployment descriptor(s) to determine if the requested Resource is protected; so, the user would be authenticated at this point, if needed. If a protected Resource has been called, information in web.xml tells the container what J2EE Role membership is required for access. Depending on the implementation, the J2EE Role can be assumed to directly map to an LDAP Group of the same name or a Role Mapping step must occur. It is generally a good practice to keep your J2EE Roles independent of the LDAP Group definitions (the two will most likely evolve independently). So, a mapping between Roles and Groups must be defined for the application. Finally, inside the User Repository, Users will be mapped to Groups. In this way, J2EE Security establishes a mapping between four entities:
Protected Resources<->J2EE Role<->LDAP Group<->LDAP Users
If the authenticated user is a member of the an LDAP Group that maps to the requested resource’s J2EE Role, then the container will grant access. If not, a permission denied error will be generated.
The J2EE Specification describes a process called Web Single SignOn. As with all things in the J2EE landscape, it is vague, but it hints at a user being able to authenticate once and then be able to access(assuming the user is authorized to access those application) any application that is protected by the same Security Policy Domain.
JBoss Specific Details
JBoss is one implementation of J2EE Security among many. JBoss is our focus here because our example is built around it and it’s OpenSource (read, free). Every J2EE Container implementation is unique. Here are some of the implementation design decisions the JBoss developers made relevant to security.
The authentication-section of the Security Subsystem of JBoss (and J2EE Security) is based upon JAAS–Java Authentication and Authorization Service. This means that a user’s credentials are represented as a JAAS Subject. The JAAS Subject contains Principal objects and Credential objects, which contain Security Attributes. In the out-of-the-box JBoss implementation, there are two Principal objects: SimplePrincipal and SimpleGroup. The first contains the Principal/user name. The latter contains all LDAP Groups and J2EE Roles in which the user has membership.
Thinkmiddleware.com hasn’t published an article on HTTP Session yet. Though, the topic is touched here. The details will be the focus of a future article.
For our purposes, HTTP Session is a mechanism defined in the Servlet Specification that allows for the storage of name-value pairs between HTTP Requests within a single user’s session.
HTTP Session is important in our discussion because JBoss stores a token in HTTP Session that can be used to look up the JAAS Subject in a cache that is maintained by the Security Subsystem.
Tracking HTTP Session is done using a cookie called JSESSIONID by default. The cookie name can be customized. It is also possible to track HTTP Session using a URL rewriting scheme or SSL sessionid. More information about HTTP Session tracking will be covered in a future article.
Since security credentials are tracked using HTTP Session, the JSESSIONID cookie is also used to track security credentials in this example.
To avoid the possibility of session hijacking, all secured applications should be access over an HTTPS connection. It’s not perfect, if your box has been compromised, your session is compromised.