HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

When designing Web-based applications, security is a critical component. Before the advent of J2EE, to implement a secure distributed application you had to code all of the security directly into the application.

J2EE introduced a powerful security infrastructure for applications that greatly assists developers and enterprises in securing their applications. When used properly, this infrastructure takes much of the burden of securing the application off of the developers, leaving them free to concentrate on implementing business logic.

The J2EE container-security services primarily address the security requirements of authentication and authorization. Authentication is the mechanism by which callers and service providers prove to each other that they are acting on behalf of specific users or systems. Authorization mechanisms provide control over what resources an identified user or system has access to. In simple terms, authentication provides the answer to "Who are you?" And authorization provides the answer to "What can you access?"

Authentication
The J2EE model supports several methods for authenticating users. These are basic, digest, form-based, and certificate-based authentications. In basic authentication, the Web server prompts the user for a user name and password, which is then transmitted to the server. Unless an SSL session has been established, this information is sent in the clear, so it's not very secure. Digest authentication improves the security a bit by sending a digest of the user name and password along with some session-specific information to the server instead of transmitting the clear text password.

Both of these methods result in a standard dialog being presented to the user for entering user name and password.

Form-based authentication allows the developer to create a custom log-in page using a form. Like basic authentication, the user name and password are sent in the clear, unless an SSL session has been established.

Finally, the most secure method of authentication is the certificate-based method. In this method, both client and server use X.509 certificates to prove their identities. This authentication always occurs over an SSL-protected channel.

The Web component deployment descriptor specifies which resources are protected, thus requiring user authentication. The actual step of authenticating the user is usually accomplished by looking the user up in a corporate directory or database.

After successfully proving a user's or service's identity, an authentication context is established. This allows the user or service to be authenticated to other entities - without repeating the authentication lookup step. A user may also delegate its authentication context to a component, allowing that component to call another component while impersonating the original caller.

The authentication mechanism is configured in the Web component deployment descriptor. Listing 1 shows an example of configuring digest authentication. Listing 2 shows an example of configuring form-based authentication. The error page specified in Listing 2 is a page presented to the user when authentication fails.

Authorization
J2EE employs a permissions-based authorization model. Each protected resource is listed in the deployment descriptor, along with a list of roles that are able to access the resource. These roles are mapped to specific users by the application deployer. Static pages, JSPs, and servlets are protected at the URL level and can be further protected down to GET or POST methods. Protection of EJBs can be specified down to specific-class methods. Specifying authorization information in the deployment descriptor is referred to as declarative authorization. Embedding authorization logic directly into an application is called programmatic authorization. The J2EE model supports both of these authorization models. Unless requirements demand it, declarative authorization is generally the preferred method.

Declarative Authorization
The authorization rules specified in the deployment descriptor are enforced by the J2EE container. This method of providing authorization frees the developer from worrying about implementing authorization, which is generally a good thing because it's an easy area for developers to introduce bugs that can lead to large security holes in the application. Applications that rely solely on this form of declarative authorization are sometimes referred to as security-unaware applications. The application code itself has no knowledge of the security that is wrapping it. Declarative authorization is a container-managed security service.

Listing 3 shows an example of applying declarative authorization to a servlet in the deployment descriptor. In this example, all servlets and other resources in the "restricted" directory will be protected. Only users assigned the role "AuthorizedUser" will be granted access to these resources. Listing 4 shows declarative authorization being applied to an EJB. This example applies protection to the UserInformation bean. Users assigned the "admin" role are granted rights to access all methods. Users assigned the "customer" role are granted the right to access the getDetails() method.

Programmatic Authorization
The J2EE model also provides support for extending the authorization model through programmatic authorization. There are four key methods developers can use. They are:

  • isCallerInRole() and getCallerPrinciple() for use by EJB code
  • isUserInRole() and getUserPrinciple() for use by Web components
These methods are typically used to provide finer-grain access control than what can be achieved through pure declarative authorization. Applications that employ programmatic authorization are referred to as security-aware applications. Programmatic security is also referred to as application-managed security.

A good example of where programmatic authorization is necessary is in protecting access to user account objects. Consider an application that manages some type of user accounts.

Let's say the developer designates two roles: one for users and the other for administrators. The users should have access only to their own account. The administrators should have access to all accounts. There is no way to enforce this policy using declarative authorization alone. This stems from the fact that access rules specified in the deployment descriptor are class-based, not instance-based. Specific users or roles can't be granted access to specific instances of an object while denying them access to other instances of an object.

A solution is to use programmatic authorization. In the account object, the developer would use the isUserInRole() method to determine if the user was an administrator. If so, the user would automatically be granted access to the account. If not, the developer would then use the method getUserPrinciple() and compare that to the account owner. If they are the same, access would be granted.

Implementing security inside each application greatly increases the chance of introducing a vulnerability that can be exposed by hackers. Programmatic authorization should be used only when the requirements can't be met through declarative authorization.

Confidentiality and Integrity
So far, I've covered the topics of authentication and authorization. The other important security requirement is message protection, specifically, employing the concepts of confidentiality and integrity.

Integrity ensures that a message hasn't been accidentally or intentionally modified. Confidentiality ensures the privacy of a message. Both of these services are provided through cryptographic techniques.

The J2EE security model doesn't provide a great deal of flexibility or support in this area. In the deployment descriptor, resources can be designated as requiring confidentiality. This permits them to be served only over SSL connections. Going beyond the pure J2EE security model, there's a great deal of support in Java for providing programmatic protection of messages.

Divided Responsibilities
One of the goals of the J2EE security model is to lessen the burden on the application developer for securing applications. To assist in achieving this goal, the J2EE model recognizes the three distinct roles played in bringing an application from concept to deployment. The roles are component provider, application assembler, and deployer.

Slight variations on these role names appear in various publications. The component provider is the developer, the person actually writing the Java code. The application assembler takes several components (beans, EJBs, JSPs, etc.) and assembles them into a complete application. Finally, the deployer is responsible for actually deploying the application into the production enterprise environment.

The component provider implements all programmatic security. In doing so, they define generic security role names for providing access control functionality. The application assembler defines logical roles, specifies which resources should be protected, and which roles are required to access those resources. The deployer then is responsible for mapping the logical roles to the specific enterprise environment. It should be noted that one individual or team may play multiple roles in bringing an application to production. It's not unusual for the component provider and the application assembler roles to be performed by the same team.

Container-Managed Security
Implementing modern security mechanisms such as confidentiality, authentication, and authorization requires a great deal of expertise in the security domain. Most application developers don't have the expertise needed to successfully implement these security services. This makes creating applications that are security-aware all the more challenging.

A better idea is to rely on the application-server vendors to implement the tough security services - and have your application make use of these container-managed services. This eliminates the necessity of having a security development engineer on every Web application project.

Having said this, the requirements must be the ultimate driver for whether or not programmatic security should be used. Some requirements, such as the account example given in this article, can't be satisfied using container-managed security alone. It should be noted that this example and the methods provided by J2EE specifically focus on authorization. It's best to always rely on container-managed authentication. Embedding authentication logic into each application creates a hard to manage authentication policy that has a high potential for security vulnerabilities.

Another advantage of relying on containermanaged services is that as authentication technology is upgraded within an enterprise, the applications don't have to be rewritten. Using programmatic authentication would require massive application rewrites if enterprise authentication technology were to change.

Relying predominantly on container-managed security also allows you to maintain a common security infrastructure as opposed to sprinkling security throughout all your Web applications. Container-managed security services allow for the centralization of security policies in a central repository. When using container-managed security, a change in security policy requires changes in application configuration, as opposed to coding changes in your applications.

Author Bio
Timothy Fisher is a consultant for Spherion Technology in Detroit, and has been involved in information-security technology for nearly 10 years. He worked in information security at Motorola, Cyclone Commerce, and Pricewaterhouse Coopers. [email protected]

	


Listing 1 
 
 <web-app> 
 <login-config> 
 <auth-method>BASIC|DIGEST</auth-method> 
 <realm-name>test</realm-name> 
 </login-config> 
 </web-app> 
 
 
 Listing 2 
 
 <web-app> 
 <login-config> 
 <auth-method>FORM</auth-method> 
 <form-login-config> 
 <form-login-page>login.jsp</form-login-page> 
 <form-error-page>error.jsp</form-error-page> 
 </form-login-config> 
 </login-config> 
 </web-app> 
 
 
 Listing 3 
 
 <web-app> 
 .. 
 <security-constraint> 
 <web-resource-collection> 
 <web-resource-name> 
 Secure Content 
 </web-resource-name> 
 <url-pattern>/restricted/*</ url-pattern> 
 </web-resource-collection> 
 <auth-constraint> 
 <role-name>AuthorizedUser</role-name> 
 </auth-constraint> 
 </security-constraint> 
 .. 
 <security-role> 
 <description> 
 The role required to access restricted content 
 </description> 
 <role-name>AuthorizedUser</role-name> 
 </security-role> 
 </web-app>  
 
 Listing 4 
 
 <method-permission> 
 <role-name>admin</role-name> 
 <method> 
 <ejb-name>UserInformation</ejb-name> 
 <method-name>*</method-name> 
 </method> 
 </method-permission> 
 
 <method-permission> 
 <role-name>customer</role-name> 
 <method> 
 <ejb-name>UserInformation</ejb-name> 
 <method-name>getDetails</method-name> 
 </method> 
 </method-permission>

  
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.