Access Control for Java Classes
How can we perform authorization of individual Web services within the router servlet in Axis? We have to control access to Java classes this time. Let's examine how JAAS accomplishes authorization over Java classes.
JAAS is an extension of the Java 2 Security Architecture. Historically, Java security has focused on security for mobile code such as Applets. In J2SA terms, permissions are granted to a codebase, the origin of the code that is being executed. Listing 3 is an excerpt from <TOMCAT>/conf/tomcat.policy.
Listing 3: Permission Declaration in a Tomcat Policy File
// Tomcat gets all permissions grant codeBase "file:${tomcat.home}/lib/-" { permission java.security.AllPermission; }; grant codeBase "file:${tomcat.home}/classes/-" { permission java.security.AllPermission; }; // Example webapp policy // By default we grant read access on webapp dir and // write in workdir grant codeBase "file:${tomcat.home}/webapps/examples" { permission java.net.SocketPermission "localhost:1024-", "listen"; permission java.util.PropertyPermission "*", "read"; };
The first and second declarations show that Tomcat system classes are given all permissions. On the other hand, the third grant statement shows that the Tomcat example Web applications can only listen to localhost:1024 and read properties. In other words, they cannot listen to other hosts or ports, read or write files, or do any action other than those specified.
Code-based authorization is useful. But in the case of SOAP messaging using Axis, we need authorization based on the entity that is the origin of the request, also called the (authenticated) requestor. Figure 1 illustrates how a JAAS-based authorization mechanism can be added to Apache Axis. Entities including bold lines are JAAS objects.
Figure 1 Authorization for Axis with JAAS.
The central data structure in JAAS is the subject. A subject is any entity (such as a person or company), and it is represented by a collection of security-related properties such as user ID, group, roles, employee number, and so on. These properties are called principals in the Java 2 Security Architecture. JAAS performs two major tasks: authentication and authorization. The subject is discovered and a subject with associated principals is produced at the authentication phase; then the subject is retrieved and examined, or consumed, at the authorization phase to decide whether the subject can perform the requested action.
Let's review Figure 1 more closely. In the Authentication Handler, we first create a LoginContext and perform login to start authentication. The following is a sample code:
LoginContext lc = null; try { Subject subject = new Subject(); Hashtable hash = new Hashtable(); hash.put("http.username", userid); [ccc] //this value should be taken from the Axis MessageContext [ccc] hash.put("http.password", password); [ccc] // this value is also from the message context subject.getPublicCredentials().add(hash); lc = new LoginContext("AxisLogin", subject); lc.login(); } catch (Exception le) {}
The idea here is that an initial subject is created including BASIC-AUTH information. The user ID might be mapped to another ID for the preceding steps. When you invoke LoginContext.login(), a LoginModule is created and invoked, at which time it creates and attaches principals to the subject (in the case of the AxisLogin login module, these are Axis-specific principals). But these login modules are pluggable, so we can assume that, given our previous scenario, the MyCustomers role will be added to the subject if the HTTP username was bob.
When invoking the service, we call Subject.doAs() so that only authorized subjects will be able to perform the operation. The actual invocation looks like this:
Subject.doAs(subject, new AxisPrivilegedAction(uri,method));
This invocation leads us to the invocation of the run() method in AxisPrivilegedAction. Within the run() method, access permission on the associated resource (specified by a URI and method in the previous program) is checked, and the target method is invoked only if no AccessControlException is thrown. You can implement PrivilegedAction classes in any way. For example, we could have a role-action-mapping database containing triples such as <role, uri, method>, and our action class could check the database to authorize the given request. If the database has a triple of the form <MyCustomers,supplier:po,processpo>, a request to perform a purchase order by bob should be allowed.