Java EE 6: Application Security Enhancements
Java Enterprise Edition Version 6 (JEE6) release includes new security features in the areas of web container security as well as authentication and authorization aspects in Java application development. These features include programmatic and declarative security enforcement in the web tier.
Based on Servlet 3.0 specification (JSR 315), the Java EE 6 Web applications can take advantage of the new programmatic and declarative security features and Security annotations previously available to EJB 3.x applications. The web applications can also use JSR 196 based pluggable authentication/authorization modules that can be configured as part of the servlet container.
Web Module Security
Web module security can be implemented programmatically (using the new security methods added in HTTP Servlet Request) as well as in a declarative manner (using the new security annotations).
The container security context can be accessed programmatically using the new methods available in the HTTP servlet request. Servlet 3.0 specifies the following methods in HttpServletRequest interface that can be used to authenticate users in a web application.
- authenticate: This method uses the container login mechanism configured for the ServletContext to authenticate the user making the request. It may modify and commit the HttpServletResponse. If the basic authentication type is configured in the application, a login dialog box is displayed to collect the user name and password for authentication purposes.
- login: The login method validates the provided username and password in the security realm used by the web container. It allows the application to capture user name and password information as an alternative to specifying form-based authentication in an application deployment descriptor, but also gives the developers programmatic control over the authentication process.
- logout: This method allows a web application to reset the caller identity of a request and establish null as the value returned when other methods like getUserPrincipal, getRemoteUser and getAuthType are called on the request.
The following HttpServletRequest interface methods are also available to access security information about the component’s caller:
- getRemoteUser: This method is called to get the user name with which the client authenticated. It returns the name of remote user associated by the container with the request. If no user has been authenticated, the method returns null.
- isUserInRole: This method determines whether a remote user is in a specific security role. If no user has been authenticated, it returns false. This method expects a String user role-name parameter. The security-role-ref element should be declared in the deployment descriptor with a role-name sub-element containing the role name to be passed to the method.
- getUserPrincipal: The getUserPrinicipal method is called to determine the principal name of the current user and returns a java.security.Principal object. If no user has been authenticated, it returns null. Calling the getName method on the Principal returned by getUserPrincipal returns the name of the remote user.
There are new annotations that can be used to enforce security in the web modules. We can apply authentication, authorization and transport level encryption using the provided annotations and deployment descriptors. The new Java EE 6 annotations are as follows:
- @ServletSecurity: The @ServletSecurity is used on a Servlet implementation class to specify security constraints to be enforced by the servlet container on HTTP protocol messages. The Servlet container will enforce these constraints on the url-patterns mapped to the servlets.
- @HttpMethodConstraint: The @HttpMethodConstraint annotation is used within the ServletSecurity annotation to represent security constraints on specific HTTP protocol messages. It’s an array specifying the HTTP method specific constraint.
- @HttpConstraint: This annotation is used within the ServletSecurity annotation to represent the security constraints to protect all HTTP methods for which a corresponding HttpMethodConstraint element is not specified within the ServletSecurity annotation.
- @DeclareRoles: The @DeclareRoles is a class level annotation, which is part of Common Annotations 1.0 (JSR 250) specification, that acts like security-role element in defining the roles used in application. It should be defined prior to referencing any role.
- @RunAs: The @RunAs annotation, also part of Common Annotations 1.0, specifies the run-as role for the given components. You can specify whether a caller’s security identity should be used for the execution of specified methods of an enterprise bean, or whether a specific run-as identity should be used. This annotation also has a class scope.
If the web application consists of a servlet, use the @HttpConstraint and, optionally, the @HttpMethodConstraint annotation within the @ServletSecurity annotation to specify a security constraint. For other web applications, use a security-constraint element in the deployment descriptor.
Declaring Security Roles
The security role names can be declared using the security-role element of deployment descriptor. A security role reference defines a mapping between the name of a role that is called from a web component using isUserInRole(String role) and the name of a security role that has been defined for the application. For example, to map the security role reference "cust" to the security role with role name "bankCustomer", the syntax would be:
<servlet> ... <security-role-ref> <role-name>cust</role-name> <role-link>bankCustomer</role-link> </security-role-ref> ... </servlet>
If the servlet is called by a user who belongs to "bankCustomer" security role, the method call isUserInRole("cust") returns true. The role-link element in the security-role-ref element must match a role-name defined in the security-role element of the same web.xml deployment descriptor, as shown here:
<security-role> <role-name>bankCustomer</role-name> </security-role>
Enforcing Transport Security
Transport security ensures that no one can tamper with the data being sent to a client or data received from a client. Java EE specification lets the developers enforce the transport security using "user data constraint" and "transport guarantee" elements in web.xml file or using the "transportGuarantee" attribute of HttpConstraint annotation. A user data constraint establishes a requirement that the constrained requests be received over a protected transport layer connection. The strength of the required protection is defined by the value of the transport guarantee. Following are the values defined in TransportGuarantee inner class:
- CONFIDENTIAL: This transport guarantee is used to establish a requirement for confidentiality part of the content. It guarantees that the data is encrypted so that it cannot be deciphered by third parties.
- NONE: This transport guarantee level does not apply SSL, and lets the data transport happen as usual. It indicates that the container must accept the constrained requests when received on any connection including an unprotected one.
We can enforce transport security in web.xml using the "user-dataconstraint" element which should be placed inside the security-constraint tag containing the resource which need transport protection. For example we can add the following snippet inside the security-constraint to enforce use of SSL when user is accessing managed resources.
<user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint>
For more information on Java EE 6 security features, check out the Security chapters in Servlet 3.0 specification document (Chapter 13) and Java EE 6 Tutorial (Chapter 24) . DZone has also recently published a reference card on the Java EE security enhancements (Note: Registration is required to download the document from their website) .
getUserPrincipal().getName() - oops. NPE
If getUserPrincipal() were to return a "Guest" this might be safer.
Even more radical, why not drop the "get" altogether, and just call the method user() - so you end up with
its a bit easier on the eye....
What about JSF
Re: What about JSF
Without breaking old functionality adding an extra method like 'isUserInRole(authorizeUnauthenticaedUsers : boolean)' that could return true even for unauthenticated users would make conditional authentication requirements easily portable between application servers within the jee spec.