|< Free Open Study >|| |
The Servlet 2.3 specification, consistent with J2EE philosophy, prescribes a model that separates the developers from the deployers of a web application:
It is the responsibility of the developers to anticipate how the application will be used after deployment, and to make it flexible enough to adapt to different environments
A deployer is responsible for the deploying the web application to the actual environment within which it will run
Developers will not know ahead of time the specific users that may be using the application but there are many situations in which access to web resources must be partitioned depending on the users involved. For example, if Jane and Jill are peers in the same department, they should not be able to access each other's salary information Accordingly, developers need to be able to build security into the web applications without referring to the actual users who may use the application. The deployer understands the relationships in the deployment environment and so should decide who can access what.
We need to be able to map names to the final users and security principals. These mappable textual names are called roles. For example:
Roles serve as an indirect mapping to users and security principals in the deployed environment.
Roles isolate developers from changes in the physical deployment. For example, a web application developer need only write code that will prevent one worker from accessing another's salary record. The fact that Jane and Jill both map to the role of a worker is not of concern to the developer. The decision to map Jane and Jill to worker is the responsibility of the deployer. We can envision a real life scenario in which Jane gets a promotion and therefore requires a supervisor role. In this case, Jane will be able to access the salary information of Jill because the web application developer has written the code to allow a supervisor role to access the information belonging to a worker.
The fact that a supervisor can access worker's salary records is a business rule. The Servlet 2.3 specification provides mechanisms that make it possible (and easy) to code such business security logic without the need to implement a security infrastructure of our own. The combination of all the business security rules that are implemented in a web application is referred to as the web application's security model.
The Servlet 2.3 specification describes two ways that containers can help in implementing an application's security model. The indirect mapping offered by roles is essential in enabling both:
Declarative security - refers to security constraints that can be configured at deployment time by the deployer. This includes, but is not limited to, mapping roles to users/principals, configuring authentication for certain resources and restricting access to other resources. The deployment descriptor file of the web application is where all of these actions are defined.
Programmatic security - refers to interfaces and methods that a web application developer can use to enforce business security requirements during the coding of the business logic within a web application. Since changes in these rules would require re-writing and recompiling the code, they should be used only when absolutely necessary. However, there are certain situations when implementation via declarative security may be insufficient. For example, if it is absolutely necessary that a worker cannot access the salary information of another worker (even if they are promoted to supervisor) we need to code this within the application.
The Servlet 2.3 specification is careful to avoid platform-specific features. This presents an interesting challenge for Tomcat, a product that is expected to run well across a variety of OS and systems. While the Servlet 2.3 specification describes features in generic terms, the designers of Tomcat 4 must actually ensure that the features work on different platforms.
The Tomcat solution is illustrated in the following figure:
Users to roles mappings are maintained through realms. In programmatic terms, a realm is nothing more than a programming interface. By specifying this interface, and not dictating the means by which this mapping is done, Tomcat can be adapted for new platforms. New means of authentication and roles mapping tracking can be accommodated via the creation of a new realms component, or access can be provided through standard data access interfaces such as JDBC.
By factoring out the means of authenticating a user, and retrieving the role mapping to a user, Tomcat is able to participate in server managed security without being tied down to any specific operating system and or platform implementation.
The programming interface that Tomcat requires every implementation of a realm to support is called org.apache.catalina.Realm. This interface defines the following methods:
public void addPropertyChangeListener()
This adds a listener to monitor property changes in the realm.
public Principal authenticate(String username, String credentials) public Principal authenticate(String username, byte credentials) public Principal authenticate(String username, String digest, String nonce, String nc, String cnonce, String realm, String md5a2,) public Principal authenticate(java.security.cert.X509Certificate certs)
These methods are used to authenticate users and principals using simple credentials, password, RFC 2096, or chains of X.509 certs.
public Container getContainer()
This method returns the container that the realm is operating under.
public String getInfo()
This method returns implementation specific information, including a version number.
public boolean hasRole(Principal principal, String role)
We can use this method to determine if a principal has a certain role within this realm.
public void removePropertyChangeListener(PropertyChangeListener listener)
This method is used to remove a previously registered listener for the realm.
public void setContainer(Container container)
This method sets the container associated with this realm.
The operational model of realms is quite straightforward. On the first access by a user of any declaratively protected resource, the applicable realm's authenticate() method is called. The user's password and roles are then cached by Tomcat for the duration of the session. This means that any database changes will not be visible until the next time authenticate() is called.
While Tomcat provides a means to access realm information for authentication and role query, it does not provide any way of creating and maintaining the information store.
By default an in-memory realm based on an XML file will be used. This base realm is only loaded at Tomcat startup. The static nature of this in-memory realm means that it is only really useful for testing purposes.
Tomcat provides an implementation of a JDBCRealm for use in production systems. A JDBCRealm will access any JDBC source to obtain user-to-roles mapping information. User authentication and role information can be stored in any information store that provides JDBC access.
Since much of the enterprise-based user and access information is accessible via directory services, Tomcat also provides an implementation of a JNDIRealm that can interface to any LDAP accessible directory service.
In an application-hosting environment, we might want to have various levels of administrative users. Some owners may be granted control over certain web applications, others over a complete virtual server. A system-level user may want to have system wide access to some resources, across all virtual hosts, and across all the web applications running within the same engine instance. Realms in Tomcat 4 can be configured to fulfill all of these requirements.
A realm can be defined and associated within the server configuration file (server.xml) with a <Context>, <Host>, or <Engine> element:
When a realm is defined as a sub-element of a <Context> element, it means that the group of users and roles managed by the realm is applicable only within the web application that the <Context> element defines.
When a realm is defined as a sub-element of a <Host> element, it means that the group of users and roles managed by the realm is applicable across the web-applications running under the same virtual host.
When a realm is defined as a sub-element of a <Engine> element, it means that the group of users and roles managed by this realm is across all the applications running across all the virtual hosts running on the same Tomcat instance. This can be used to provide system-administrator-level access to all the applications on a particular Tomcat instance.
Inner scope always overrides outer scope. So, if a JDBCRealm is defined in the <Engine> scope, but subsequently a MemoryRealm is defined in the <Context> scope, users' authentication will be done against the MemoryRealm (and not the global JDBCRealm) for the application associated with the specific <Context>.
Now that we have the authentication database and roles mapping, we need to put protection on some resources. The Servlet 2.3 specification defines two new elements in the deployment descriptor to support this declarative security mechanism. They are <security-constraint> and <login-config>:
The <security-constraint> element specifies what web resources need to be protected, the type of authentication required, and what roles should have access to the resource. This is declarative security in action, also known as container-managed security.
There can be as many <security-constraint> entries in a web.xml file as there are different sets of resources to protect. The <login-config> element specifies the style of authentication required by the application.
Under container-managed security, a J2EE application builder can specify security constraint and role mapping purely using GUI tools and have the container implement the actual access control. The GUI configuration process is the declarative means by which the application deployed can give instructions to the container on how to managed security. While GUI based security administration tools exist for many commercial products, servlet containers are not required to implement them in any standard manner. The Servlet 2.3 specification is the first revision to formalize this as a requirement for every compliant container.
Let's take a look at the sub-elements of a <security-constraint> element:
This is the name for the constraint, typically used by a GUI tool to refer back to this specific constraint.
This specifies a group of resources to protect within a web application. We can use one or more <url-pattern> elements to specify the set(s) of resources. An <http-method> element can also be used to specify the specific HTTP method to constrain (GET or POST, and so on).
This contains <role-name> elements, each of which specifies the role that is allowed to access this constrained set of resources.
This specifies the transport guarantee (via a <transport-guarantee> element) that must be met when access to the resources is attempted. The transport guarantee can be NONE, INTEGRAL, or CONFIDENTIAL. If INTEGRAL or CONFIDENTIAL is applied the access must usually be made through an SSL connection; otherwise the request is refused.
The <login-config> element specifies the authentication method to be used within an application when the container attempts to authenticate a user. Let's take a look at the sub-elements of <login-config>.
The value of this can be one of BASIC, DIGEST, FORM, and CLIENT-CERT.
This is not a Tomcat realm. It is simply a text string that is used when a BASIC authentication dialog is displayed.
If the FORM authentication method is specified, this provides more information on the web page and the error page that will be used during the custom form authentication process.
Since resources in a web application are accessed via HTTP, authentication methods are restricted to those supported by HTTP. The set of authentication methods supported by Tomcat 4 (as defined in the Servlet 2.3 specification) includes:
BASIC Authentication is the most popular form of HTTP authentication around. You've probably experienced BASIC authentication many times: when you reach a web destination, the web browser pops up a dialog box prompting you to enter user name and password. The user name is passed in clear text, and the password is transferred in very easily decoded Base64 encoding. This method of authentication is the least secure, but the most widely supported, of the four.
FORM-based authentication uses a custom form supplied by the web application deployer to perform the actual authentication. Once the user has completed the user and password information in the custom form, the information is sent back to the server for processing. If the authentication fails an error page is displayed to the user. As a standard POST is used to send password information back to the server this is a very weak form of authentication; although the additional protection methods described in the basic authentication section may be used in conjunction with this type of authentication.
In DIGEST authentication, the password is transmitted in an encrypted digest form, using a one-way hash algorithm such as MD5. At the server end, a pre-hashed digest is stored of the password and is compared to the one received. Since the actual password is never transmitted directly, this form of authentication is significantly more secure than BASIC authentication. This form of authentication is not in widespread use, although it is supported in the latest version of most web browsers.
Even though BASIC and FORM-based authentication are not intrinsically strong methods of authentication, they can be made strong by deploying them over a secured transport such as SSL. We can use X.509 client-side certificates to perform client authentication. The server can authenticate a cert passed by the client by:
Verifying that the certificate comes from a trusted CA
Using the CA's public key to validate that the cert has not been tampered with
Checking the cert's expiry date
Checking the client information on the cert (in order to authenticate the client)
The latest versions of Internet Explorer and Netscape both support this feature.
|< Free Open Study >|| |