Advanced JavaServer Pages Security
Topics in this Chapter
- Servlet Authentication
- Principals and Roles
- Declarative Authentication
- Portability
- Types of Authentication
- Basic Authentication
- Digest Authentication
- Form-Based Authentication
- SSL and Client Certificate Authentication
- Web Application Security Elements
- Customizing Authentication
- Resin
- Tomcat 4.0
- Programmatic Authentication
Computer security used to be the domain of hackers and their antagonists, but with the advent of the World Wide Web, it's become an issue for the rank and file setting up shop on the net. Because of this growing awareness, software developers today are far more likely to deal with security than were their counterparts of the late 20th century.
Many books have been written about the wide ranging topic of computer security, including Java security, and this chapter is a substitute for none of them. This discussion is restricted to protecting web application resources with the authentication mechanisms described in the servlet specification.1
Servlet Authentication
Servlet authentication looks simple:
A user tries to access a protected resource, such as a JSP page.
If the user has been authenticated, the servlet container makes the resource available; otherwise, the user is asked for a username and password.
If the name and password cannot be authenticated, an error is displayed and the user is given the opportunity to enter a new username and password.
The steps outlined above are simple, but vague. It's not apparent who asks for a username and password, who does the authentication, how it's performed, or even how the user is asked for a username and password. Those steps are unspecified because the servlet specification leaves them up to applications and servlet containers. This vagueness in the servlet specification has an effect on portability; see "Portability" for more information.
Principals and Roles
In security-speak, the user in the steps listed on page 251 is a principal. Principals are named entities that can represent anything; most often, they represent individuals or corporations.
Principals can fill one or more roles; for example, a customer could also be an employee. Security constraints in WEB-INF/web.xml associate roles with protected resources, like this:
<web-app> ... <security-constraint> <!-- web resources that are protected --> <web-resource-collection> <web-resource-name>Protected Resource</web-resource-name> <url-pattern>/page_1.jsp</url-pattern> </web-resource-collection> <auth-constraint> <!-- role-name indicates roles that are allowed to access the web resources specified above --> <role-name>customer</role-name> </auth-constraint> </security-constraint> ... <security-constraint> <!-- web resources that are protected --> <web-resource-collection> <web-resource-name>Protected Resource2</web-resource-name> <url-pattern>/page_2.jsp</url-pattern> </web-resource-collection> <auth-constraint> <!-- role-name indicates roles that are allowed to access the web resources specified above --> <role-name>employee</role-name> </auth-constraint> </security-constraint> <web-app>
Two security constraints are specified above that restrict access to /page_1.jsp and /page_2.jsp to principals that are in roles customer or employee, respectively.
Security constraints, like those listed above, associate resources with roles. It's up to servlet containers or applications to associate roles with principals; for example, with Tomcat, you edit a tomcat-users.xml file that has entries like this:
<tomcat-users> ... <user name="rwhite" password="tomcat" roles="customer", "other"/> ... </tomcat-users>
Here, rwhite has a password of tomcat and can fill roles customer or other; thus, rwhite can access /page_1.jsp, but not /page_2.jsp according to the security constraints listed above.
Other servlet containers provide different mechanisms for associating principals with roles; for example, "Resin" illustrates how it's done with Resin for basic authentication.
Table 9-1 lists HttpServletRequest methods that allow you to retrieve information about principals and roles.
Table 9-1 HttpServletRequest Methods for Principals and Roles
Method |
Description |
Principal getUserPrincipal() |
Returns a reference to a java.security.Principal |
boolean isUserInRole(String) |
Determines whether a user is in a role, specified by the string argument |
String getRemoteUser() |
Returns the username that was used for login |
The servlet API does not provide corresponding setter methods for the getter methods listed in Table 9-1; therefore, principals and roles can only be set by servlet containers, meaning that applications cannot set them. This can be a consideration if you implement programmatic authenticationsee "Programmatic Authentication" for more information.
Table 9-2 lists other ServletRequest methods that provide security information.
Table 9-2 Other ServletRequest Security Methods1
Method |
Description |
String getAuthType() |
Returns the authentication type: BASIC, SSL, or null |
boolean isSecure() |
Returns true if the connection is HTTPS |
String getScheme() |
Scheme represents transport mechanism: http, https... |
Like the methods listed in Table 9-1, the servlet API does not provide corresponding setter methods for those methods listed in Table 9-2. This means that the authentication type and transport scheme can only be set by servlet containers.
Declarative Authentication
Declarative authentication requires no programming because authentication is declared with XML tags in a deployment descriptor and implemented by the servlet container. Declarative authentication is attractive because it's easy, but it's not as flexible as other approaches that require you to write code.
At one end of the spectrum is, declarative authentication, with is 100% servlet container implemented and 0% application code; at the other end is programmatic authentication, with 0% servlet container and 100% application code.
Most servlet containers provide access to the middle of that spectrum by providing hooks so that you can replace their default authentication mechanism.
"Basic Authentication" provides an example of declarative authentication, "Customizing Authentication" illustrates customizing authentication, and programmatic authentication is discussed in "Programmatic Authentication".
Portability
The servlet specification leaves enough security details unspecified that servlet containers must fill in the gaps with nonportable functionality. For example, the servlet specification does not specify a default authentication mechanism, so servlet containers implement their own; for example, Tomcat uses an XML file to specify usernames and passwords, whereas Resin requires you to implement an authenticator.
Because of nonportable security aspects of servlet containers and depending upon your choice for authentication, you may need to write some nonportable code, such as a Resin authenticator or a Tomcat realm, both of which are discussed in "Customizing Authentication".
On the other hand, you can use declarative authentication to minimize any code you have to write.
Types of Authentication
A servlet-based web application can choose from the following types of authentication, from least secure to most:
- Basic authentication
- Form-based authentication
- Digest authentication
- SSL and client certificate authentication
All of the authentication mechanisms listed above are discussed in this chapter. Basic and digest authentication are discussed in much detail in RFC2617, which can be found at ftp://ftp.isi.edu/in-notes/rfc2617.txt.
You select one of the authentication mechanisms listed above in /WEBINF/web.xml, like this:
<web-app> ... <login-config> <auth-method>BASIC</auth-method> <realm-name>Basic Authentication Example</realm-name> </login-config> ... </web-app>
Although basic and form-based authentication are not secure, you can use them in combination with SSL for secure transport.
You can find out the authentication method for a request with HttpServletRequest.getAuthTypesee Table 9-2.