Security is a fairly broad topic and may encompass everything from encryption to personalization, depending on how "security" is defined. This chapter focuses on the levels of security that you can implement to secure your Struts applications, beginning in this section with an overview of the various security levels. That is followed by sections that look in depth at using container-managed security and application-managed security, the two primary ways to secure your Struts applications.
Transport-level security using HTTPS
Authentication and authorization
Role-based access control
Some aspects of personalization-specifically, some techniques for hiding or displaying content based on a user's authorization-will also be covered.
Data can be securely transmitted by using HTTP over Secure Socket Layer (referred to as HTTPS). HTTPS secures data by encrypting the protocol at the transport level. In other words, the entire HTTP conversation between the client browser and the Web server is encrypted. Struts applications, like most Web applications, can send data over HTTPS without modification.
HTTPS does impact performance, however. There is an order of magnitude of performance penalty when using HTTPS. To reduce the impact on performance, it is common for applications to switch the protocol between HTTP and HTTPS. The typical scenario uses the HTTPS protocol for application login and submission of sensitive data. Once the data has been transmitted, the protocol is switched back to HTTP. While on the surface this seems like a good approach, it leaves open a serious security hole whereby the user's session can be hijacked. Sensitive user information, such as a credit card number, may be stored in that session. A network snoop could use the session ID to spoof a valid user session. Due to this risk, container-managed security does not support protocol switching. However, if you need protocol switching and can accept the security risks, there are mechanisms for doing so that integrate with Struts, as you will see in "Integrating Struts with SSL," later in this chapter.
Authentication is the process of proving to an application that you are who you say you are. For Web applications, this process is most commonly associated with entering a username and password. If you are registered as a user of the application and you provide a valid password, the application allows access to privileged features of the application. In contrast, if you cannot provide valid credentials, you are allowed access only to the public areas of the site. In fact, many Web applications may only allow authenticated access-with the only public page being the login screen. Authentication can be provided through custom coding for the application, or by using container-managed security services.
Authorization is how the application determines which aspects of the Web application you are allowed to access. Generally speaking, determining a user's authorization requires the user to first be authenticated. At that point, application-provided or container-managed security can be used to determine a user's authorization.
Role-based access control (RBAC) is a common scheme for implementing authorization. Users are assigned roles through a container-specific means. When a user is authenticated, the user's roles are associated with the HTTP request. Given this information, access to certain pages or user interface components can be allowed or disallowed based on the user's roles. In most cases, a user is allowed to have multiple roles. However, roles are typically flat; that is, there is no hierarchical relationship between roles.
Servlet containers provide security as specified by the servlet specification. Container-managed security allows the developer to declaratively specify how authentication is to be performed and how authorization is to be granted. Container-managed security provides an easy, unobtrusive way of adding security to an application. This mechanism of implementing security provides the following benefits:
It is declarative. Authentication and authorization are specified in the web.xml file. Container-specific details, such as the security realm, typically are configured in server-specific XML configuration files.
It supports multiple authentication schemes, such as password authentication, FORM-based authentication, authentication using encrypted passwords, and authentication using client-side digital certificates.
Using container-specific security realms, user data can be provided by a variety of stores, including flat files, relational databases, and Lightweight Directory Access Protocol (LDAP) servers.
Redirects are handled automatically. In other words, the container determines when a user is accessing a protected URL, prompts for user credentials, and, if authenticated, redirects to the requested page. This is a powerful mechanism, particularly for applications that publish links to protected pages in e-mail communications.
Containers are, however, somewhat limiting because of the following:
The implementation of container-managed security varies by container. An application using container-managed security generally requires modification at some level when ported from one application server to another.
The login flow does not allow easy custom processing of login requests. In other words, additional processing cannot be performed in the authentication process.
Authorization can only use a flat, role-based approach. Access to Web pages cannot be granted based on multiple factors, for example, a managerial level and a department number.
FORM-based login forces a workflow that uses a separate page for login. This limits the flexibility of the application.
Container-managed authentication requires changes to the application server's configuration that may not be allowed in a hosted environment.
These limitations can be overcome by using application-managed security. However, using application-managed security means that custom code must be designed and written. The decision of which approach to take should be driven by the requirements. While container-managed security is simpler to implement, it does restrict the flexibility of your security policy. One container's security implementation may be different from another's, making your application less portable. Also, container-managed security limits you to a specific login workflow that may not be what you want for your application.
Application-managed security, on the other hand, allows you to implement your security policy as needed at the price of requiring more custom code. Struts mitigates this problem by allowing for customized role processing via a chain command (or a custom request processor in versions of Struts prior to 1.3). Also, servlet filters can be used to apply across-the-board security policies. Cookies can be used to persist user login information between sessions. In addition, there are Struts extensions that permit finer-grained control of the use of HTTPS.
One last point: there is a somewhat hybrid approach that allows programmatic access to the methods that are usually only available when using container-managed security. This interesting mechanism will be covered later in the chapter, in the section "Using Servlet Filters for Security."