Programming


Programming

Rights for Methods

One method for protecting application systems is to limit access to specific areas of functionality to certain users. The EJB architecture supports such limitations by enabling the definition of roles (which are mapped to existing users). Access to the methods of Enterprise Beans is then allowed only to users with certain defined roles.

In order to limit access to methods in this way, the following steps must be carried out:

  1. Setting up the necessary users and groups via user management. This is external to the EJB container.

  2. Definition of the roles in the assembly descriptor.

  3. Definition of access rights for methods.

  4. Associating the defined roles with the existing users and groups.

In the following we will describe the necessary steps for protecting the methods of the session bean EuroExchangeSL (see the example in Chapter 4, in the section on stateless session beans). Note here that no program lines need to be written for the definition of access rights for methods. This configuration cannot take place until the assembly of the application with the application assembler. Like the transaction context, the security context is implicitly propagated from client to component and between components without the need for the explicit definition of extra parameters in the interfaces of the EJBs.

An application server either has its own user management or uses the user management of another system. Thus an application server could employ the users of the operating system in order to avoid a double management burden. Correspondingly varied are the user interfaces that are employed for user administration. What is common to all of them is that they enable the definition of users and passwords, and structure the users into groups. The example definition in Listing 8-1 provides the users system, UserA, and UserB with passwords and defines a user group Administrators. They will be used again in the course of this chapter. The specific sample used below employs the following naming conventions:

user.<user name>=password and group.<group name>=<group members>.

 

Listing 8-1: Sample user definition for an application server.

start example
user.system=systempassword
user.UserA=password1
user.UserB=password2
group.Administrators=system,
group.AllUsers=system,UserA,UserB,
...
 
end example

The assembly descriptor describes the interplay of all Enterprise Beans in a Java archive (JAR). Here the various user roles are also defined. The roles are also used to restrict access to methods. The example in Listing 8-2 defines the roles everyone and admins.

Listing 8-2: Definition of user roles in the deployment descriptor.

start example
<assembly-descriptor>
  ...
  <security-role>
    <description>
      all users of the euroExchangeBean
    </description>
    <role-name>everyone</role-name>
  </security-role>
  <security-role>
    <description>
      all Administrators
    </description>
    <role-name>admins</role-name>
  </security-role>
  ...
</assembly-descriptor>
 
end example

Access to the Enterprise Bean is configured in such a way that only users with the role everyone can access the bean's methods. The methods for setting the exchange rate are more highly protected, and can be called only by users with the role admins (Listing 8-3).

Listing 8-3: Definition of access rights for methods in the deployment descriptor.

start example
</assembly-descriptor>
  ...
  <method-permission>
    <role-name>everyone</role-name>
    <method>
      <ejb-name>EuroExchangeSL</ejb-name>
      <method-name>
        changeFromEuro
      </method-name>
    </method>
    <method>
      <ejb-name>EuroExchangeSL</ejb-name>
      <method-name>
        changeToEuro
      </method-name>
    </method>
  </method-permission>
  <method-permission>
    <role-name>admins</role-name>
    <method>
      <ejb-name>EuroExchangeSL</ejb-name>
      <method-name>
        setExchangeRate
      </method-name>
    </method>
  </method-permission>
  ...
</assembly-descriptor>
 
end example

The definition of access rights uses the same syntax as the definition of transaction attributes (see Chapter 7). For an Enterprise Bean the rights can be defined for all methods, all methods with a particular name, or one method with a particular name and particular parameters. Moreover, the methods of the home and remote interfaces can be distinguished.

Now the users and groups of the application server will be assigned their roles. This takes place with the deployment tools of the EJB container. Our example (Listing 8-4) shows the assignment using an XML descriptor. Your EJB container's (application server's) administration guide contains precise instructions as to how this step is to be carried out.

Listing 8-4: Sample assignment of roles to users and groups.

start example
<security-role-assignment>
  <role-name>everyone</role-name>
  <principal>UserA</principal>
  <principal>Administrators</principal>
</security-role-assignment>
<security-role-assignment>
  <role-name>admins</role-name>
  <principal>UserB</principal>
  <principal>Administrators</principal>
</security-role-assignment>
 
end example

After all these definitions have been made and the deployment of the Enterprise Bean has again been carried out, the client program can be tested with various users. A prohibited access attempt triggers an exception (java.rmi.RemoteException).

It should be noted that the above mapping solution, although common, does not offer the most complete flexibility. Consider the scenario whereby a user's privilege is to be revoked (such as UserB in the above listing). According to the above configuration, the deployment descriptor would have to be modified and the bean redeployed. This is clearly unmanageable for a system that contains hundreds of users.

An alternative method would be to assign each role to a specific security group and manage this group directly from the underlying security system, such as an LDAP (Lightweight Directory Access Protocol) server. An assignment of roles for this strategy is given in Listing 8-5.

Listing 8-5: Sample alternative assignment of roles to groups.

start example
<security-role-assignment>
  <role-name>everyone</role-name>
  <principal>AllUsers</principal>
</security-role-assignment>
<security-role-assignment>
  <role-name>admins</role-name>
  <principal>Administrators</principal>
</security-role-assignment>

 
end example

If a method is to be executed explicitly without security checking, then it can be given the attribute unchecked in the assembly descriptor. Listing 8-6 shows an example in which the methods changeFromEuro and changeToEuro of the EuroExchangeSL bean can be called without security checking. Any user can call these methods. Only the method setExchangeRate remains limited to users with the role admin.

Listing 8-6: Use of the attribute unchecked in the assembly descriptor.

start example
</assembly-descriptor>
  ...
  <method-permission>
    <unchecked/>
    <method>
      <ejb-name>EuroExchangeSL</ejb-name>
      <method-name>
        changeFromEuro
      </method-name>
    </method>
    <method>
      <ejb-name>EuroExchangeSL</ejb-name>
      <method-name>
        changeToEuro
      </method-name>
    </method>
  </method-permission>
  <method-permission>
    <role-name>admins</role-name>
    <method>
      <ejb-name>EuroExchangeSL</ejb-name>
      <method-name>
        setExchangeRate
      </method-name>
    </method>
  </method-permission>
  ...
</assembly-descriptor>
 
end example

Manual Access Verification

Another way of protecting particular application functions against unauthorized access is to check the identity and roles of the user in the application logic. One can then include additional conditions at run time in checking access rights.

The following steps are necessary if the Enterprise Bean wishes to access the user's identity and roles.

  1. Setting up the requisite users and groups via user management; this is external to the EJB container;

  2. Definition of role references;

  3. Definition of roles in the assembly descriptor;

  4. Assigning of role references to roles;

  5. Use of the methods getCallerPrincipal and isCallerInRole in the application logic of the Enterprise Bean.

The following example uses the same users and groups as the previous example. The final definition of the roles is carried out, as before, by the application assembler. The bean developer therefore does not yet know the names of these roles and must work with provisional names during programming. These provisional names are called role references (security-role-ref). Listing 8-7 defines the two role references exchange and setCurrency for our session bean.

Listing 8-7: Definition of role references in the deployment descriptor.

start example
<enterprise-beans>
  <session>
    ...
    <security-role-ref>
      <description>
        role reference to exchange
      </description>
      <role-name>exchange</role-name>
    </security-role-ref>
    <security-role-ref>
      <description>
        role reference to
        setting the exchange rate
      </description>
      <role-name>setCurrency</role-name>
    </security-role-ref>
    ...
  <session>
</enterprise-beans>
 
end example

Now the names of the defined role references can be used in programming. The EJBContext provides two methods for access to the user:

  • java.security.Principal getCallerPrincipal(): This method returns the identity of the current user as an object of the class Principal. This object can also be used for access control lists.

  • boolean isCallerInRole(java.lang.String name): This method determines whether the current user has a particular role. The name specified here corresponds to the name of the role reference.

The method checkSecureAccess will serve as an example of the use of these methods (see Listing 8-8), which for each access outputs the name of the user over the error output stream (stderr). Additionally, a check is made as to whether the user has the role reference setCurrency. In programming, the names of the role references are used exclusively, and not the roles.

Listing 8-8: Bean method for access protection.

start example
...
public class EuroExchangeBean implements SessionBean {
...
    public void setExchangeRate(String currency, float euro, float foreignCurr)
    {
        if(currency == null) {
            throw new EJBException("illegal argument: currency");
        }
        if(!checkSecureAccess()) {
            throw new EJBException("Access denied");
        }
        ...
    }
    private boolean checkSecureAccess() {
        java.security.Principal principal;
        String name;
        boolean mayAccess;
        mayAccess = ctx.isCallerInRole("setCurrency");
        principal = ctx.getCallerPrincipal();
        name = principal.getName();
        if(mayAccess){
            System.err.println("Accessed granted to " + name);
        } else {
            System.err.println(name + ": Access denied!");
        }
        return mayAccess;
    }
    ...
}

 
end example

It is only after the completion of the Enterprise Bean that the roles are defined and the users and groups assigned to them. Only then have the correct names for the roles used in the program been set. Of course, the program is not changed, but rather the relationship between the role references and the roles is defined. In the example in Listing 8-9 the role reference exchange is assigned to the role everyone, and the role reference setCurrency to the role admins. The deployment descriptor is adapted to this at deployment.

Listing 8-9: Assignment of role references to roles in the deployment descriptor.

start example
<enterprise-beans>
  <session>
    ...
    <security-role-ref>
      <description>
        role for changing from euros
      </description>
      <role-name>exchange</role-name>
      <role-link>everyone</role-link>
    </security-role-ref>
    <security-role-ref>
      <description>
        role for setting the exchange rate
      </description>
      <role-name>setCurrency</role-name>
      <role-link>admins</role-link>
    </security-role-ref>
    ...
  <session>
</enterprise-beans>
 
end example

Figure 8-2 shows once again the chain of mappings. The Enterprise Bean uses the names of the role references (deployment descriptor). These refer to the roles defined at deployment (assembly descriptor). The users (Principal) and groups (Group) of the application server are assigned the roles.

click to expand
Figure 8-2: Chain of mappings for roles.

This chain of mappings is very helpful for the clear distribution of labor between the roles of the bean developer, application assembler, and deployer (see the section in Chapter 3 on EJB assignment of roles). However, for the developer this can mean an additional burden if in the test domain all roles are united in one person.

Enterprise Beans with Defined User Context

When one Enterprise Bean uses another Enterprise Bean, the user context is passed on. The method getCallerPrincipal always returns the user that has registered with the client. This makes an overall security plan possible (Figure 8-3).

click to expand
Figure 8-3: User context in a chain of calls.

With message-driven beans that are not called directly by a user, but through an asynchronous message, the definition of a user is always required.

The defined user is always valid for an entire Enterprise Bean. With session and entity beans the defined user context (Listing 8-10) is used for the execution of all methods of the home and remote interfaces. With message-driven beans the method onMessage is executed with the given user context. Moreover, all Enterprise Beans that are called by another Enterprise Bean with specified user context then work with this user. Such an action makes sense in many applications, for example, when the user works with extended access rights.

Listing 8-10: Definition of a user context for a bean.

start example
<enterprise-beans>
  <session>
    <ejb-name>ejb/EuroExchangeSL</ejb-name>
    ...
    <security-identity>
      <run-as-specified-identity>
        <role-name>Special</role-name>
      </run-as-specified-identity>
    </security-identity>
    ...
  </session>
...
</enterprise-beans>
 
end example

In the extract in Listing 8-11 from the deployment descriptor of the session bean EuroExchangeSL, it is defined that the bean should be executed with the rights of the role Special. These instructions are given by the application assembler. It must also define the associated roles. The following example shows the associated definition for the user Special.

Listing 8-11: Defining the user role Special.

start example
<enterprise-beans>
  <session>
    ...
    <security-role-ref>
      <role-name>Special</role-name>
    </security-role-ref>
    ...
  <session>
<enterprise-beans>

 
end example

Later, the deployer will assign this role to a single user. This user will then be used for execution, and will also be returned as result by the method getCallerPrincipal.

Summary

It would be a mistake to conclude much about the significance of the subject of security in the domain of EJB from the comparatively brief treatment in this chapter. The subject of security was considered very early in the development of Java, where notions of security became a fundamental part of the language. For example, Java contains a security manager that enables the execution of program segments with various access rights and thereby limits access to secure system functions. There are also the earlier-mentioned services and class libraries for authentication, authorization, encryption, and the management of associated objects. Language concepts and services together form a complete security concept.

A J2EE-conforming application server provides an infrastructure for making use of the security services. It implements a user management system or incorporates an existing one such as the operating system security or LDAP server. The application server can be so configured that only encrypted network connections will be accepted by the client. A variety of authentication methods can be supported, such as registration with user name and password or with the use of a certificate.

The application server is responsible for relaying the identity of the user through all levels of the application, for example, to the Enterprise Beans by registration at a web page via JSP, and on to the database or another system. Thus each layer can take over responsibility for security and allow the user more or fewer rights in accessing its functionality.

Even the Enterprise Beans in the EJB container take their share of responsibility for the security of the entire system. Through configuration, access rights for methods can be allocated. Through programming, the identity of the users can be used for decisions in the business logic. Furthermore, the automatic transmittal of the user's identity can be interrupted and a user determined for the execution of an Enterprise Bean. Many other aspects of security do not fall in the area of responsibility of Enterprise Beans, but are taken over by the application server or the persistence systems.

This process works as long as the matter of security is not the actual object of the application. If a management system for certificates is being written or even if only an access control list is to be defined, then the procedures described here are insufficient. In that case an Enterprise Bean will require an additional resource that offers specialized security services. For example, for servicing users, an Enterprise Bean might use a service for user management instead of a database as persistence system. The application server has the task of providing a suitable service that grants the Enterprise Bean access to the users. Through the use of the known resource references this service can be made known to the Enterprise Bean. For the Enterprise Bean to remain portable, one must see to it that the service used is standardized and usable on application servers of other providers.

In summary, one may say that a J2EE-conforming application server supports the development of secure applications from a technical viewpoint. The concepts are suitable for a variety of security strategies and designed to embed the application server in an existing environment. Since this does not go without saying with respect to application servers of other platforms, this fact gives EJB a significant advantage in the marketplace.