Java Security Fundamentals

   

Using Security with Enterprise JavaBeans and J2EE

Security is an important part of the J2EE and EJB specifications, although many EJB developers argue that there is much more that the specifications need to account for from a security perspective. The J2EE 1.3 and EJB 2.0 Specifications are better than the previous versions when it comes to specifying standards for dealing with security issues. Three main security goals are set for the EJB architecture:

  • Lessen the burden placed on the bean provider for dealing with security issues.

  • Allow the EJB applications to be portable across different vendor's servers and allow the different vendors to use different security mechanisms.

  • Allow support for security policies to be set by the deployer or assembler rather than by the bean provider.

The EJB and J2EE specifications describe two entirely different methods of handling security in enterprise beans and in other J2EE components . These two methods are called programmatic and declarative security.

Using Programmatic Security

The EJB 2.0 Specification recommends not using programmatic security in your enterprise beans because it's too easy to couple your application to the physical security environment. If you needed to deploy your application in other security domains with different roles, it might make it necessary to have to change source code to work correctly in this new environment.

Even though it's not recommended, there are still situations that arise that make it necessary to use programmatic security in your applications. Applications should use programmatic security mainly when the declarative method does not offer enough flexibility or when business requirements dictate the need.

For the most part, either an enterprise bean or a servlet can use programmatic security. When doing programmatic security within EJB, you can use the methods defined in the EJBContext interface:

 public boolean isCallerInRole(String roleName);  public Principal getCallerPrincipal(); 

The isCallerInRole method tests whether the principal that made the call to the enterprise bean is a member of the role specified in the argument. The Principal is typically propagated over from another tier , and the security context information resides in the current thread. The following fragment shows an example of how you might use the isCallerInRole method in an enterprise bean:

 //Other enterprise bean code here  //...  public void submitBid( Integer auctionId,       double newBidAmount, String bidderUserName )       throws InvalidBidException, InvalidAuctionStatusException{     // Make sure this user is a valid bidder      if ( !getSessionContext().isCallerInRole( "bidder" )) {       throw new InvalidBidException( "You must register first" );      }      // Get the home interface for the english auction bean      EnglishAuctionHome auctionHome = getEnglishAuctionHome();      try{       // Locate the correct auction        EnglishAuction auction = auctionHome.findByPrimaryKey( auctionId );        // Locate the bidder        Bidder bidder = null;        // Try to submit the bid        auction.submitBid( newBidAmount, bidder );      }catch( FinderException ex ){       ex.printStackTrace();      }catch( RemoteException ex ){       ex.printStackTrace();      }    } 

This is the submitBid method in the AuctionHouseBean class. If the user is not a member of the bidder role, they are not allowed to submit a bid, and an InvalidBidException is thrown. This would force a user to register before submitting bids for an auction.

Depending on the setting in the security-identity element in the bean's deployment descriptor, the getCallerPrincipal method returns the Principal object for the current caller. When the security-identity element has a use-caller-identity value in it, the original caller of the enterprise bean will be propagated when the bean makes calls on itself.

If the deployer specifies a run-as element in the deployment descriptor, a different principal other than the initial caller might be returned from this method. A deployer can set the security-identity to another principal to execute with more permissions than the current caller. For example, it might need to invoke an operation as an administrator, but the operational environment doesn't want to map all callers to this group directly.

The following example shows an example of how you might use the getCallerPrincipal method in an enterprise bean:

 //Other enterprise bean code here  //...  Principal principal = getSessionContext().getCallerPrincipal();  String bidderName = null;  if ( principal != null ) {   bidderName = principal.getName();  }else{   bidderName = "Unknown";  }  // Log the user's bid attempt to a file  String msg = bidderName + " submitted a bid for auction: " + auctionId );  logMessage( msg ); 

Programmatic security is done similarly in a servlet by using these two methods on the HttpServletRequest interface:

 public boolean isUserInRole(String roleName);  public Principal getUserPrincipal(); 

These methods allow the components to make business logic decisions based on the security role of the caller or remote user. Whether the servlet makes a call to a security realm in the application tier or has the information cached on the Web tier is entirely up to the container's implementation.

Caution

The form and context of the principal names will vary greatly depending on the authentication and vendor used.


When an enterprise bean uses the isCallerInRole method within an enterprise bean, the bean provider must declare each security role referenced in the code using the security- role-ref element. The following example illustrates how an enterprise bean's references to security roles are used in the deployment descriptor:

 <ejb-jar>    <enterprise-beans>      ...      <entity>        <ejb-name>EnglishAuction</ejb-name>        ...        <security-role-ref>          <description>The auction restricts some operations to valid bidders          </description>          <role-name>bidder</role-name>        </security-role-ref>        ...      </entity>      ...    </enterprise-beans>    ...  </ejb-jar> 

The deployment descriptor indicates that the enterprise bean EnglishAuction invokes the isCallerInRole method using the role of "bidder." There can be multiple security-role- ref elements for an enterprise bean, one for each different role used as an argument to the isCallerInRole method. The role name is scoped only to the enterprise bean that declares it, so if you use the same role name in a different enterprise bean, you'll need to declare a security-role-ref element in the deployment descriptor for that bean as well.

Using Declarative Security

Declarative security is done by expressing an application's security policy, including which security role or roles have permission to access an enterprise bean, in a form that is completely external to the application code. The application assembler uses one or more security-role elements in the assembly instructions in the deployment descriptor. Here's a sample deployment descriptor that includes a security-role element added by the assembler:

 <ejb-jar>    <enterprise-beans>      ...      <entity>        <ejb-name>EnglishAuction</ejb-name>        ...        <security-role-ref>          <description>The auction restricts some operations to valid bidders          </description>          <role-name>bidder</role-name>          <role-link>registered-bidder</role-link>        </security-role-ref>        ...      </entity>      ...    </enterprise-beans>    <assembly-descriptor>      <security-role>        <description>A role to represent users who have registered with the          system as authorized auction participants        </description>        <role-name>registered-bidder</role-name>      </security-role>    </assembly-descriptor>    ...    ...  </ejb-jar> 

The deployment descriptor includes a security-role element that defines a role of "registered-bidder."

Note

The roles defined in the security-role element do not represent roles in the physical operation environment. They are used only to define a logical security view of an application. They should not be confused with user groups, principals, and other security concepts that exist in the operational environment.


It's also a requirement for the application assembler to map any security-role-ref elements defined by the bean provider to the security-role elements. The assembler does this by inserting a role-link element in the security-role-ref element that references one of the valid security-role elements.

The application assembler is not required to add security-role elements to the deployment descriptor. The reason that the assembler would do it in the first place is to provide information to the deployer so that the deployer doesn't have to have intimate knowledge about what the business methods are for or are doing. If the assembler adds no security-role elements to the deployment descriptor, it's up to the deployer to understand the business methods in the enterprise beans and the operational environment to conduct the mapping. The security-role elements are scoped to the deployment descriptor and would need to be duplicated in other ejb-jar.xml files.

If the application assembler does provide one or more security-role elements in the deployment descriptor, they can also specify the methods of the home and remote interfaces that each role is authorized to invoke. The assembler defines the method permissions in the deployment descriptor using the method-permission element. Each method-permission element can contain one or more security roles and one or more methods. The following illustrates how an assembler might configure the method permissions:

 <ejb-jar>    <enterprise-beans>      ...      <entity>        <ejb-name>EnglishAuction</ejb-name>        ...        <security-role-ref>          <description>The auction restricts some operations to valid bidders          </description>          <role-name>bidder</role-name>          <role-link>registered-bidder</role-link>        </security-role-ref>        ...      </entity>      ...    </enterprise-beans>    <assembly-descriptor>      <security-role>        <description>A role to represent users who have registered with the          system as authorized auction participants        </description>        <role-name>registered-bidder</role-name>      </security-role>      <security-role>        <description>          A role to represent a user who has permission to close an auction        </description>        <role-name>authorized-agent</role-name>      </security-role>    </assembly-descriptor>    ...    ...   <method-permission>    <role-name>registered-bidder</role-name>    <role-name>authorized-agent</role-name>    <method>      <ejb-name>EnglishAuction</ejb-name>      <method-name>getLeadingBid</method-name>    </method>   </method-permission>  </ejb-jar> 

There can be multiple method-permission elements in the deployment descriptor. The method permission for the enterprise beans is defined as the union of all the method permissions defined in the deployment descriptor.

There are three different ways of writing a method-permission element within the deployment descriptor. The first method is used for referring to all the remote and home methods of a specified bean:

 <method-permission>    <role-name>registered-bidder</role-name>    <method>      <ejb-name>AuctionHouse</ejb-name>      <method-name>*</method-name>    </method>  </method-permission> 

The wildcard " * " is used to indicate the roles that can access all the methods on both interfaces. The second style of declaring a method-permission element is

 <method-permission>    <role-name>registered-bidder</role-name>    <method>      <ejb-name>AuctionHouse</ejb-name>      <method-name>submitBid</method-name>    </method>  </method-permission> 

It is used to specify a particular method of the home or component interface. If there are multiple overloaded methods with the same name, this style would grant access to all the different overloaded methods with the same name.

If there are overloaded methods with the same name and you would like to reference a particular method, you can use the third method:

 <method-permission>    <role-name>registered-bidder</role-name>    <method>      <ejb-name>AuctionHouse</ejb-name>      <method-name>submitBid</method-name>      <method-params>        <method-param>java.lang.Double</method-param>      </method-params>    </method>  </method-permission> 

The method-params element contains a list of fully qualified java types of the method's input parameters in order. If you want to choose an overloaded method that takes no parameters, you would have an empty method-params element like this:

 <method-params>  </method-params> 

If the method contains an array, the method-param element would look like this:

 <method-params>    <method-param>int[]</method-param>  </method-params> 

Specifying Identities in the Deployment Descriptor

The application assembler can specify whether the original caller's security identity should be used to execute methods within an enterprise bean or whether a specific run-as identity should be used. This doesn't affect the original caller's permission to call a bean, but it does affect the permissions associated with the bean when it calls other methods or beans. To do this, the assembler uses the security-identity element in the deployment descriptor. The value of this element can either be use-caller-identity or run-as . If run-as is specified, this element must include a role-name entry to define the security identity to be taken on by the bean. Because a message-driven bean doesn't interact directly with a caller, run-as is the only option if you want to control a message-driven bean's security identity. The assembler doesn't have to provide the security-identity element within the deployment descriptor. In this case, it's the responsibility of the deployer to determine which caller identity should be used when one component invokes an operation onto another.

Mapping the Deployment Roles to the Physical Environment

Up to this point in our discussion of setting up and defining the security view of our enterprise beans, we have said that the roles that are defined in the deployment descriptor are just logical roles and that the deployer would be responsible for performing the mapping of these logical roles to the ones that exist in the operational environment. The specifications leave it up to the vendor as to how this happens and, to be quite honest, not many of the vendors have provided a very flexible way to do this for anything but the most trivial security setups.

In some cases, the vendor expects you to put principal names directly into the deployment descriptor for the enterprise bean or servlet. Arguably, this is where EJB shows its immaturity the most. If you build an EJB application that you then sell and install for a customer, you don't want to have to modify the XML deployment descriptors just because the principals are different. Also, what about an existing customer that wants to add or delete an existing principal; does that mean you are going to have to redeploy a component?

You definitely should attempt to follow the intent of the EJB specification or suffer the consequences of lack of portability and interoperability if you don't. In some cases, however, you'll need to think out of the box and provide your own implementation. Security just might be one of those places. The next section discusses how the auction's application needs have some special security requirements and how we'll fulfill those requirements by building in our own security model.



Special Edition Using Enterprise JavaBeans 2.0
Special Edition Using Enterprise JavaBeans 2.0
ISBN: 0789725673
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net