Exploring EJB security

Securing enterprise data has always been a primary application development concern. This is especially true today in the age of sophisticated cyber-world hackers, phishers, and identity/data thieves. Consequently, security is a major concern in developing robust Java EE solutions. EJB has a security model that is elegant, flexible, and portable across heterogeneous systems.

In the remainder of this topic, we’ll explore some basic security concepts such as authentication and authorization, users, and groups, and we’ll investigate the Java EE/EJB security framework. We’ll also take a look at both declarative and programmatic security in EJB 3.

Let’s start with two of the most basic ideas in security: authentication and authorization.

Authentication vs. authorization

Securing an application involves two primary functions: authentication and authorization. Authentication must be done before authorization can be performed, but as you’ll see, both are necessary aspects of application security. Let’s explore both of these concepts.

Authentication

Authentication is the process of verifying user identity. By authenticating yourself, you prove that you are who you say you are. In the real world, this is usually accomplished through visual inspection/identity cards, signature/handwriting, fingerprint checks, and even DNA tests. In the computer world, the most common method of authentication is by checking username and password. All security is meaningless if someone can log onto a system with a false identity.


Authorization

Authorization is the process of determining whether a user has access to a particular resource or task, and it comes into play once a user is authenticated. In an open system, an authenticated user can access any resource. In a realistic security environment, this all-or-nothing approach would be highly ineffective. Therefore, most systems must restrict access to resources based on user identity. Although there might be some resources in a system that are accessible to all, most resources should be accessed only by a limited group of people.

Both authentication and authorization, but especially authorization, are closely tied to other security concepts, namely users, groups, and roles, which we’ll look at next.

Users, groups, and roles

To perform efficient and maintainable authorization, it is best if you can organize users into some kind of grouping. Otherwise, each resource must have an associated list of all the users that can access it. In a nontrivial system, this would easily become an administrator’s nightmare. To avoid this problem, users are organized into groups and groups as a whole are assigned access to resources, making the access list for an individual resource much more manageable.

The concept of role is closely related to the concept of group, but is a bit tricky to understand. For an EJB application, roles are much more critical than users and groups. To understand the distinction, consider the fact that you might not be building an in-house solution but a packaged Java EE application. Consequently, you might not know the exact operational environment your application will be deployed in once it is purchased by the customer. As a result, it’s impossible for you to code for the specific group names a customer’s system administrator will choose. Neither should you care about groups. What you do care about is what role a particular user in a group plays for your application. In the customer system, user Joe might belong to the system group called peons. Now assume that an ActionBazaar integrated B2B Enterprise Purchasing System is installed on the customer’s site. Among other things, this type of B2B installation transparently logs in all existing users from the customer system into the ActionBazaar site through a custom desktop shortcut. Once logged in, from ActionBazaar’s perspective, Joe could simply be a buyer who buys items online on behalf of the B2B customer company. To another small application in the operational environment, user Joe might be an administrator who changes system-wide settings. For each deployed application in the operational environment, it is the responsibility of the system administrator to determine what system group should be mapped to what application role. In the Java EE world, this is typically done through vendor-specific administrative interfaces. As a developer, you simply need to define what roles your application’s users have and leave the rest to the assembler or deployer. For ActionBazaar, roles can be buyers, sellers, administrators, and so on.

Let’s solidify our understanding of application security in EJB using an Action-Bazaar example.

A security problem in ActionBazaar

At ActionBazaar, customer service representatives (CSRs) are allowed to cancel a user’s bid under certain circumstances (for example, if the seller discloses something in answer to an e-mail question from the bidder that should have been mentioned on the item description). However, the cancel bid operation doesn’t check if the user is actually a CSR as long as the user can locate the functionality on the ActionBazaar site—for example, by typing in the correct URL. Figure 6.4 illustrates the security problem in ActionBazaar.

A clever hacker breaks into the ActionBazaar web server logs and figures out the URL used by CSRs to cancel bids. Using this knowledge, he devises an even cleverer "shill bidding" scheme to incite users to overpay for otherwise cheap items. The hacker posts items on sale and uses a friend’s account to incite a bidding war with genuine bidders. If at any point genuine bidders give up bidding and a fake bid becomes the highest bid, the hacker avoids actually having to pay for the item and losing money in posting fees by canceling his highest fake bid through the stolen URL. No one is any wiser as the genuine bidders as well as the ActionBazaar system think the highest bid was canceled for legitimate reasons. The end result is that an honest bidder is fooled into overpaying for otherwise cheap items.

After a while, ActionBazaar customer service finally catches onto the scheme thanks to a few observant users and makes sure the bid canceling action is authorized for CSRs only. Now if a hacker tries to access the functionality, the system simply denies access, even if the hacker has a registered ActionBazaar account and accesses the functionality through the URL or otherwise. As we discuss how security is managed by EJB in the next section, you will begin to see what an actual solution looks like.

A security breach in ActionBazaar allows a hacker to shill bids by posting an item, starting a bidding war from a fake account and then at the last minute canceling the highest fake bid. The end result is that an unsuspecting bidder winds up with an overpriced item.

Figure 6.4 A security breach in ActionBazaar allows a hacker to shill bids by posting an item, starting a bidding war from a fake account and then at the last minute canceling the highest fake bid. The end result is that an unsuspecting bidder winds up with an overpriced item.

EJB 3 and Java EE security

Java EE security is largely based on the Java Authentication and Authorization Service (JAAS) API. JAAS essentially separates the authentication system from the Java EE application by using a well-defined, pluggable API. In other words, the Java EE application need only know how to talk to the JAAS API. The JAAS API, in contrast, knows how to talk to underlying authentication systems like Lightweight Directory Access Protocol (LDAP), such as Microsoft Active Directory or Oracle Internet Directory (OID) using a vendor plug-in. As a result, you can easily swap between authentication systems simply by swapping JAAS plug-ins without changing any code. In addition to authentication, the application server internally uses JAAS to perform authorization for both the web and EJB tiers. When we look at programmatic EJB security management, we’ll directly deal with JAAS very briefly when we discuss the JAAS javax.security.Principal interface. Feel free to explore JAAS at http://java.sun.com/products/jaas/ since our discussion is limited to what is needed for understanding EJB security.

JAAS is designed so that both the authentication and authorization steps can be performed at any Java EE tier, including the web and EJB tiers. Realistically, however, most Java EE applications are web accessible and share an authentication system across tiers, if not across the application server. JAAS fully leverages this reality and once a user (or entity, to use a fancy security term) is authenticated at any Java EE tier, the authentication context is passed through tiers whenever possible, instead of repeating the authentication step. The Principal object we already mentioned represents this sharable, validated authentication context. Figure 6.5 depicts this common Java EE security management scenario.

As shown in figure 6.5, a user enters the application through the web tier. The web tier gathers authentication information from the user and authenticates the supplied credentials using JAAS against an underlying security system. A successful authentication results in a valid user Principal. At this point, the Principal is associated with one or more roles. For each secured web/EJB tier resource, the application server checks if the principal/role is authorized to access the resource. The Principal is transparently passed from the web tier to the EJB tier as needed.

A detailed discussion of web tier authentication and authorization is beyond the scope of this topic, as is the extremely rare scenario of standalone EJB authentication using JAAS. However, we’ll give you a basic outline of web tier security to serve as a starting point for further investigation before diving into authorization management in EJB 3.

Most common Java EE security management scenario using JAAS

Figure 6.5 Most common Java EE security management scenario using JAAS

Web tier authentication and authorization

The web tier servlet specification (http://java.sun.com/products/servlet/) successfully hides a great many low-level details for both authentication and authorization. As a developer, you simply need to tell the servlet container what resources you want secured, how they are secured, how authentication credentials are gathered, and what roles have access to secured resources. The servlet container, for the most part, takes care of the rest. Web tier security is mainly configured using the login-config and security-constraint elements of the web.xml file. Listing 6.4 shows how securing the administrative module of ActionBazaar might look using these elements.

Listing 6.4 Sample web.xml elements to secure order canceling and other ActionBazaar admin functionality

Listing 6.4 Sample web.xml elements to secure order canceling and other ActionBazaar admin functionalityListing 6.4 Sample web.xml elements to secure order canceling and other ActionBazaar admin functionality

Listing 6.4 specifies how the web container should gather and validate authentication Q. In our case, we have chosen the simplest authentication mechanism, BASIC. BASIC authentication uses an HTTP header-based authentication scheme that usually causes the web browser to gather username/password information using a built-in prompt. Other popular authentication mechanisms include FORM and CLIENT-CERT. FORM is essentially the same as BASIC except for the fact that the prompt used is an HTML form that you create. CLIENT-CERT, on the other hand, is an advanced form of authentication that bypasses username/password prompts altogether. In this scheme, the client sends a public key certificate stored in the client browser to the web server using Secured Socket Layer (SSL) and the server authenticates the contents of the certificate instead of a username/password. The credentials are then validated by the JAAS provider.

Next we specify the realm the container should authenticate against Q. A realm is essentially a container-specific abstraction over a JAAS-driven authentication system. We then specify that all URLs that match the pattern /admin/* should be secured G. Finally, we specify that only validated principals with the CSR role can access the secured pages ©. In general, this is all there really is to securing a web application using JAAS, unless you choose to use programmatic security, which essentially follows the same pattern used in programmatic EJB security.

EJB authentication and authorization

At the time of writing, authenticating and accessing EJBs from a standalone client without any help from the servlet container is still a daunting task that requires you to thoroughly understand JAAS. In effect, you’d have to implement all of the authentication steps that the servlet container nicely abstracts away from you. Thankfully, this task is not undertaken very often and most application servers provide a JAAS login module that can be used by applications.

On the other hand, the authorization model in EJB 3 is simple yet powerful. Much like authorization in the web tier, it centers on the idea of checking whether the authenticated Principal is allowed to access an EJB resource based on the

Principal’s role. Like transaction management, authentication can be either declarative or programmatic, each of which provides a different level of control over the authentication process. In addition, like the transaction management features discussed in this topic, security applies to session beans and MDBs, and not the JPA entities.

We’ll first explore declarative security management by coding our bid-canceling scenario presented in 6.4.3 and then move on to exploring programmatic security management.

Declarative security

Listing 6.5 applies authentication rules to the BidManagerBean that includes the cancelBid method our clever hacker used for his shill-bidding scheme. Now, only CSRs are allowed to use this method. Note that we have omitted method implementation since this is not relevant to our discussion.

Listing 6.5 Securing bid cancellation using declarative security management

Listing 6.5 Securing bid cancellation using declarative security management

Listing 6.5 features some of the most commonly used security annotations defined by common metadata annotations for Java Platform Specification JSR-250, javax. annotation.security.DeclareRoles, javax.annotation.security.RolesAllowed, and javax.annotation.security.PermitAll. Two other annotations that we have not used but will discuss are javax.annotation.security.DenyAll and javax.anno-tation.security.RunAs. Let’s start our analysis of the code and security annotations with the @DeclareRoles annotation.

Declaring roles

We highly recommend that you declare the security roles to be employed in your application, EJB module, EJB, or business methods. There are a few ways of declaring roles, one of which is through the @DeclareRoles annotation, which we use in listing 6.5 Q. This annotation applies at either the method or the class level and consists of an array of role names. We are specifying that the BidManagerBean use the roles of bidder, csr, and admin. Alternatively, we could have specified roles for the entire enterprise application or EJB module through deployment descriptors. The ActionBazaar application could use the roles of guests, bidders, sellers, Power Sellers, CSRs, admins, and so on. If we never declare roles, the container will automatically build a list of roles by inspecting the @RolesAllowed annotation. Remember, when the application is deployed, the local system administrator must map each role to groups defined in the runtime security environment.

Specifying authenticated roles

The @RolesAllowed annotation is the crux of declarative security management. This annotation can be applied to either an EJB business method or an entire class. When applied to an entire EJB, it tells the container which roles are allowed to access any EJB method. On the other hand, we can use this annotation on a method to specify the authentication list for that particular method. The tremendous flexibility offered by this annotation becomes evident when you consider the fact that you can override class-level settings by reapplying the annotation at the method level (for example, to restrict access further for certain methods). However, we discourage such usage because at best it is convoluted and at worst it can cause subtle mistakes that are hard to discern. In listing 6.5, we specify that only CSR and ADMIN roles be allowed to cancel bids through the cancelBid method Q. The @PermitAll and @DenyAll annotations are conveniences that perform essentially the same function as the @RolesAllowed annotation.

@PermitAll and @DenyAll

We can use the @PermitAll annotation to mark an EJB class or a method to be invoked by any role. We use this annotation in listing 6.5 G to instruct the container that any user can retrieve the current bids for a given item. You should use this annotation sparingly, especially at the class level, as it is possible to inadvertently leave security holes if it is used carelessly. The @DenyAll annotation does exactly the opposite of @PermitAll. That is, when used at either the class or the method level, it renders functionality inaccessible by any role. You might be wondering why you would ever use this annotation. Well, the annotation makes sense when you consider the fact that your application may be deployed in wide-ranging environments that you did not envision. You can essentially invalidate methods or classes that might be inappropriate for a particular environment without changing code by using the @DenyAll annotation. Just as with the @RolesAllowed annotation, when applied at the method level these annotations will override bean-level authorization settings.

NOTE The three security annotations, @PermitAll, @DenyAll, and ©Role-Allowed, cannot simultaneously be applied to the same class or the same method.

Let’s now wrap up our discussion of declarative security management by discussing our final annotation, @RunAs.

@RunAs

The @RunAs annotation comes in handy if you need to dynamically assign a new role to the existing Principal in the scope of an EJB method invocation. You might need to do this, for example, if you’re invoking another EJB within your method but the other EJB requires a role that is different from the current Principal’s role. Depending on the situation, the new "assumed" role might be either more restrictive, lax, or neither. For example, the cancelBid method in listing 6.5 might need to invoke a statistics-tracking EJB that manages historical records in order to delete the statistical record of the canceled bid taking place. However, the method for deleting a historical record might require an ADMIN role. Using the @RunAs annotation, we can temporarily assign a CSR an ADMIN role so that the statistics-tracking EJB thinks an admin is invoking the method:

tmp2F452_thumb

You should use this annotation sparingly since like the @PermitAll annotation, it can open up security holes you might not have foreseen.

As you can see, declarative security gives you access to a powerful authentication framework while staying mostly out of the way. The flexibility available to you through the relatively small number of relevant annotations should be apparent as well. If you have ever rolled out your own security or authentication system, one weakness might have crossed your mind already. The problem is that although you can authenticate a role using declarative security, what if you need to provide security settings specific to individuals, or even simple changes in method behavior based on the current Principal’s role? This is where programmatic EJB security steps onto the stage.

Using EJB programmatic security

In effect, programmatic security provides direct access to the Principal as well as a convenient means to check the Principal’s role in the code. Both of these functions are made available through the EJB context. We’ll begin exploring programmatic security by redeveloping the bid-canceling scenario as a starting point. Listing 6.6 implements the scenario.

Listing 6.6 Securing bid cancellation using programmatic security

Listing 6.6 Securing bid cancellation using programmatic security

Listing 6.6 first injects the EJB context Q. We use the isCallerlnRole method of the EJBContext to see if the underlying authenticated principal has the CSR role Q. If it does not, we throw a java.lang.SecurityException notifying the user about the authorization violation Q. Otherwise, the bid cancellation method is allowed to proceed normally. We discuss both the security management related methods provided in the EJB context next, namely isCallerlnRole and getCallerPrincipal.

isCallerlnRole and getCallerPrincipal

Programmatic security is made up solely of the two previously mentioned security-related methods. The methods are defined in the javax.ejb.EJBContext interface as follows:

tmp2F454_thumb

You’ve already seen the isCallerlnRole method in action; it is fairly self-explanatory. Behind the scenes, the EJB context retrieves the Principal associated with the current thread and checks if any of its roles match the name you provided. The getCallerPrincipal method gives you direct access to the java. security.Principal representing the current authentication context. The only method of interest in the Principal interface is getName, which returns the name of the Principal. Most of the time, the name of the Principal is the login name of the validated user. This means that just as in the case of a homemade security framework, you could validate the individual user if you needed to.

For example, let’s assume that we had a change of heart and decided that in addition to the CSRs, bidders can cancel their own bids as long as the cancellation is done within a minute of putting in the bid. We could implement this using the getCallerPrincipal method as follows:

tmp2F455_thumb

Note, though, that there is no guarantee exactly what the Principal name might return. In some environments, it can return the role name, group name, or any other arbitrary String that makes sense for the authentication system. Before you use the Principal.getName method, you should check the documentation of your particular security environment. As you can see, the one great drawback of programmatic security management is the intermixing of security code with business logic as well as the potential hard-coding of role and Principal names. In previous versions of EJB, there was no way of getting around these shortfalls. However, in EJB 3 you can alleviate this problem somewhat by using interceptors. Let’s see how to accomplish this next.

Using interceptors for programmatic security

As you know, in EJB 3 you can set up interceptors that are invoked before and after (around) any EJB business method. This facility is ideal for crosscutting concerns that should not be duplicated in every method, such as programmatic security (discussed in topic 5) . We could reimplement listing 6.6 using interceptors instead of hard-coding security in the business method (see listing 6.7).

Listing 6.7 Using interceptors with programmatic security

Listing 6.7 Using interceptors with programmatic securityListing 6.7 Using interceptors with programmatic security

The SecurityInterceptor class method checkUserRole is designated as Around-Invoke, meaning it would be invoked whenever a method is intercepted Q. In the method, we check to see if the Principal is a CSR Q. If the role is not correct, we throw a SecurityException. Our BidManagerBean, on the other hand, specifies the Securitylnterceptor class as the interceptor for the cancelBid method Q.

Note that although using interceptors helps matters a bit in terms of removing hard-coding from business logic, there is no escaping the fact that there is still a lot of hard-coding going on in the interceptors themselves. Moreover, unless you’re using a simple security scheme where most EJB methods have similar authorization rules and you can reuse a small number of interceptors across the application, things could become complicated very quickly. In effect, you’d have to resort to writing ad hoc interceptors for method-specific authentication combinations (just admin, CSR and admin, everyone, no one, and so on). Contrast this to the relatively simple approach of using the declarative security management annotations or deployment descriptors. All in all, declarative security management is the scheme you should stick with, unless you have an absolutely unavoidable reason not to do so.

Summary

In this topic, we discussed the basic theory of transactions, transaction management using CMT and BMT, basic security concepts, as well as programmatic and declarative security management. Both transactions and security are crosscutting concerns that ideally should not be interleaved with business logic. The EJB 3 take on security and transaction management tries to reflect exactly this belief, fairly successfully in our opinion, while allowing some flexibility.

An important point to consider is the fact that even if you specify nothing for transaction management in your EJB, the container still assumes default transactional behavior. However, the container applies no default security settings if you leave it out. The assumption is that at a minimum, an application server would be authenticated and authorized at a level higher than EJB (for example, the web tier). Nevertheless, we definitely recommend that you not leave yourself vulnerable by ignoring security at the mission-critical EJB layer where most of your code and data is likely to reside. Security vulnerabilities are insidious and you are better safe than sorry. Most importantly, the security features of EJB 3 are so easy to use that there is no reason to risk the worst by ignoring them.

The discussion on security and transactions wraps up our coverage of session and message-driven beans. Neither feature is directly applied to the EJB Persistence API as they were for entity beans in EJB 2. You’ll see why this is the case as we explore the persistence API in the next few topics.

Next post:

Previous post: