Enterprise applications provide business logic support functionality for an enterprise, typically in commercial organizations, to improve the enterprise's productivity and efficiency. Services provided by enterprise applications are typically business-oriented applications such as online shopping and online payment processing, interactive product catalogue, automated billing systems, security, content management, CRM, ERP, Business Intelligence, HR management, manufacturing, EAI, Enterprise Forms Automation, etc. Enterprise applications typically have interfaces to other enterprise software (for example, from a database to Enterprise JavaBeansTM) and are centrally managed. [Enterprise software. (2009, October 20). In Wikipedia, The Free Encyclopedia. Retrieved 19:41, October 29, 2009, from http://en.wikipedia.org/w/index.php?title=Enterprise_software]
The following parties are responsible for administering security for enterprise applications:
System Administrator
The system administrator is responsible for setting up a database of users and assigning those users to the proper group. The system administrator is also responsible for setting properties on the Enterprise Server that enable the applications to run properly. In terms of security, some examples include setting up a default principal to role mapping, anonymous users, default users, and propagated identities. More information on system administrator responsibilities is found in Sun GlassFish Enterprise Server v3 Administration Guide. When needed for this tutorial, the steps for performing specific steps will also be provided herein.
Application Developer/Bean Provider
The application developer/bean provider is responsible for annotating the classes and methods of the enterprise application in order to provide information to the deployer about which methods need to have restricted access. This tutorial describes the steps necessary to complete this task.
Deployer
The deployer is responsible for taking the security view provided by the application developer and implementing that security upon deployment. This document provides the information needed to accomplish this task for the tutorial example applications. For more information on deployment, the best source for the Enterprise Server is the Sun GlassFish Enterprise Server v3 Application Deployment Guide.
Enterprise beans are Java EE components that implement Enterprise JavaBeans (EJB) technology. Enterprise beans run in the EJB container, a runtime environment within the Enterprise Server. Although transparent to the application developer, the EJB container provides system-level services such as transactions and security to its enterprise beans, which form the core of transactional Java EE applications.
Enterprise bean methods can be secured using one of the following methods:
Declarative Security (preferred)
Declarative security enables the application developer to specify which users are authorized to access which methods of the enterprise beans, what type of authentication will be used, and whether or not the protected data will use a secure connection.
In older versions of Java EE, declarative security was specified in the application deployment descriptor. A deployment descriptor is an XML file that is external to the application and expresses, among other things, an application's security structure. With the introduction of Java EE 5, metadata annotations (or simply, annotations,) were introduced to specify which users were authorized to access protected methods of the enterprise applications. Beginning with Java EE 6, the presence of an annotation in the business method of an enterprise application that specifies method permissions is all that is needed for method protection and authentication in some situations. This section discusses this simple and efficient method of securing enterprise beans
There are some limitations to the simplified method of securing enterprise beans, so there are some instances where you would want to continue to use the deployment descriptor to specify security information. An authentication mechanism must be configured on the server for the simple solution to work. The Enterprise Server assumes a default authentication method of basic authentication, but not all servers are configured for a default authentication mechanism, in which case you would need to use a vendor-specific deployment descriptor to specify an authentication method. Using deployment descriptors to specify security information for enterprise applications is discussed in Part VII, Security, in The Java EE 6 Tutorial, Volume II.
For this tutorial, we will describe how to invoke username-password authentication of authorized users by decorating the enterprise application's business methods with annotations that specify method permissions. To make the deployer's task easier, the application developer can define security roles. A security role is a grouping of permissions that a given type of users of the application must have in order to successfully use the application. For example, in a payroll application, there will be users who want to view their own payroll information (employee), user who need to view others payroll information (manager), and users who need to be able to change others payroll information (payrollDept). The application developer would determine who the potential users of the application would be, and which methods would be accessible to which users. The application developer would then decorate classes or methods of the enterprise bean with annotations that specify the types of users authorized to access those methods. Using annotations to specify authorized users is described in Specifying Authorized Users by Declaring Security Roles.
When one of the annotations is used to define method permissions, the deployment system will automatically require username-password authentication. Username-password authentication is used often in applications. In this type of authentication, a user will be prompted to enter their username and password. These will be compared against a database of known users. If the user is found and the password matches, the roles that the user is assigned will be compared against the roles that are authorized to access the method. If the user is authenticated and found to have a role that is authorized to access that method, the data will be returned to the user.
Using declarative security is discussed in Securing an Enterprise Bean Using Declarative Security and Annotations.
Programmatic security is code that is embedded in a business method, is used to access a caller's identity programmatically, and uses this information to make security decisions within the method itself. Programmatic security is useful when declarative security alone is not sufficient to express the security model of an application.
In general, security management should be enforced by the container in a manner that is transparent to the enterprise beans' business methods. The programmatic security API's described in this chapter should be used only in the less frequent situations in which the enterprise bean business methods need to access the security context information, such as when you want to grant access based on the time of day (or other nontrivial condition checks) for a particular role.
Programmatic security is discussed in Securing an Enterprise Bean Programmatically.
Some of the material in this chapter assumes that you have already read Chapter 23, Introduction to Security in the Java EE Platform, Chapter 14, Enterprise Beans, and Chapter 15, Getting Started with Enterprise Beans.
As mentioned earlier, enterprise beans run in the EJB container, a runtime environment within the Enterprise Server, as shown in Figure 24–1.
This section discusses how to secure a Java EE application where one or more modules (such as EJB JAR files) are packaged into an EAR file, the archive file that holds the application. Security annotations will be used in the Java programming class files to specify authorized users and basic, or username-password, authentication.
Enterprise beans often provide the business logic of a web application. In these cases, packaging the enterprise bean within the web application's WAR module simplifies deployment and application organization. Enterprise beans may be packaged within a WAR module as Java programming language class files or within a JAR file that is bundled within the WAR module. When a servlet or JSP page handles the web front-end, and the application is packaged into a WAR module as a Java programming class file, then security for the application can be handled in the application's web.xml file. The EJB in the WAR file can have its own deployment descriptor, ejb-jar.xml, if required. Securing web applications using web.xml is discussed in Chapter 25, Getting Started Securing Web Applications and Part VII, Security, in The Java EE 6 Tutorial, Volume II.
The following sections describe declarative and programmatic security mechanisms that can be used to protect enterprise bean resources. The protected resources include methods of enterprise beans that are called from application clients, web components, or other enterprise beans.
You can protect enterprise beans by doing the following:
You should also read JSR-318: Enterprise JavaBeans 3.1 for more information on this topic. This document can be downloaded from http://jcp.org/en/jsr/detail?id=318. Chapter 17 of this specification, Security Management, discusses security management for enterprise beans.
Declarative security enables the application developer to specify which users are authorized to access which methods of the enterprise beans, and to authenticate these users with basic, or username-password, authentication.
Frequently, the person who is developing an enterprise application is not the same person who is responsible for deploying the application. When an application developer uses declarative security to define method permissions and authentications mechanisms, they are passing along to the deployer a security view of the enterprise beans contained in the EJB JAR. When a security view is passed on to the deployer, the deployer uses this information to define method permissions for security roles. If you don’t define a security view, the deployer will have to determine what each business method does to determine which users are authorized to call each method.
A security view consists of a set of security roles, a semantic grouping of permissions that a given type of users of an application must have to successfully access the application. Security roles are meant to be logical roles, representing a type of user. You can define method permissions for each security role. A method permission is a permission to invoke a specified group of methods of the enterprise beans’ business interface, home interface, component interface, and/or web service endpoints. After method permissions are defined, username-password authentication will be used to verify the identity of the user.
It is important to keep in mind that security roles are used to define the logical security view of an application. They should not be confused with the user groups, users, principals, and other concepts that exist in the Enterprise Server. An additional step is required to map the roles defined in the application to users, groups, and principals that are the components of the user database in the file realm of the Enterprise Server. These steps are outlined in Mapping Security Roles to Enterprise Server Groups.
The following sections show how an application developer uses declarative security to either secure an application or to create a security view to pass along to the deployer.
This section discusses how to use annotations to specify the method permissions for the methods of a bean class. If you'd like more information on these annotations, refer to JSR-250 Common Annotations for the Java Platform.
Method permissions can be specified on the class, the business methods of the class, or both. Method permissions can be specified on a method of the bean class to override the method permissions value specified on the entire bean class. The following annotations are used to specify method permissions:
This annotation is used to specify all of the roles that will be used by the application, including roles not specifically named in a RolesAllowed annotation. The set of security roles used by the application is the total of the security roles defined in the @DeclareRoles and @RolesAllowed annotations.
The @DeclareRoles annotation is specified on a bean class, where it serves to declare roles that can be tested (for example, by calling isCallerInRole) from within the methods of the annotated class. When declaring the name of a role used as a parameter to the isCallerInRole(String roleName) method, the declared name must be the same as the parameter value.
Here is some example code that demonstrates the use of the DeclareRoles annotation.
@DeclareRoles("BusinessAdmin") public class Calculator { public void convertCurrency() { if(x.isUserInRole("BusinessAdmin")) { //.... } } //... }
The syntax for declaring more than one role is as shown in the following example:
@DeclareRoles({"Administrator", "Manager", "Employee"})
@RolesAllowed("list-of-roles")
The @RolesAllowed annotation specifies the security roles permitted to access method(s) in an application. This annotation can be specified on a class or on method(s). When specified at the class level, it applies to all methods in the class. When specified on a method, it applies to that method only, and overrides any values specified at the class level.
To specify that no roles are authorized to access method(s) in an application, use the @DenyAll annotation. To specify that a user in any role is authorized to access the application, use the @PermitAll annotation.
When used in conjunction with the @DeclareRoles annotation, the combined set of security roles are used by the application.
Here is some example code that demonstrates the use of the RolesAllowed annotation.
@RolesAllowed("AllUsers") public class Calculator { @RolesAllowed("Administrator") public void setNewRate(int rate) { //.. }
The @PermitAll annotation specifies that all security roles are permitted to execute the specified method(s). The user is not checked against a database to ensure that this user is authorized to access this application.
This annotation can be specified on a class or on method(s). Specifying this annotation on the class means that it applies to all methods of the class. Specifying it at the method level means that it applies to only that method.
Here is some example code that demonstrates the use of the PermitAll annotation.
import javax.annotation.security.*; @RolesAllowed("RestrictedUsers") public class Calculator { @RolesAllowed("Administrator") public void setNewRate(int rate) { //... } @PermitAll public long convertCurrency(long amount) { //... } }
The @DenyAll annotation specifies that no security roles are permitted to execute the specified method(s). This means that these methods are excluded from execution in the Java EE container.
Here is some example code that demonstrates the use of the DenyAll annotation.
import javax.annotation.security.*; @RolesAllowed("Users") public class Calculator { @RolesAllowed("Administrator") public void setNewRate(int rate) { //... } @DenyAll public long convertCurrency(long amount) { //... } }
The following code snippet demonstrates the use of the @DeclareRoles annotation with the isCallerInRole method. In this example, the @DeclareRoles annotation declares a role that the enterprise bean PayrollBean uses to make the security check using isCallerInRole("payroll") to verify that the caller is authorized to change salary data.
@DeclareRoles("payroll") @Stateless public class PayrollBean implements Payroll { @Resource SessionContext ctx; public void updateEmployeeInfo(EmplInfo info) { oldInfo = ... read from database; // The salary field can be changed only by callers // who have the security role "payroll" if (info.salary != oldInfo.salary && !ctx.isCallerInRole("payroll")) { throw new SecurityException(...); } ... } ... }
The following example code illustrates the use of the RolesAllowed annotation:
@RolesAllowed("admin") public class SomeClass { public void aMethod () {...} public void bMethod () {...} ... } @Stateless public class MyBean extends SomeClass implements A { @RolesAllowed("HR") public void aMethod () {...} public void cMethod () {...} ... }
In this example, assuming aMethod, bMethod, and cMethod are methods of business interface A, the method permissions values of methods aMethod and bMethod are @RolesAllowed("HR") and @RolesAllowed("admin") respectively. The method permissions for method cMethod have not been specified.
To clarify, the annotations are not inherited by the subclass per se, they apply to methods of the superclass which are inherited by the subclass.
The Enterprise Server assigns users to principals or groups, rather than to security roles. When you are developing a Java EE application, you don’t need to know what categories of users have been defined for the realm in which the application will be run. In the Java EE platform, the security architecture provides a mechanism for mapping the security roles defined in the application to the users, principals, or groups defined in the runtime realm. The deployer will work with the security view provided by the application developer to implement this mapping.
One way to declare a mapping between a security role used in the application and one or more groups and/or principals defined for the applicable realm of the Enterprise Server is to use the security-role-mapping element in the runtime deployment descriptor (sun-application.xml, sun-web.xml, or sun-ejb-jar.xml.) This is the method to use when the role name defined in the application does not match the group or principal name defined for the Enterprise Server. An example of this role mapping can be found in Part VII, Security, in The Java EE 6 Tutorial, Volume II.
In the tutorial, the role names used in the application are the same as the group names defined on the Enterprise Server. Under these circumstances, you can enable a default principal-to-role mapping on the Enterprise Server using the Admin Console. To enable the default principal-to-role-mapping, follow these steps:
Start the Enterprise Server, then the Admin Console.
Expand the Configuration node.
Select the Security node.
On the Security page, check the Enabled box beside Default Principal to Role Mapping.
When method permissions are specified, basic, username-password, authentication will be invoked by the Enterprise Server.
If you would like to specify a different type of authentication, or to require a secure connection using SSL, you would specify this information in an application deployment descriptor. Using application deployment descriptors is discussed in Part VII, Security, in The Java EE 6 Tutorial, Volume II.
This section discusses how to configure an enterprise bean for username-password authentication. When a bean that is constrained in this way is requested, the server requests a user name and password from the client and verifies that the user name and password are valid by comparing them against a database of authorized users on the Enterprise Server.
If the topic of authentication is new to you, please refer to the section titled Specifying an Authentication Mechanism.
This example demonstrates security by starting with the unsecured enterprise bean application, cart, which is found in the directory tut-install/examples/ejb/cart/ and is discussed in The cart Example.
In general, the following steps are necessary to add username-password authentication to an existing application that contains an enterprise bean.
Create an application like the one in The cart Example.
If you have not already done so, complete the steps inSetting Up Your System for Running the Security Examples to configure your system for running the tutorial applications.
Modify the source code for the enterprise bean, CartBean.java, to specify which roles are authorized to access which protected methods. This step is discussed in Annotating the Bean.
Build, package, and deploy the enterprise bean, then build and run the client application by following the steps in Building, Deploying, and Running the Secure Cart Example Using NetBeans IDE or Building, Deploying, and Running the Secure Cart Example Using Ant.
The source code for the original cart application was modified as shown in the following code snippet (modifications in bold, method details are removed to save space). The resulting file can be found in the following location:
tut-install/examples/ejb/cart-secure/cart-secure-ejb/src/java/cart/ ejb/CartBean.java
The code snippet is as follows:
package cart.ejb; import cart.util.BookException; import cart.util.IdVerifier; import java.util.ArrayList; import java.util.List; import javax.ejb.Remove; import javax.ejb.Stateful; import javax.annotation.security.RolesAllowed; @Stateful public class CartBean implements Cart { String customerName; String customerId; List<String> contents; public void initialize(String person) throws BookException { if (person == null) { throw new BookException("Null person not allowed."); } else { customerName = person; } customerId = "0"; contents = new ArrayList<String>(); } public void initialize(String person, String id) throws BookException { if (person == null) { throw new BookException("Null person not allowed."); } else { customerName = person; } IdVerifier idChecker = new IdVerifier(); if (idChecker.validate(id)) { customerId = id; } else { throw new BookException("Invalid id: " + id); } contents = new ArrayList<String>(); } @RolesAllowed("TutorialUser") public void addBook(String title) { contents.add(title); } @RolesAllowed("TutorialUser") public void removeBook(String title) throws BookException { boolean result = contents.remove(title); if (result == false) { throw new BookException("\"" + title + "\" not in cart."); } } @RolesAllowed("TutorialUser") public List<String> getContents() { return contents; } @Remove() @RolesAllowed("TutorialUser") public void remove() { contents = null; } }
The @RolesAllowed annotation is specified on methods for which you want to restrict access. In this example, only users in the role of TutorialUser will be allowed to add and remove books from the cart, and to list the contents of the cart. An @RolesAllowed annotation implicitly declares a role that will be referenced in the application; therefore, no @DeclareRoles annotation is required. The presence of the @RolesAllowed annotation also implicitly declares that authentication will be required for a user to access these methods. If no authentication method is specified in the deployment descriptor, the type of authentication will be username-password authentication.
Follow the instructions for building, deploying, and running the secure cart example by following the instructions in Building, Packaging, Deploying, and Running the cart Example,
Follow the instructions for building, deploying, and running the secure cart example by following the instructions in Building, Packaging, Deploying, and Running the cart Example. Enter your user name and password when prompted to do so.
Programmatic security is code that is embedded in a business method, is used to access a caller's identity programmatically, and uses this information to make security decisions within the method itself.
In general, security management should be enforced by the container in a manner that is transparent to the enterprise beans’ business methods. The security API described in this section should be used only in the less frequent situations in which the enterprise bean business methods need to access the security context information, such as when you want to restrict access to a particular time of day.
The javax.ejb.EJBContext interface provides two methods that allow the bean provider to access security information about the enterprise bean’s caller.
java.security.Principal getCallerPrincipal();
The purpose of the getCallerPrincipal method is to allow the enterprise bean methods to obtain the current caller principal’s name. The methods might, for example, use the name as a key to information in a database.
The following code sample illustrates the use of the getCallerPrincipal() method:
@Stateless public class EmployeeServiceBean implements EmployeeService{ @Resource SessionContext ctx; @PersistenceContext EntityManager em; public void changePhoneNumber(...) { ... // obtain the caller principal. callerPrincipal = ctx.getCallerPrincipal(); // obtain the caller principal’s name. callerKey = callerPrincipal.getName(); // use callerKey as primary key to find EmployeeRecord EmployeeRecord myEmployeeRecord = em.find(EmployeeRecord.class, callerKey); // update phone number myEmployeeRecord.setPhoneNumber(...); ... } }
In this example, the enterprise bean obtains the principal name of the current caller and uses it as the primary key to locate an EmployeeRecord entity. This example assumes that application has been deployed such that the current caller principal contains the primary key used for the identification of employees (for example, employee number).
boolean isCallerInRole(String roleName);
The enterprise bean code can use the isCallerInRole(String roleName) method to allow the bean provider/application developer to code the security checks that cannot be easily defined using method permissions. Such a check might impose a role-based limit on a request, or it might depend on information stored in the database.
The enterprise bean code can use the isCallerInRole(String roleName) method to test whether the current caller has been assigned to a given security role. Security roles are defined by the bean provider or the application assembler, and are assigned to principals or principal groups that exist in the operational environment by the deployer.
The following code sample illustrates the use of the isCallerInRole(String roleName) method:
@Stateless public class PayrollBean implements Payroll { @Resource SessionContext ctx; public void updateEmployeeInfo(EmplInfo info) { oldInfo = ... read from database; // The salary field can be changed only by callers // who have the security role "payroll" if (info.salary != oldInfo.salary && !ctx.isCallerInRole("payroll")) { throw new SecurityException(...); } ... } ... }
You would use programmatic security in this way to dynamically control access to a method, for example, when you want to deny access except during a particular time of day. An example application that uses the getCallerPrincipal and isCallerInRole methods is described in Example: Using the isCallerInRole and getCallerPrincipal Methods.
This example demonstrates how to use the getCallerPrincipal() and isCallerInRole(String role) methods with an enterprise bean. This example starts with a very simple EJB application, converter, and modifies the methods of the ConverterBean so that currency conversion will only occur when the requester is in the role of TutorialUser.
The source code for the original converter application was modified as shown in the following code snippet (modifications in bold) to add the if..else clause that tests if the caller is in the role of TutorialUser. If the user is in the correct role, the currency conversion is computed and displayed. If the user is not in the correct role, the computation is not performed, and the application displays the result as 0.
The code snippet is as follows:
package converter.secure.ejb; import java.math.BigDecimal; import javax.ejb.*; import java.security.Principal; import javax.annotation.Resource; import javax.ejb.SessionContext; import javax.annotation.security.DeclareRoles; import javax.annotation.security.RolesAllowed; @Stateless() @DeclareRoles("TutorialUser") public class ConverterBean{ @Resource SessionContext ctx; private BigDecimal yenRate = new BigDecimal("96.0650"); private BigDecimal euroRate = new BigDecimal("0.0078"); @RolesAllowed("TutorialUser") public BigDecimal dollarToYen(BigDecimal dollars) { BigDecimal result = new BigDecimal("0.0"); Principal callerPrincipal = ctx.getCallerPrincipal(); if (ctx.isCallerInRole("TutorialUser")) { result = dollars.multiply(yenRate); return result.setScale(2, BigDecimal.ROUND_UP); }else{ return result.setScale(2, BigDecimal.ROUND_UP); } } @RolesAllowed("TutorialUser") public BigDecimal yenToEuro(BigDecimal yen) { BigDecimal result = new BigDecimal("0.0"); Principal callerPrincipal = ctx.getCallerPrincipal(); if (ctx.isCallerInRole("TutorialUser")) { result = yen.multiply(euroRate); return result.setScale(2, BigDecimal.ROUND_UP); }else{ return result.setScale(2, BigDecimal.ROUND_UP); } } }
After you've made the changes to the enterprise bean, follow the instructions in Compiling, Packaging, and Running the converter Example.
After you've made the changes to the enterprise bean, follow the instructions in Compiling, Packaging, and Running the converter Example.
Problem: The application displays zero values after authentication, as shown here:
appclient-command-common: [exec] $100.00 is 0.00 Yen. [exec] 0.00 Yen is 0.00 Euro. |
Solution: Verify that the user name and password that you entered for authentication match a user name and password in the Enterprise Server, and that this user is assigned to the group named TutorialUser. User names and passwords are case-sensitive. Read Adding Users to the Enterprise Server for more information on adding users to the file realm of the Enterprise Server.
You can specify whether a caller’s security identity should be used for the execution of specified methods of an enterprise bean, or whether a specific run-as identity should be used.
Figure 24–2 illustrates this concept.
In this illustration, an application client is making a call to an enterprise bean method in one EJB container. This enterprise bean method, in turn, makes a call to an enterprise bean method in another container. The security identity during the first call is the identity of the caller. The security identity during the second call can be any of the following options:
By default, the identity of the caller of the intermediate component is propagated to the target enterprise bean. This technique is used when the target container trusts the intermediate container.
A specific identity is propagated to the target enterprise bean. This technique is used when the target container expects access using a specific identity.
To propagate an identity to the target enterprise bean, configure a run-as identity for the bean as discussed in Configuring a Component’s Propagated Security Identity.
Establishing a run-as identity for an enterprise bean does not affect the identities of its callers, which are the identities tested for permission to access the methods of the enterprise bean. The run-as identity establishes the identity that the enterprise bean will use when it makes calls.
The run-as identity applies to the enterprise bean as a whole, including all the methods of the enterprise bean’s business interface, home interface, component interface, and web service endpoint interfaces, the message listener methods of a message-driven bean, the time-out callback method of an enterprise bean, and all internal methods of the bean that might be called in turn.
You can configure an enterprise bean’s run-as, or propagated, security identity using the @RunAs annotation. The RunAs annotation defines the role of the application during execution in a Java EE container. It can be specified on a class, allowing developers to execute an application under a particular role. The role must map to the user/group information in the container's security realm. The RunAs annotation specifies the name of a security role as its parameter.
Here is some example code that demonstrates the use of the RunAs annotation.
@RunAs("Admin") public class Calculator { //.... }
You will have to map the run-as role name to a given principal defined on the Enterprise Server if the given roles associate to more than one user principal. Mapping roles to principals is described in Part VII, Security, in The Java EE 6 Tutorial, Volume II.
When an enterprise bean is designed so that either the original caller identity or a designated identity is used to call a target bean, the target bean will receive the propagated identity only; it will not receive any authentication data.
There is no way for the target container to authenticate the propagated security identity. However, because the security identity is used in authorization checks (for example, method permissions or with the isCallerInRole() method), it is vitally important that the security identity be authentic. Because there is no authentication data available to authenticate the propagated identity, the target must trust that the calling container has propagated an authenticated security identity.
By default, the Enterprise Server is configured to trust identities that are propagated from different containers. Therefore, there are no special steps that you need to take to set up a trust relationship.
The deployer is responsible for ensuring that an assembled application is secure after it has been deployed in the target operational environment. If a security view has been provided to the deployer through the use of security annotations and/or a deployment descriptor, the security view is mapped to the mechanisms and policies used by the security domain in the target operational environment, which in this case is the Enterprise Server. If no security view is provided, the deployer must set up the appropriate security policy for the enterprise bean application.
Deployment information is specific to a web or application server. Please read the Sun GlassFish Enterprise Server v3 Application Deployment Guide for more information on deploying enterprise beans.
Web applications may accept unauthenticated web clients and allow these clients to make calls to the EJB container. The EJB specification requires a security credential for accessing EJB methods. Typically, the credential will be that of a generic unauthenticated user. The way you specify this credential is implementation-specific.
In the Enterprise Server, you must specify the name and password that an unauthenticated user will use to log in by modifying the Enterprise Server using the Admin Console:
Start the Enterprise Server, then the Admin Console.
Expand the Configuration node.
Select the Security node.
On the Security page, set the Default Principal and Default Principal Password values.
The Java EE authentication requirements for application clients are the same as for other Java EE components, and the same authentication techniques can be used as for other Java EE application components.
No authentication is necessary when accessing unprotected web resources. When accessing protected web resources, the usual varieties of authentication can be used, namely HTTP basic authentication, SSL client authentication, or HTTP login form authentication. These authentication methods are discussed in Specifying an Authentication Mechanism.
Authentication is required when accessing protected enterprise beans. The authentication mechanisms for enterprise beans are discussed in Securing Enterprise Beans. Lazy authentication can be used.
An application client makes use of an authentication service provided by the application client container for authenticating its users. The container’s service can be integrated with the native platform’s authentication system, so that a single sign-on capability is employed. The container can authenticate the user when the application is started, or it can use lazy authentication, authenticating the user when a protected resource is accessed.
An application client can provide a class to gather authentication data. If so, the javax.security.auth.callback.CallbackHandler interface must be implemented, and the class name must be specified in its deployment descriptor. The application’s callback handler must fully support Callback objects specified in the javax.security.auth.callback package. Gathering authentication data in this way is discussed in the next section, Using Login Modules.
An application client can use the Java Authentication and Authorization Service (JAAS) to create login modules for authentication. A JAAS-based application implements the javax.security.auth.callback.CallbackHandler interface so that it can interact with users to enter specific authentication data, such as user names or passwords, or to display error and warning messages.
Applications implement the CallbackHandler interface and pass it to the login context, which forwards it directly to the underlying login modules. A login module uses the callback handler both to gather input (such as a password or smart card PIN) from users and to supply information (such as status information) to users. Because the application specifies the callback handler, an underlying login module can remain independent of the various ways that applications interact with users.
For example, the implementation of a callback handler for a GUI application might display a window to solicit user input. Or the implementation of a callback handler for a command-line tool might simply prompt the user for input directly from the command line.
The login module passes an array of appropriate callbacks to the callback handler’s handle method (for example, a NameCallback for the user name and a PasswordCallback for the password); the callback handler performs the requested user interaction and sets appropriate values in the callbacks. For example, to process a NameCallback, the CallbackHandler might prompt for a name, retrieve the value from the user, and call the setName method of the NameCallback to store the name.
For more information on using JAAS for login modules for authentication, refer to the following sources:
Java Authentication and Authorization Service (JAAS) in Java Platform, Standard Edition
Java Authentication and Authorization Service (JAAS) Reference Guide
Java Authentication and Authorization Service (JAAS): LoginModule Developer’s Guide
Links to this information are provided in Further Information about Security.
Programmatic login enables the client code to supply user credentials. If you are using an EJB client, you can use the com.sun.appserv.security.ProgrammaticLogin class with their convenient login and logout methods.
Programmatic login is specific to a server. Information on programmatic login for the Enterprise Server is included in the Sun GlassFish Enterprise Server v3 Application Development Guide or the documentation for the server you are using.
In EIS applications, components request a connection to an EIS resource. As part of this connection, the EIS can require a sign-on for the requester to access the resource. The application component provider has two choices for the design of the EIS sign-on:
Container-managed sign-on
In the container-managed sign-on approach, the application component lets the container take the responsibility of configuring and managing the EIS sign-on. The container determines the user name and password for establishing a connection to an EIS instance. For more information, read Container-Managed Sign-On.
Component-managed sign-on
In the component-managed sign-on approach, the application component code manages EIS sign-on by including code that performs the sign-on process to an EIS. For more information, read Component-Managed Sign-On.
You can also configure security for resource adapters. Read Configuring Resource Adapter Security for more information.
In container-managed sign-on, an application component does not have to pass any sign-on security information to the getConnection() method. The security information is supplied by the container, as shown in the following example.
// Business method in an application component Context initctx = new InitialContext(); // Perform JNDI lookup to obtain a connection factory javax.resource.cci.ConnectionFactory cxf = (javax.resource.cci.ConnectionFactory)initctx.lookup( "java:comp/env/eis/MainframeCxFactory"); // Invoke factory to obtain a connection. The security // information is not passed in the getConnection method javax.resource.cci.Connection cx = cxf.getConnection(); ...
In component-managed sign-on, an application component is responsible for passing the needed sign-on security information to the resource to the getConnection method. For example, security information might be a user name and password, as shown here:
// Method in an application component Context initctx = new InitialContext(); // Perform JNDI lookup to obtain a connection factory javax.resource.cci.ConnectionFactory cxf = (javax.resource.cci.ConnectionFactory)initctx.lookup( "java:comp/env/eis/MainframeCxFactory"); // Get a new ConnectionSpec com.myeis.ConnectionSpecImpl properties = //.. // Invoke factory to obtain a connection properties.setUserName("..."); properties.setPassword("..."); javax.resource.cci.Connection cx = cxf.getConnection(properties); ...
A resource adapter is a system-level software component that typically implements network connectivity to an external resource manager. A resource adapter can extend the functionality of the Java EE platform either by implementing one of the Java EE standard service APIs (such as a JDBC driver), or by defining and implementing a resource adapter for a connector to an external application system. Resource adapters can also provide services that are entirely local, perhaps interacting with native resources. Resource adapters interface with the Java EE platform through the Java EE service provider interfaces (Java EE SPI). A resource adapter that uses the Java EE SPIs to attach to the Java EE platform will be able to work with all Java EE products.
To configure the security settings for a resource adapter, you need to edit the resource adapter descriptor file, ra.xml. Here is an example of the part of an ra.xml file that configures the following security properties for a resource adapter:
<authentication-mechanism> <authentication-mechanism-type>BasicPassword</authentication-mechanism-type> <credential-interface> javax.resource.spi.security.PasswordCredential </credential-interface> </authentication-mechanism> <reauthentication-support>false</reauthentication-support>
You can find out more about the options for configuring resource adapter security by reviewing as-install/lib/dtds/connector_1_0.dtd. You can configure the following elements in the resource adapter deployment descriptor file:
Authentication mechanisms
Use the authentication-mechanism element to specify an authentication mechanism supported by the resource adapter. This support is for the resource adapter and not for the underlying EIS instance.
There are two supported mechanism types:
BasicPassword: This mechanism supports the interface javax.resource.spi.security.PasswordCredential.
Kerbv5: This mechanism supports the interface javax.resource.spi.security.GenericCredential. The Enterprise Server does not currently support this mechanism type.
Reauthentication support
Use the reauthentication-support element to specify whether the resource adapter implementation supports re-authentication of existing Managed-Connection instances. Options are true or false.
Security permissions
Use the security-permission element to specify a security permission that is required by the resource adapter code. Support for security permissions is optional and is not supported in the current release of the Enterprise Server. You can, however, manually update the server.policy file to add the relevant permissions for the resource adapter, as described in the Developing and Deploying Applications section of the Sun GlassFish Enterprise Server v3 Application Development Guide.
The security permissions listed in the deployment descriptor are ones that are different from those required by the default permission set as specified in the connector specification.
Refer to the following URL for more information on Sun’s implementation of the security permission specification: http://java.sun.com/javase/6/docs/technotes/guides/security/PolicyFiles.html#FileSyntax.
In addition to specifying resource adapter security in the ra.xml file, you can create a security map for a connector connection pool to map an application principal or a user group to a back end EIS principal. The security map is usually used in situations where one or more EIS back end principals are used to execute operations (on the EIS) initiated by various principals or user groups in the application. You can find out more about security maps in the Configuring Security chapter section of the Sun GlassFish Enterprise Server v3 Administration Guide.
When using the Enterprise Server, you can use security maps to map the caller identity of the application (principal or user group) to a suitable EIS principal in container-managed transaction-based scenarios. When an application principal initiates a request to an EIS, the Enterprise Server first checks for an exact principal using the security map defined for the connector connection pool to determine the mapped back end EIS principal. If there is no exact match, then the Enterprise Server uses the wild card character specification, if any, to determine the mapped back-end EIS principal. Security maps are used when an application user needs to execute EIS operations that require to be executed as a specific identity in the EIS.
To work with security maps, use the Admin Console. From the Admin Console, follow these steps to get to the security maps page:
Expand the Resources node.
Expand the Connectors node.
Select the Work Security Maps node.
Click New to create a new work security map for a resource adapter.
Enter a name by which you will refer to the security map, as well as the other required information. Click the Help button for more information on the individual options.