Part Seven introduces basic security concepts and examples.
This and subsequent chapters discuss how to address security requirements in Java EE, web, and web services applications. Every enterprise that has sensitive resources that can be accessed by many users, or resources that traverse unprotected, open, networks, such as the Internet, needs to be protected.
This chapter introduces basic security concepts and security implementation mechanisms. More information on these concepts and mechanisms can be found in the Security chapter of the Java EE 6 specification. This document is available for download online at http://www.jcp.org/en/jsr/detail?id=316.
Other chapters in this tutorial that address security requirements include the following:
Chapter 24, Getting Started Securing Enterprise Applications discusses adding security to Java EE components such as enterprise beans and application clients.
Chapter 25, Getting Started Securing Web Applications discusses and provides examples for adding security to web components such as servlets, and to web services such as JAX-WS.
Some of the material in this chapter assumes that you understand basic security concepts. To learn more about these concepts, you should explore the Java SE security web site before you begin this chapter. The URL for this site is http://java.sun.com/javase/6/docs/technotes/guides/security/.
This tutorial assumes deployment onto the Sun GlassFishEnterprise Server v3 and provides some information regarding configuration of the Enterprise Server. The best source for information regarding configuration of the Enterprise Server, however, is the Sun GlassFish Enterprise Server v3 Administration Guide. The best source for development tips specific to the Enterprise Server is the Sun GlassFish Enterprise Server v3 Application Development Guide. The best source for tips on deploying applications to the Enterprise Server is the Sun GlassFish Enterprise Server v3 Application Deployment Guide.
Java EE, web, and web services applications are made up of components that can be deployed into different containers. These components are used to build a multi-tier enterprise application. Security for components is provided by their containers. A container provides two kinds of security: declarative and programmatic security.
Declarative security expresses an application component’s security requirements using deployment descriptors. Deployment descriptors are external to an application, and include information that specifies how security roles and access requirements are mapped into environment-specific security roles, users, and policies. For this volume of the tutorial, deployment descriptors are used to secure web applications. For more information about deployment descriptors, read Using Deployment Descriptors for Declarative Security.
Annotations (also called metadata) are used to specify information about security within a class file. When the application is deployed, this information can either be used by or overridden by the application deployment descriptor. Annotations save you from having to write declarative information inside XML descriptors. Instead, you just put annotations on the code and the required information gets generated. For this tutorial, annotations are used for securing enterprise applications. For more information about annotations, read Using Annotations.
Programmatic security is embedded in an application and is used to make security decisions. Programmatic security is useful when declarative security alone is not sufficient to express the security model of an application. For more information about programmatic security, read Using Programmatic Security.
The security behavior of a Java EE environment may be better understood by examining what happens in a simple application with a web client, a JSP user interface, and enterprise bean business logic.
In the following example, which is taken from JSR-316, the Java EE 6 Specification , the web client relies on the web server to act as its authentication proxy by collecting user authentication data from the client and using it to establish an authenticated session.
In the first step of this example, the web client requests the main application URL. This action is shown in Figure 23–1.
Since the client has not yet authenticated itself to the application environment, the server responsible for delivering the web portion of the application (hereafter referred to as web server) detects this and invokes the appropriate authentication mechanism for this resource. For more information on these mechanisms, read Security Implementation Mechanisms.
The web server returns a form that the web client uses to collect authentication data (for example, user name and password) from the user. The web client forwards the authentication data to the web server, where it is validated by the web server, as shown in Figure 23–2.
The validation mechanism may be local to a server, or it may leverage the underlying security services. On the basis of the validation, the web server sets a credential for the user.
The credential is used for future determinations of whether the user is authorized to access restricted resources it may request. The web server consults the security policy (derived from the deployment descriptor) associated with the web resource to determine the security roles that are permitted access to the resource. The web container then tests the user’s credential against each role to determine if it can map the user to the role. Figure 23–3 shows this process.
The web server’s evaluation stops with an “is authorized” outcome when the web server is able to map the user to a role. A “not authorized” outcome is reached if the web server is unable to map the user to any of the permitted roles.
If the user is authorized, the web server returns the result of the original URL request, as shown in Figure 23–4.
In our example, the response URL of a JSP page is returned, enabling the user to post form data that needs to be handled by the business logic component of the application. Read Chapter 25, Getting Started Securing Web Applications for more information on protecting web applications.
The JSP page performs the remote method call to the enterprise bean, using the user’s credential to establish a secure association between the JSP page and the enterprise bean (as shown in Figure 23–5). The association is implemented as two related security contexts, one in the web server and one in the EJB container.
The EJB container is responsible for enforcing access control on the enterprise bean method. It consults the security policy (derived from the deployment descriptor) associated with the enterprise bean to determine the security roles that are permitted access to the method. For each role, the EJB container uses the security context associated with the call to determine if it can map the caller to the role.
The container’s evaluation stops with an “is authorized” outcome when the container is able to map the caller’s credential to a role. A “not authorized” outcome is reached if the container is unable to map the caller to any of the permitted roles. A “not authorized” result causes an exception to be thrown by the container, and propagated back to the calling JSP page.
If the call is authorized, the container dispatches control to the enterprise bean method. The result of the bean’s execution of the call is returned to the JSP, and ultimately to the user by the web server and the web client.
A properly implemented security mechanism will provide the following functionality:
Prevent unauthorized access to application functions and business or personal data (authentication)
Hold system users accountable for operations they perform (non-repudiation)
Protect a system from service interruptions and other breaches that affect quality of service (QoS)
Ideally, properly implemented security mechanisms will also provide the following functionality:
Easy to administer
Transparent to system users
Interoperable across application and enterprise boundaries
Java EE applications consist of components that can contain both protected and unprotected resources. Often, you need to protect resources to ensure that only authorized users have access. Authorization provides controlled access to protected resources. Authorization is based on identification and authentication. Identification is a process that enables recognition of an entity by a system, and authentication is a process that verifies the identity of a user, device, or other entity in a computer system, usually as a prerequisite to allowing access to resources in a system.
Authorization and authentication are not required for an entity to access unprotected resources. Accessing a resource without authentication is referred to as unauthenticated or anonymous access.
The characteristics of application security that, when properly addressed, help to minimize the security threats faced by an enterprise, include the following:
Authentication: The means by which communicating entities (for example, client and server) prove to one another that they are acting on behalf of specific identities that are authorized for access. This ensures that users are who they say they are.
Authorization, or Access Control: The means by which interactions with resources are limited to collections of users or programs for the purpose of enforcing integrity, confidentiality, or availability constraints. This ensures that users have permission to perform operations or access data.
Data integrity: The means used to prove that information has not been modified by a third party (some entity other than the source of the information). For example, a recipient of data sent over an open network must be able to detect and discard messages that were modified after they were sent. This ensures that only authorized users can modify data.
Confidentiality or Data Privacy: The means used to ensure that information is made available only to users who are authorized to access it. This ensures that only authorized users can view sensitive data.
Non-repudiation: The means used to prove that a user performed some action such that the user cannot reasonably deny having done so. This ensures that transactions can be proven to have happened.
Quality of Service (QoS): The means used to provide better service to selected network traffic over various technologies.
Auditing: The means used to capture a tamper-resistant record of security-related events for the purpose of being able to evaluate the effectiveness of security policies and mechanisms. To enable this, the system maintains a record of transactions and security information.
The characteristics of an application should be considered when deciding the layer and type of security to be provided for applications. The following sections discuss the characteristics of the common mechanisms that can be used to secure Java EE applications. Each of these mechanisms can be used individually or with others to provide protection layers based on the specific needs of your implementation.
Java SE provides support for a variety of security features and mechanisms, including:
Java Authentication and Authorization Service (JAAS): JAAS is a set of APIs that enable services to authenticate and enforce access controls upon users. JAAS provides a pluggable and extensible framework for programmatic user authentication and authorization. JAAS is a core Java SE API and is an underlying technology for Java EE security mechanisms.
Java Generic Security Services (Java GSS-API): Java GSS-API is a token-based API used to securely exchange messages between communicating applications. The GSS-API offers application programmers uniform access to security services atop a variety of underlying security mechanisms, including Kerberos.
Java Cryptography Extension (JCE): JCE provides a framework and implementations for encryption, key generation and key agreement, and Message Authentication Code (MAC) algorithms. Support for encryption includes symmetric, asymmetric, block, and stream ciphers. Block ciphers operate on groups of bytes while stream ciphers operate on one byte at a time. The software also supports secure streams and sealed objects.
Java Secure Sockets Extension (JSSE): JSSE provides a framework and an implementation for a Java version of the SSL and TLS protocols and includes functionality for data encryption, server authentication, message integrity, and optional client authentication to enable secure Internet communications.
Simple Authentication and Security Layer (SASL): SASL is an Internet standard (RFC 2222) that specifies a protocol for authentication and optional establishment of a security layer between client and server applications. SASL defines how authentication data is to be exchanged but does not itself specify the contents of that data. It is a framework into which specific authentication mechanisms that specify the contents and semantics of the authentication data can fit.
Java SE also provides a set of tools for managing keystores, certificates, and policy files; generating and verifying JAR signatures; and obtaining, listing, and managing Kerberos tickets.
For more information on Java SE security, visit its web page at http://java.sun.com/javase/6/docs/technotes/guides/security/.
Java EE security services are provided by the component container and can be implemented using declarative or programmatic techniques (container security is discussed more in Securing Containers). Java EE security services provide a robust and easily configured security mechanism for authenticating users and authorizing access to application functions and associated data at many different layers. Java EE security services are separate from the security mechanisms of the operating system.
In Java EE, component containers are responsible for providing application-layer security. Application-layer security provides security services for a specific application type tailored to the needs of the application. At the application layer, application firewalls can be employed to enhance application protection by protecting the communication stream and all associated application resources from attacks.
Java EE security is easy to implement and configure, and can offer fine-grained access control to application functions and data. However, as is inherent to security applied at the application layer, security properties are not transferable to applications running in other environments and only protect data while it is residing in the application environment. In the context of a traditional application, this is not necessarily a problem, but when applied to a web services application, where data often travels across several intermediaries, you would need to use the Java EE security mechanisms along with transport-layer security and message-layer security for a complete security solution.
The advantages of using application-layer security include the following:
Security is uniquely suited to the needs of the application.
Security is fine-grained, with application-specific settings.
The disadvantages of using application-layer security include the following:
The application is dependent on security attributes that are not transferable between application types.
Support for multiple protocols makes this type of security vulnerable.
Data is close to or contained within the point of vulnerability.
For more information on providing security at the application layer, read Securing Containers.
Transport-layer security is provided by the transport mechanisms used to transmit information over the wire between clients and providers, thus transport-layer security relies on secure HTTP transport (HTTPS) using Secure Sockets Layer (SSL). Transport security is a point-to-point security mechanism that can be used for authentication, message integrity, and confidentiality. When running over an SSL-protected session, the server and client can authenticate one another and negotiate an encryption algorithm and cryptographic keys before the application protocol transmits or receives its first byte of data. Security is “live” from the time it leaves the consumer until it arrives at the provider, or vice versa, even across intermediaries. The problem is that it is not protected once it gets to its destination. One solution is to encrypt the message before sending.
Transport-layer security is performed in a series of phases, which are listed here:
The client and server agree on an appropriate algorithm.
A key is exchanged using public-key encryption and certificate-based authentication.
A symmetric cipher is used during the information exchange.
Digital certificates are necessary when running secure HTTP transport (HTTPS) using Secure Sockets Layer (SSL). The HTTPS service of most web servers will not run unless a digital certificate has been installed. Digital certificates have already been created for the Enterprise Server. If you are using a different server, check to see if it has digital certificates, and, if not, use the procedure outlined in Working with Digital Certificates to set up a digital certificate that can be used by your web or application server to enable SSL.
The advantages of using transport-layer security include the following:
Relatively simple, well understood, standard technology.
Applies to message body and attachments.
The disadvantages of using transport-layer security include the following:
Tightly-coupled with transport-layer protocol.
All or nothing approach to security. This implies that the security mechanism is unaware of message contents, and as such, you cannot selectively apply security to portions of the message as you can with message-layer security.
Protection is transient. The message is only protected while in transit. Protection is removed automatically by the endpoint when it receives the message.
Not an end-to-end solution, simply point-to-point.
For more information on transport-layer security, read Establishing a Secure Connection Using SSL.
In message-layer security, security information is contained within the SOAP message and/or SOAP message attachment, which allows security information to travel along with the message or attachment. For example, a portion of the message may be signed by a sender and encrypted for a particular receiver. When the message is sent from the initial sender, it may pass through intermediate nodes before reaching its intended receiver. In this scenario, the encrypted portions continue to be opaque to any intermediate nodes and can only be decrypted by the intended receiver. For this reason, message-layer security is also sometimes referred to as end-to-end security.
The advantages of message-layer security include the following:
Security stays with the message over all hops and after the message arrives at its destination.
Security can be selectively applied to different portions of a message (and to attachments if using XWSS).
Message security can be used with intermediaries over multiple hops.
Message security is independent of the application environment or transport protocol.
The disadvantage of using message-layer security is that it is relatively complex and adds some overhead to processing.
The Enterprise Server supports message security using Metro, a web services stack that uses Web Services Security (WSS) to secure messages. Because this message security is specific to Metro and is not a part of the Java EE platform, this tutorial does not discuss using WSS to secure messages. See the Metro User's Guide at https://metro.dev.java.net/guide/. Other sources of information for message security include Sun GlassFish Enterprise Server v3 Administration Guide and Sun GlassFish Enterprise Server v3 Application Development Guide.
In Java EE, the component containers are responsible for providing application security. A container provides two types of security: declarative and programmatic. The following sections discuss these concepts in more detail.
Declarative security expresses an application component’s security requirements using deployment descriptors. A deployment descriptor is an XML document with an .xml extension that describes the deployment settings of an application, a module, or a component. Because deployment descriptor information is declarative, it can be changed without the need to modify the source code. At runtime, the Java EE server reads the deployment descriptor and acts upon the application, module, or component accordingly.
This tutorial does not document how to write the deployment descriptors from scratch, only what configurations each example requires its deployment descriptors to define. For help with writing deployment descriptors, you can view the provided deployment descriptors in a text editor. Another way to learn how to write deployment descriptors is to read the specification in which the deployment descriptor elements are defined.
Deployment descriptors must provide certain structural information for each component if this information has not been provided in annotations or is not to be defaulted.
Different types of components use different formats, or schema, for their deployment descriptors. The security elements of deployment descriptors which are discussed in this tutorial include the following:
Enterprise JavaBeans components may use an EJB deployment descriptor named META-INF/ejb-jar.xml and would be contained in the EJB JAR file.
The schema for enterprise bean deployment descriptors is provided in the EJB 3.1 Specification (JSR-318), Chapter 9, Deployment Descriptor, which can be downloaded from http://jcp.org/en/jsr/detail?id=318.
Deployment descriptor elements for web services components are defined in JSR–109. This deployment descriptor provides deployment-time mapping functionality between Java and WSDL. In conjunction with JSR–181, JAX-WS 2.2 complements this mapping functionality with development-time Java annotations that control mapping between Java and WSDL.
The schema for web services deployment descriptors is provided in Web Services for Java EE (JSR-109), section 7.1, Web Services Deployment Descriptor XML Schema, which can be downloaded from http://jcp.org/en/jsr/detail?id=109.
Schema elements for web application deployment descriptors are discussed in this tutorial in the section Introduction to Web Application Deployment Descriptors.
Web components use a web application deployment descriptor named web.xml.
The schema for web component deployment descriptors is provided in the Java Servlet 3.0 Specification (JSR-315), chapter 14, Deployment Descriptor, which can be downloaded from http://jcp.org/en/jsr/detail?id=315.
Security elements for web application deployment descriptors are discussed in this tutorial in the section Introduction to Web Application Deployment Descriptors.
Annotations enable a declarative style of programming, and so encompass both the declarative and programmatic security concepts. Users can specify information about security within a class file using annotations. When the application is deployed, this information is used by the Enterprise Server. Not all security information can be specified using annotations, however. Some information must be specified in the application deployment descriptors.
Annotations let you avoid writing boilerplate code under many circumstances by enabling tools to generate it from annotations in the source code. This leads to a declarative programming style, where the programmer says what should be done and tools emit the code to do it. It also eliminates the need for maintaining side files that must be kept up to date with changes in source files. Instead the information can be maintained in the source file.
In this tutorial, specific annotations that can be used to specify security information within a class file are described in Securing an Enterprise Bean Using Declarative Security and Annotations. In this version of the tutorial, annotations are not shown for securing web applications. This is because the use of annotations vary between web components, and deployment descriptors are the common method of securing web applications.
The following are sources for more information on annotations:
JSR 175: A Metadata Facility for the Java Programming Language
JSR 181: Web Services Metadata for the Java Platform
JSR 250: Common Annotations for the Java Platform
The Java SE discussion of annotations
Links to this information are provided in Further Information about Security.
Programmatic security is embedded in an application and is used to make security decisions. Programmatic security is useful when declarative security alone is not sufficient to express the security model of an application. The API for programmatic security consists of two methods of the EJBContext interface and six methods of the servlet HttpServletRequest interface. These methods allow components to make business logic decisions based on the security role of the caller or remote user.
Programmatic security is discussed in more detail in the following sections:
This tutorial describes deployment to the Sun GlassFish Enterprise Server v3, which provides highly secure, interoperable, and distributed component computing based on the Java EE security model. The Enterprise Server supports the Java EE 6 security model. You can configure the Enterprise Server for the following purposes:
Adding, deleting, or modifying authorized users. For more information on this topic, read Working with Realms, Users, Groups, and Roles.
Configuring secure Java Management Extensions (JMX) connectors.
Adding, deleting, or modifying existing or custom realms.
A discussion of this topic is available in Realm Configuration in Sun GlassFish Enterprise Server v3 Application Development Guide.
Defining an interface for pluggable authorization providers using Java Authorization Contract for Containers (JACC).
Java Authorization Contract for Containers (JACC) defines security contracts between the Enterprise Server and authorization policy modules. These contracts specify how the authorization providers are installed, configured, and used in access decisions. JACC is discussed in JACC Support in Sun GlassFish Enterprise Server v3 Application Development Guide.
Using pluggable audit modules.
A discussion of using pluggable audit modules can be found in Pluggable Audit Module Support in Sun GlassFish Enterprise Server v3 Application Development Guide
Customizing authentication mechanisms
All implementations of Java EE 6–compatible Servlet containers are required to support the Servlet Profile of JSR–196, which offers an avenue for customizing the authentication mechanism applied by the web container on behalf of one or more applications. Some discussion of using the JSR–196 contract to configure a custom container authentication mechanism is discussed in Adding Authentication Mechanisms to the Servlet Container in Sun GlassFish Enterprise Server v3 Application Development Guide.
Setting and changing policy permissions for an application.
You can read more about changing policy permissions in The server.policy File in Sun GlassFish Enterprise Server v3 Application Development Guide.
The following features are specific to the Enterprise Server:
Message security is discussed in Configuring Message Security for Web Services in Sun GlassFish Enterprise Server v3 Application Development Guide.
Single sign-on across all Enterprise Server applications within a single security domain.
You can learn more about single sign-on in User Authentication for Single Sign-on in Sun GlassFish Enterprise Server v3 Application Development Guide.
You can learn more about programmatic login in Programmatic Login in Sun GlassFish Enterprise Server v3 Application Development Guide.
For more information about configuring the Enterprise Server, read the Sun GlassFish Enterprise Server v3 Application Development Guide and Sun GlassFish Enterprise Server v3 Administration Guide.
You often need to protect resources to ensure that only authorized users have access. Authorization provides controlled access to protected resources. Authorization is based on identification and authentication. Identification is a process that enables recognition of an entity by a system, and authentication is a process that verifies the identity of a user, device, or other entity in a computer system, usually as a prerequisite to allowing access to resources in a system. These concepts are discussed in more detail in Characteristics of Application Security.
This section discusses setting up users so that they can be correctly identified and either given access to protected resources, or denied access if the user is not authorized to access the protected resources. To authenticate a user, you need to follow these basic steps:
The Application Developer writes code to prompt the user for their user name and password. The different methods of authentication are discussed in Specifying an Authentication Mechanism.
The Application Developer communicates how to set up security for the deployed application by use of a deployment descriptor or metadata annotation. This step is discussed in Setting Up Security Roles.
The Server Administrator sets up authorized users and groups on the Enterprise Server. This is discussed in Managing Users and Groups on the Enterprise Server.
The Application Deployer maps the application’s security roles to users, groups, and principals defined on the Enterprise Server. This topic is discussed in Mapping Roles to Users and Groups.
A realm is a security policy domain defined for a web or application server. It is also a string, passed as part of an HTTP request during basic authentication, that defines a protection space. The protected resources on a server can be partitioned into a set of protection spaces, each with its own authentication scheme and/or authorization database containing a collection of users, which may or may not be assigned to a group. Managing users on the Enterprise Server is discussed in Managing Users and Groups on the Enterprise Server.
An application will often prompt a user for their user name and password before allowing access to a protected resource. After the user has entered their user name and password, that information is passed to the server, which either authenticates the user and sends the protected resource, or does not authenticate the user, in which case access to the protected resource is denied. This type of user authentication is discussed in Specifying an Authentication Mechanism.
In some applications, authorized users are assigned to roles. In this situation, the role assigned to the user in the application must be mapped to a principal or group defined on the application server. Figure 23–6 shows this. More information on mapping roles to users and groups can be found in Setting Up Security Roles.
The concepts of users, groups, principals, and realms exist in most application or web servers, but might use different names in different products. If you are using a server other than Enterprise Server, consult your product's documentation for the terminology specific to that server.
The following sections provide more information on realms, users, groups, and roles.
A realm is a security policy domain defined for a web or application server. It is also a string, passed as part of an HTTP request during basic authentication, that defines a protection space. The protected resources on a server can be partitioned into a set of protection spaces, each with its own authentication scheme and/or authorization database containing a collection of users, which may or may not be assigned to a group. For a web application, a realm is a complete database of users and groups that identify valid users of a web application (or a set of web applications) and are controlled by the same authentication policy.
The Java EE server authentication service can govern users in multiple realms. In this release of the Enterprise Server, the file, admin-realm, and certificate realms come preconfigured for the Enterprise Server.
In the file realm, the server stores user credentials locally in a file named keyfile. You can use the Admin Console to manage users in the file realm. When using the file realm, the server authentication service verifies user identity by checking the file realm. This realm is used for the authentication of all clients except for web browser clients that use the HTTPS protocol and certificates.
In the certificate realm, the server stores user credentials in a certificate database. When using the certificate realm, the server uses certificates with the HTTPS protocol to authenticate web clients. To verify the identity of a user in the certificate realm, the authentication service verifies an X.509 certificate. For step-by-step instructions for creating this type of certificate, see Working with Digital Certificates. The common name field of the X.509 certificate is used as the principal name.
The admin-realm is also a FileRealm and stores administrator user credentials locally in a file named admin-keyfile. You can use the Admin Console to manage users in this realm in the same way you manage users in the file realm. For more information, see Managing Users and Groups on the Enterprise Server.
A user is an individual (or application program) identity that has been defined in the Enterprise Server. In a web application, a user can have a set of roles associated with that identity, which entitles them to access all resources protected by those roles. Users can be associated with a group.
A Java EE user is similar to an operating system user. Typically, both types of users represent people. However, these two types of users are not the same. The Java EE server authentication service has no knowledge of the user name and password you provide when you log on to the operating system. The Java EE server authentication service is not connected to the security mechanism of the operating system. The two security services manage users that belong to different realms.
A group is a set of authenticated users, classified by common traits, defined in the Enterprise Server.
A Java EE user of the file realm can belong to an Enterprise Server group. (A user in the certificate realm cannot.) An Enterprise Server group is a category of users classified by common traits, such as job title or customer profile. For example, most customers of an e-commerce application might belong to the CUSTOMER group, but the big spenders would belong to the PREFERRED group. Categorizing users into groups makes it easier to control the access of large numbers of users.
An Enterprise Server group has a different scope from a role. An Enterprise Server group is designated for the entire Enterprise Server, whereas a role is associated only with a specific application in the Enterprise Server.
A role is an abstract name for the permission to access a particular set of resources in an application. A role can be compared to a key that can open a lock. Many people might have a copy of the key. The lock doesn’t care who you are, only that you have the right key.
The following terminology is also used to describe the security requirements of the Java EE platform:
Principal: A principal is an entity that can be authenticated by an authentication protocol in a security service that is deployed in an enterprise. A principal is identified using a principal name and authenticated using authentication data.
Security policy domain (also known as security domain or realm): A security policy domain is a scope over which a common security policy is defined and enforced by the security administrator of the security service.
Security attributes: A set of security attributes is associated with every principal. The security attributes have many uses, for example, access to protected resources and auditing of users. Security attributes can be associated with a principal by an authentication protocol.
Credential: A credential contains or references information (security attributes) used to authenticate a principal for Java EE product services. A principal acquires a credential upon authentication, or from another principal that allows its credential to be used.
Managing users on the Enterprise Server is discussed in more detail in the Sun GlassFish Enterprise Server v3 Administration Guide.
This tutorial provides steps for managing users that will need to be completed to work through the tutorial examples.
To add users to the Enterprise Server, follow these steps:
Start the Enterprise Server if you haven’t already done so. Information on starting the Enterprise Server is available in Starting and Stopping the Enterprise Server.
Start the Admin Console if you haven’t already done so. You can start the Admin Console by starting a web browser and entering the URL http://localhost:4848/asadmin. If you changed the default Admin port during installation, enter the correct port number in place of 4848.
To log in to the Admin Console, enter the user name and password of a user in the admin-realm who belongs to the asadmin group. The name and password entered during installation will work, as will any users added to this realm and group subsequent to installation.
Expand the Configuration node in the Admin Console tree.
Expand the Security node in the Admin Console tree.
Expand the Realms node.
Select the file realm to add users you want to access applications running in this realm. (For the example security applications, select the file realm.)
Select the admin-realm to add users you want to enable as system administrators of the Enterprise Server.
You cannot enter users into the certificate realm using the Admin Console. You can only add certificates to the certificate realm. For information on adding (importing) certificates to the certificate realm, read Adding Users to the Certificate Realm.
Click the Manage Users button.
Click New to add a new user to the realm.
Enter the correct information into the User ID, Password, and Group(s) fields.
If you are adding a user to the file realm, enter a name to identify the user, a password to allow the user access to the realm, and a group to which this user belongs. For more information on these properties, read Working with Realms, Users, Groups, and Roles.
For the example security applications, enter a user with any name and password you like, but make sure that the user is assigned to the group of TutorialUser. The user name and password are case-sensitive. Keep a record of the user name and password for working with examples later in this tutorial.
If you are adding a user to the admin-realm, enter the name to identify the user, a password to allow the user access to the Enterprise Server, and enter asadmin in the Group field. Restart the Enterprise Server and Admin Console after making this change.
Click OK to add this user to the list of users in the realm.
Click Logout when you have completed this task.
In the certificate realm, user identity is set up in the Enterprise Server security context and populated with user data obtained from cryptographically-verified client certificates. For step-by-step instructions for creating this type of certificate, see Working with Digital Certificates.
When you design an enterprise bean or web component, you should always think about the kinds of users who will access the component. For example, a web application for a human resources department might have a different request URL for someone who has been assigned the role of DEPT_ADMIN than for someone who has been assigned the role of DIRECTOR. The DEPT_ADMIN role may let you view employee data, but the DIRECTOR role enables you to modify employee data, including salary data. Each of these security roles is an abstract logical grouping of users that is defined by the person who assembles the application. When an application is deployed, the deployer will map the roles to security identities in the operational environment, as shown in Figure 23–6.
For enterprise applications, you define security roles using the @DeclareRoles and @RolesAllowed metadata annotations. For web applications, you define roles in the application deployment descriptor, web.xml.
For applications, you define security roles in the Java EE deployment descriptor file application.xml, and the corresponding role mappings in the Enterprise Server deployment descriptor file sun-application.xml. For individually deployed web or EJB modules, you define roles in the Java EE deployment descriptor files web.xml or ejb-jar.xml and the corresponding role mappings in the Enterprise Server deployment descriptor files sun-web.xml or sun-ejb-jar.xml.
The following is an example of an application where the role of DEPT-ADMIN is authorized for methods that review employee payroll data and the role of DIRECTOR is authorized for methods that change employee payroll data.
The enterprise bean would be annotated as shown in the following code:
@DeclareRoles({"DEPT-ADMIN", "DIRECTOR"}) @Stateless public class PayrollBean implements Payroll { @Resource SessionContext ctx; @RolesAllowed("DEPT-ADMIN") public void reviewEmployeeInfo(EmplInfo info) { oldInfo = ... read from database; / ... } @RolesAllowed("DIRECTOR") public void updateEmployeeInfo(EmplInfo info) { newInfo = ... update database; ... } ... }
The deployment descriptor would include security constraints, as shown in the following example:
<security-constraint> <web-resource-collection> <web-resource-name>view dept data</web-resource-name> <url-pattern>/hr/employee/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>DEPT_ADMIN</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>change dept data</web-resource-name> <url-pattern>/hr/employee/*</url-pattern> <http-method>GET</http-method> <http-method>PUT</http-method> </web-resource-collection> <auth-constraint> <role-name>DIRECTOR</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>
The web.xml application deployment descriptor is described in more detail in Introduction to Web Application Deployment Descriptors.
These annotations are discussed in more detail in Securing an Enterprise Bean Using Declarative Security and Annotations.
After users have provided their login information, and the application has declared what roles are authorized to access protected parts of an application, the next step is to map the security role to the name of a user, or principal. This step is discussed in the following section.
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 roles defined in the application to the users or groups defined in the runtime realm. To map a role name permitted by the application or module to principals (users) and groups defined on the server, use the security-role-mapping element in the runtime deployment descriptor (sun-application.xml, sun-web.xml, or sun-ejb-jar.xml) file. The entry needs to declare a mapping between a security role used in the application and one or more groups or principals defined for the applicable realm of the Enterprise Server. An example for the sun-web.xml file is shown below:
<sun-web-app> <security-role-mapping> <role-name>DIRECTOR</role-name> <principal-name>schwartz</principal-name> </security-role-mapping> <security-role-mapping> <role-name>DEPT-ADMIN</role-name> <group-name>dept-admins</group-name> </security-role-mapping> </sun-web-app>
The role name can be mapped to either a specific principal (user), a group, or both. The principal or group names referenced must be valid principals or groups in the current default realm of the Enterprise Server. The role-name in this example must exactly match the role-name in the security-role element of the corresponding web.xml file or the role name defined in the @DeclareRoles and/or @RolesAllowed annotations.
Sometimes 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. From the Admin Console, select Configuration, then Security, then check the enable box beside Default Principal to Role Mapping. If you need more information about using the Admin Console, see Adding Users to the Enterprise Server or its online help.
Secure Socket Layer (SSL) technology is security that is implemented at the transport layer (see Transport-Layer Security, for more information about transport layer security). SSL allows web browsers and web servers to communicate over a secure connection. In this secure connection, the data that is being sent is encrypted before being sent and then is decrypted upon receipt and before processing. Both the browser and the server encrypt all traffic before sending any data. SSL addresses the following important security considerations.
Authentication: During your initial attempt to communicate with a web server over a secure connection, that server will present your web browser with a set of credentials in the form of a server certificate. The purpose of the certificate is to verify that the site is who and what it claims to be. In some cases, the server may request a certificate that the client is who and what it claims to be (which is known as client authentication).
Confidentiality: When data is being passed between the client and the server on a network, third parties can view and intercept this data. SSL responses are encrypted so that the data cannot be deciphered by the third party and the data remains confidential.
Integrity: When data is being passed between the client and the server on a network, third parties can view and intercept this data. SSL helps guarantee that the data will not be modified in transit by that third party.
An SSL HTTPS connector is already enabled in the Enterprise Server. For more information on configuring SSL for the Enterprise Server, refer to the Sun GlassFish Enterprise Server v3 Administration Guide.
If you are using a different application server or web server, an SSL HTTPS connector might or might not be enabled. If you are using a server that needs its SSL connector to be configured, consult the documentation for that server.
As a general rule, to enable SSL for a server, you must address the following issues:
There must be a Connector element for an SSL connector in the server deployment descriptor.
There must be valid keystore and certificate files.
The location of the keystore file and its password must be specified in the server deployment descriptor.
You can verify whether or not SSL is enabled by following the steps in Verifying SSL Support.
To specify a requirement that protected resources be received over a protected transport layer connection (SSL), specify a user data constraint in the application deployment descriptor. The following is an example of a web.xml application deployment descriptor that specifies that SSL be used:
<security-constraint> <web-resource-collection> <web-resource-name>view dept data</web-resource-name> <url-pattern>/hr/employee/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>DEPT_ADMIN</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>
A user data constraint (<user-data-constraint> in the deployment descriptor) requires that all constrained URL patterns and HTTP methods specified in the security constraint are received over a protected transport layer connection such as HTTPS (HTTP over SSL). A user data constraint specifies a transport guarantee (<transport-guarantee> in the deployment descriptor). The choices for transport guarantee include CONFIDENTIAL, INTEGRAL, or NONE. If you specify CONFIDENTIAL or INTEGRAL as a security constraint, that type of security constraint applies to all requests that match the URL patterns in the web resource collection and not just to the login dialog box.
The strength of the required protection is defined by the value of the transport guarantee.
Specify CONFIDENTIAL when the application requires that data be transmitted so as to prevent other entities from observing the contents of the transmission.
Specify INTEGRAL when the application requires that the data be sent between client and server in such a way that it cannot be changed in transit.
Specify NONE to indicate that the container must accept the constrained requests on any connection, including an unprotected one.
The user data constraint is handy to use with basic and form-based user authentication. When the login authentication method is set to BASIC or FORM, passwords are not protected, meaning that passwords sent between a client and a server on an unprotected session can be viewed and intercepted by third parties. Using a user data constraint with the user authentication mechanism can alleviate this concern.
For testing purposes, and to verify that SSL support has been correctly installed, load the default introduction page with a URL that connects to the port defined in the server deployment descriptor:
https://localhost:8181/
The https in this URL indicates that the browser should be using the SSL protocol. The localhost in this example assumes that you are running the example on your local machine as part of the development process. The 8181 in this example is the secure port that was specified where the SSL connector was created. If you are using a different server or port, modify this value accordingly.
The first time that you load this application, the New Site Certificate or Security Alert dialog box displays. Select Next to move through the series of dialog boxes, and select Finish when you reach the last dialog box. The certificates will display only the first time. When you accept the certificates, subsequent hits to this site assume that you still trust the content.
The SSL protocol is designed to be as efficient as securely possible. However, encryption and decryption are computationally expensive processes from a performance standpoint. It is not strictly necessary to run an entire web application over SSL, and it is customary for a developer to decide which pages require a secure connection and which do not. Pages that might require a secure connection include login pages, personal information pages, shopping cart checkouts, or any pages where credit card information could possibly be transmitted. Any page within an application can be requested over a secure socket by simply prefixing the address with https: instead of http:. Any pages that absolutely require a secure connection should check the protocol type associated with the page request and take the appropriate action if https is not specified.
Using name-based virtual hosts on a secured connection can be problematic. This is a design limitation of the SSL protocol itself. The SSL handshake, where the client browser accepts the server certificate, must occur before the HTTP request is accessed. As a result, the request information containing the virtual host name cannot be determined before authentication, and it is therefore not possible to assign multiple certificates to a single IP address. If all virtual hosts on a single IP address need to authenticate against the same certificate, the addition of multiple virtual hosts should not interfere with normal SSL operations on the server. Be aware, however, that most client browsers will compare the server’s domain name against the domain name listed in the certificate, if any (this is applicable primarily to official, CA-signed certificates). If the domain names do not match, these browsers will display a warning to the client. In general, only address-based virtual hosts are commonly used with SSL in a production environment.
Digital certificates for the Enterprise Server have already been generated and can be found in the directory as-install/domain-dir/config/. These digital certificates are self-signed and are intended for use in a development environment; they are not intended for production purposes. For production purposes, generate your own certificates and have them signed by a CA.
The instructions in this section apply to the developer and cluster profiles of the Enterprise Server. In the enterprise profile, the certutil utility is used to create digital certificates. For more information, see the Sun GlassFish Enterprise Server v3 Administration Guide.
To use SSL, an application or web server must have an associated certificate for each external interface, or IP address, that accepts secure connections. The theory behind this design is that a server should provide some kind of reasonable assurance that its owner is who you think it is, particularly before receiving any sensitive information. It may be useful to think of a certificate as a “digital driver’s license” for an Internet address. It states with which company the site is associated, along with some basic contact information about the site owner or administrator.
The digital certificate is cryptographically signed by its owner and is difficult for anyone else to forge. For sites involved in e-commerce or in any other business transaction in which authentication of identity is important, a certificate can be purchased from a well-known certificate authority (CA) such as VeriSign or Thawte. If your server certificate is self-signed, you must install it in the Enterprise Server keystore file (keystore.jks). If your client certificate is self-signed, you should install it in the Enterprise Server truststore file (cacerts.jks).
Sometimes authentication is not really a concern. For example, an administrator might simply want to ensure that data being transmitted and received by the server is private and cannot be snooped by anyone eavesdropping on the connection. In such cases, you can save the time and expense involved in obtaining a CA certificate and simply use a self-signed certificate.
SSL uses public key cryptography, which is based on key pairs. Key pairs contain one public key and one private key. If data is encrypted with one key, it can be decrypted only with the other key of the pair. This property is fundamental to establishing trust and privacy in transactions. For example, using SSL, the server computes a value and encrypts the value using its private key. The encrypted value is called a digital signature. The client decrypts the encrypted value using the server’s public key and compares the value to its own computed value. If the two values match, the client can trust that the signature is authentic, because only the private key could have been used to produce such a signature.
Digital certificates are used with the HTTPS protocol to authenticate web clients. The HTTPS service of most web servers will not run unless a digital certificate has been installed. Use the procedure outlined in the next section, Creating a Server Certificate, to set up a digital certificate that can be used by your application or web server to enable SSL.
One tool that can be used to set up a digital certificate is keytool, a key and certificate management utility that ships with the Java SE SDK. It enables users to administer their own public/private key pairs and associated certificates for use in self-authentication (where the user authenticates himself or herself to other users or services) or data integrity and authentication services, using digital signatures. It also allows users to cache the public keys (in the form of certificates) of their communicating peers. For a better understanding of keytool and public key cryptography, read the keytool documentation at http://java.sun.com/javase/6/docs/technotes/tools/solaris/keytool.html.
A server certificate has already been created for the Enterprise Server. The certificate can be found in the domain-dir/config/ directory. The server certificate is in keystore.jks. The cacerts.jks file contains all the trusted certificates, including client certificates.
If necessary, you can use keytool to generate certificates. The keytool utility stores the keys and certificates in a file termed a keystore, a repository of certificates used for identifying a client or a server. Typically, a keystore is a file that contains one client or one server’s identity. It protects private keys by using a password.
If you don’t specify a directory when specifying the keystore file name, the keystores are created in the directory from which the keytool command is run. This can be the directory where the application resides, or it can be a directory common to many applications.
To create a server certificate, follow these steps:
Create the keystore.
Export the certificate from the keystore.
Sign the certificate.
Import the certificate into a truststore: a repository of certificates used for verifying the certificates. A truststore typically contains more than one certificate.
Run keytool to generatea new key pair in the default development keystore file, keystore.jks. This example uses the alias server-alias to generate a new public/private key pair and wrap the public key into a self-signed certificate inside keystore.jks. The key pair is generated using an algorithm of type RSA, with a default password of changeit. For more information and other examples of creating and managing keystore files, read the keytool online help at http://java.sun.com/javase/6/docs/technotes/tools/solaris/keytool.html.
RSA is public-key encryption technology developed by RSA Data Security, Inc. The acronym stands for Rivest, Shamir, and Adelman, the inventors of the technology.
From the directory in which you want to create the key pair , run keytool with the following parameters.
Generate the server certificate. (Type the keytool command all on one line.)
java-home/bin/keytool -genkey -alias server-alias -keyalg RSA -keypass changeit -storepass changeit -keystore keystore.jks |
When you press Enter, keytool prompts you to enter the server name, organizational unit, organization, locality, state, and country code.
You must enter the server name in response to keytool’s first prompt, in which it asks for first and last names. For testing purposes, this can be localhost.
When you run the example applications, the host (server name) specified in the keystore must match the host identified in the javaee.server.name property specified in the file tut-install/examples/bp-project/build.properties.
Export the generated server certificate in keystore.jks into the file server.cer. (Type the keytool command all on one line.)
java-home/bin/keytool -export -alias server-alias -storepass changeit -file server.cer -keystore keystore.jks |
If you want to have the certificate signed by a CA, read the example at http://java.sun.com/javase/6/docs/technotes/tools/solaris/keytool.html.
To add the server certificate to the truststore file, cacerts.jks, run keytool from the directory where you created the keystore and server certificate. Use the following parameters:
java-home/bin/keytool -import -v -trustcacerts -alias server-alias -file server.cer -keystore cacerts.jks -keypass changeit -storepass changeit |
Information on the certificate, such as that shown next, will display.
% keytool -import -v -trustcacerts -alias server-alias -file server.cer -keystore cacerts.jks -keypass changeit -storepass changeit Owner: CN=localhost, OU=Sun Micro, O=Docs, L=Santa Clara, ST=CA, C=USIssuer: CN=localhost, OU=Sun Micro, O=Docs, L=Santa Clara, ST=CA, C=USSerial number: 3e932169Valid from: Tue Apr 08Certificate fingerprints:MD5: 52:9F:49:68:ED:78:6F:39:87:F3:98:B3:6A:6B:0F:90 SHA1: EE:2E:2A:A6:9E:03:9A:3A:1C:17:4A:28:5E:97:20:78:3F: Trust this certificate? [no]: |
Enter yes, and then press the Enter or Return key. The following information displays:
Certificate was added to keystore[Saving cacerts.jks] |
To check the contents of a keystore that contains a certificate with an alias server-alias, use this command:
keytool -list -keystore keystore.jks -alias server-alias -v |
To check the contents of the cacerts file, use this command:
keytool -list -keystore cacerts.jks |
For more information about security in Java EE applications, see:
Java EE 6 Specification:
The Sun GlassFish Enterprise Server v3 Application Development Guide includes security information for application developers.
The Sun GlassFish Enterprise Server v3 Administration Guide includes information on setting security settings for the Enterprise Server.
The Sun GlassFish Enterprise Server v3 Application Deployment Guide includes information on security settings in the deployment descriptors specific to the Enterprise Server.
EJB 3.1 Specification (JSR-318):
Implementing Enterprise Web Services 1.3 (JSR-109):
Java Platform, Standard Edition 6 security information:
http://java.sun.com/javase/6/docs/technotes/guides/security/
Java Servlet Specification, Version 3.0:
JSR 181: Web Services Metadata for the Java Platform:
JSR 250: Common Annotations for the Java Platform:
The Java SE discussion of annotations:
http://java.sun.com/javase/6/docs/technotes/guides/language/annotations.html
JSR 115: Java Authorization Contract for Containers 1.3:
Chapter 24 of the CORBA/IIOP specification, Secure Interoperability:
Java Authentication and Authorization Service (JAAS) in Java Platform, Standard Edition:
http://java.sun.com/developer/technicalArticles/Security/jaasv2/index.html
Java Authentication and Authorization Service (JAAS) Reference Guide:
http://java.sun.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html
Java Authentication and Authorization Service (JAAS): LoginModule Developer’s Guide:
http://java.sun.com/javase/6/docs/technotes/guides/security/jaas/JAASLMDevGuide.html
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.
A web application is an application that is accessed using a web browser over a network such as the Internet or a company's intranet. As discussed in Chapter 24, Getting Started Securing Enterprise Applications, the JavaTM EE platform uses a distributed multi-tiered application model. As discussed in Distributed Multitiered Applications, web applications run in the web-tier.
Web applications contain resources that can be accessed by many users. These resources often traverse unprotected, open networks, such as the Internet. In such an environment, a substantial number of web applications will require some type of security. The ways to implement security for Java EE web applications are discussed in a general way in Securing Containers. This chapter provides more detail and a few examples that explore these security services as they relate to web components.
Both types of web applications can be secured using the same security model:
Presentation-oriented: A presentation-oriented web application generates interactive web pages containing various types of markup language such as HTML, XHTML, and XML, and generates dynamic content in response to requests. The technologies that are discussed in this chapter and that are considered presentation-oriented web applications include Java Servlets and JavaServerTM Faces technology. You can read more about web applications in Chapter 3, Getting Started with Web Applications.
Service-oriented: A service-oriented web application implements the endpoint of a web service. Presentation-oriented applications are often clients of service-oriented web applications. The technologies that are discussed in the chapter and that are considered service-oriented web applications include the Java API for XML-Based Web Services (JAX-WS) and the Java API for RESTful Web Services (JAX-RS). You can read more about web services in Chapter 11, Introduction to Web Services
Securing applications and their clients in the business tier and the EIS tier is discussed in Chapter 24, Getting Started Securing Enterprise Applications.
The following topics are included in this chapter:
In the Java EE platform, web components provide the dynamic extension capabilities for a web server. Web components are either Java servlets, JSF pages, or web service endpoints. The interaction between a web client and a web application is illustrated in Figure 25–1.
Web components are supported by the services of a runtime platform called a web container. A web container provides services such as request dispatching, security, concurrency, and life-cycle management. Certain aspects of web application security can be configured when the application is installed, or deployed, to the web container. Annotations and/or deployment descriptors are used to relay information to the deployer about security and other aspects of the application. Specifying this information in annotations or in the deployment descriptor helps the deployer set up the appropriate security policy for the web application. Any values explicitly specified in the deployment descriptor override any values specified in annotations.
Security for Java EE web applications can be implemented in the following ways:
Declarative security can be implemented using either an application's deployment descriptor or using metadata annotations. Metadata annotations (or simply, annotations) are used to specify information about security within a class file. An application deployment descriptor is an XML file that is external to the application and which expresses an application’s security structure, including security roles, access control, and authentication requirements. When an application is deployed, security information specified using annotations can be overridden by the application deployment descriptor.
Declarative security is described in Using Deployment Descriptors to Secure Web Applications.
Programmatic security is embedded in an application and is used to make security decisions. Programmatic security is useful when declarative security alone is not sufficient to express the security model of an application. Declarative security alone may not be sufficient in cases where conditional login in a particular work flow, instead of for all cases, is required in the middle of an application.
New in Java EE 6 and Servlet specification 3.0 are the authenticate, login, and logout, methods of the HttpServletRequest interface. With the addition of the authenticate, login, and logout methods to the Servlet specification, an application deployment descriptor is no longer required for web applications, but may still be used to further specify security requirements beyond the basic default values.
Programmatic security is discussed in Using Programmatic Security with Web Applications
Message security works with web services and incorporates security features, such as digital signatures and encryption, into the header of a SOAP message, working in the application layer, ensuring end-to-end security. Message security is not a component of Java EE 6, but is included here for informational purposes only.
Message security is discussed in Using Message Security with Web Applications.
Some of the material in this chapter builds on material presented earlier in this tutorial. In particular, this chapter assumes that you are familiar with the information in the following chapters:
Chapter 13, Building RESTful Web Services with JAX-RS and Jersey
Chapter 23, Introduction to Security in the Java EE Platform
Chapter 24, Getting Started Securing Enterprise Applications
Web applications are created by application developers who give, sell, or otherwise transfer the application to an application deployer for installation into a runtime environment. Application developers communicate how the security is to be set up for the deployed application by the use of the deployment descriptor mechanism or by the use of annotations. When this information is passed on to the deployer, the deployer uses this information to define method permissions for security roles, set up user authentication, and set up the appropriate transport mechanism. If you don’t define security requirements, the deployer will have to determine the security requirements independently.
Many elements necessary for security in a web application cannot, as yet, be specified as annotations for all types of web applications. Therefore, in this volume of the tutorial, we describe how to secure web applications using deployment descriptors only. For information on using annotations to secure web applications, refer to the following sources:
The Java Servlet Specification, Version 3.0, for information on the @ServletSecurity annotation
Part VII, Security, in The Java EE 6 Tutorial, Volume II
The web application deployment descriptor file does pretty much what it's name says it does: it describes how the web application should be deployed. The web application deployment descriptor describes a lot more about a web application than just its security information, but this chapter only discusses the elements of the application deployment descriptor that relate to security.
For web applications written using the Java programming language, the web application deployment descriptor is written using the EXtensible Markup Language (XML) syntax. The web application deployment descriptor is named web.xml, and, when included with a web application, it must reside in a WEB-INF subdirectory at the web application root. The contents of this file direct a deployment tool to deploy a module or application with the specified security settings, and describes other specific configuration requirements and/or container options.
The following XML code is an example of the elements in a deployment descriptor that apply specifically to declaring security for web applications or for resources within web applications. This example comes from An Example of Security, from the Java Servlet Specification, Version 3.0.
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd" version=?2.5?> <display-name>A Secure Application</display-name> <servlet> <servlet-name>catalog</servlet-name> <servlet-class>com.mycorp.CatalogServlet</servlet-class> <init-param> <param-name>catalog</param-name> <param-value>Spring</param-value> </init-param> <!-- Defining Security Roles --> <security-role-ref> <role-name>MGR</role-name> <!-- role name used in code --> <role-link>manager</role-link> </security-role-ref> </servlet> <security-role> <role-name>manager</role-name> </security-role> <servlet-mapping> <servlet-name>catalog</servlet-name> <url-pattern>/catalog/*</url-pattern> </servlet-mapping> <!-- Defining A Security Constraint --> <security-constraint> <!-- Specifying the Resources to be Protected --> <web-resource-collection> <web-resource-name>SalesInfo</web-resource-name> <url-pattern>/salesinfo/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <!-- Specifying which Users Can Access Protected Resources --> <auth-constraint> <role-name>manager</role-name> </auth-constraint> <!-- Specifying Secure Transport using SSL --> <user-data-constraint> <transport-guarantee>CONFIDENTIAL </transport-guarantee> </user-data-constraint> </security-constraint> <!-- Specifying an Authentication Method --> <login-config> <auth-method>BASIC</auth-method> <realm-name>file</realm-name> </login-config> </web-app>
Even if you are simply using the deployment descriptor to specify security, there are some structural elements that must be included in this file in order for it to work properly. For example, the <security-constraint> element is a sub-element of the <web-app> element, so the <web-app> element must always be included, and it must indicate the version of the web application schema (2.4 or 2.5) it is using. The elements that are specified within the deployment descriptor must comply with the rules for processing that version of the deployment descriptor. Version 3.0 of the Java Servlet Specification, which can be downloaded at http://jcp.org/en/jsr/detail?id=315, contains more information regarding the structure of deployment descriptors.
XML files are hierarchical. The elements must be specified in a particular order within the deployment descriptor, between elements that are its parent. To visually see an example of how the deployment descriptor elements are nested within their parent elements, refer to the elements within the <security-constraint> element above, which is itself nested within <web-app> elements. For this example, the lines have been indented to emphasize the nesting aspect of the file, but the file itself ignores the formatting and relies only on the elements and their content for its processing. Information about the application is specified as a value between the opening (<element-name>) and closing (</element-name>) elements. For example, between the opening <transport-guarantee> element and the closing </transport-guarantee> element, there is the value CONFIDENTIAL, which describes which type of transport guarantee should be used for this application.
The following sections describe each of the security elements of a deployment descriptor in more detail, listing all of the options available for each element:
Some of the elements of web application security must be addressed in server configuration files rather than in the deployment descriptor or annotations for the web application. Configuring security on the Enterprise Server is discussed in the following sections and books:
Securing the Enterprise Server (in this book)
Managing Users and Groups on the Enterprise Server (in this book)
Installing and Configuring SSL Support (in this book)
Deploying Secure Enterprise Beans (in this book)
Sun GlassFish Enterprise Server v3 Application Development Guide
A security constraint is used to define the access privileges to a collection of resources using their URL mapping. The following elements can be part of a security constraint:
Web resource collection (web-resource-collection)
A web resource collection is a list of URL patterns (the part of a URL after the host name and port which you want to constrain) and HTTP operations (the methods within the files that match the URL pattern which you want to constrain (in this example, POST and GET)) that describe a set of resources to be protected. Web resource collections are discussed in Specifying a Web Resource Collection.
Authorization constraint (auth-constraint)
Authorization constraints establish a requirement for authentication and name the roles authorized to perform the constrained requests. For more information about authorization constraints, read Specifying an Authentication Mechanism.
User data constraint (TutorialUser-data-constraint)
User data constraints establish a requirement that the constrained requests be received over a protected transport layer connection. This guarantees how the data will be transported between client and server. The strength of the required protection is defined by the value of the transport guarantee. A transport guarantee of INTEGRAL is used to establish a requirement for content integrity and a transport guarantee of CONFIDENTIAL is used to establish a requirement for confidentiality. The transport guarantee of NONE indicates that the container must accept the constrained requests when received on any connection including an unprotected one. User data constraints are discussed in Specifying a Secure Connection.
A web resource collection consists of the following sub-elements:
web-resource-name is the name you use for this resource. It's use is optional, but it is useful to describe the resources being protected as applications get more complex.
url-pattern is used to list the request URI to be protected.
Many applications feature unprotected web content, which any caller can access without authentication. In the web tier, you provide unrestricted access simply by not configuring a security constraint for that particular request URI. It is common to have some unprotected resources and some protected resources. In this case, you will define security constraints and a login method, but they will not be used to control access to the unprotected resources. Users won’t be asked to log in until the first time they enter a protected request URI.
The Java Servlet specification defines the request URI as the part of a URL after the host name and port. For example, let’s say you have an e-commerce site with a browseable catalog that you would want anyone to be able to access, and a shopping cart area for customers only. You could set up the paths for your web application so that the pattern /cart/* is protected but nothing else is protected. Assuming that the application is installed at context path /myapp, the following are true:
http://localhost:8080/myapp/index.jsp is not protected.
http://localhost:8080/myapp/cart/index.jsp is protected.
A user will not be prompted to log in the first time that user accesses a resource in the cart/ subdirectory.
http-method or http-method-omission is used to specify which methods should be protected or which methods should be omitted from protection. An HTTP method is protected by a web-resource-collection when no HTTP methods are named in the collection (which means all are protected), or the collection specifically names the HTTP method in a contained http-method element, or the collection contains one or more http-method-omission elements, none of which names the HTTP method.
An authorization constraint (auth-constraint) contains the role-name element. You can use as many role-name elements as needed here.
An authorization constraint establishes a requirement for authentication and names the roles authorized to access the URL patterns and HTTP methods declared by this security constraint. If there is no authorization constraint, the container must accept the request without requiring user authentication. If there is an authorization constraint, but no roles are specified within it, the container will not allow access to constrained requests under any circumstances. The role name(s) specified here must either correspond to the role name of one of the <security-role> elements defined for this web application, or be the specially reserved role name *, which is a compact syntax for indicating all roles in the web application. Role names are case sensitive. The roles defined for the application must be mapped to users and groups defined on the server. For more information about security roles, read Working with Security Roles.
A user data constraint (<TutorialUser-data-constraint> in the deployment descriptor) contains the <transport-guarantee> element. A user data constraint can be used to require that a protected transport layer connection such as HTTPS (HTTP over SSL) be used for all constrained URL patterns and HTTP methods specified in the security constraint. The choices for transport guarantee include CONFIDENTIAL, INTEGRAL, or NONE. If you specify CONFIDENTIAL or INTEGRAL as a security constraint, it generally means that the use of SSL is required, and that type of security constraint applies to all requests that match the URL patterns in the web resource collection and not just to the login dialog box.
The strength of the required protection is defined by the value of the transport guarantee. Specify CONFIDENTIAL when the application requires that data be transmitted so as to prevent other entities from observing the contents of the transmission. Specify INTEGRAL when the application requires that the data be sent between client and server in such a way that it cannot be changed in transit. Specify NONE to indicate that the container must accept the constrained requests on any connection, including an unprotected one.
The user data constraint is handy to use in conjunction with basic and form-based user authentication. When the login authentication method is set to BASIC or FORM, passwords are not protected, meaning that passwords sent between a client and a server on an unprotected session can be viewed and intercepted by third parties. Using a user data constraint with the user authentication mechanism can alleviate this concern. Configuring a user authentication mechanism is described in Specifying an Authentication Mechanism.
To guarantee that data is transported over a secure connection, ensure that SSL support is configured for your server. If your server is the Sun Java System Enterprise Server, SSL support is already configured. If you are using another server, consult the documentation for that server for information on setting up SSL support. More information on configuring SSL support on the Enterprise Server can be found in Establishing a Secure Connection Using SSL and in the Sun GlassFish Enterprise Server v3 Administration Guide.
Good Security Practice: If you are using sessions, after you switch to SSL you should never accept any further requests for that session that are non-SSL. For example, a shopping site might not use SSL until the checkout page, and then it might switch to using SSL to accept your card number. After switching to SSL, you should stop listening to non-SSL requests for this session. The reason for this practice is that the session ID itself was not encrypted on the earlier communications. This is not so bad when you’re only doing your shopping, but after the credit card information is stored in the session, you don’t want a bad guy trying to fake the purchase transaction against your credit card. This practice could be easily implemented using a filter.
You can create a separate security constraint for different resources within your application. For example, you could allow users with the role of PARTNER access to the GET and POST methods of all resources with the URL pattern /acme/wholesale/*, and allow users with the role of CLIENT access to theGET and POST methods of all resources with the URL pattern /acme/retail/*. An example of a deployment descriptor that would demonstrate this functionality is the following:
<!-- SECURITY CONSTRAINT #1 --> <security-constraint> <web-resource-collection> <web-resource-name>wholesale</web-resource-name> <url-pattern>/acme/wholesale/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>PARTNER</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <!-- SECURITY CONSTRAINT #2 --> <security-constraint> <web-resource-collection> <web-resource-name>retail</web-resource-name> <url-pattern>/acme/retail/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>CLIENT</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>
When the same url-pattern and http-method occur in multiple security constraints, the constraints on the pattern and method are defined by combining the individual constraints, which could result in unintentional denial of access. The Java Servlet 3.0 Specification (downloadable from http://jcp.org/en/jsr/detail?id=315) gives more detail and an example that illustrates the combination of constraints and how the declarations will be interpreted.
The login configuration element is separate from the security-constraint element, as there can be multiple security constraints applying to multiple resources, but the same authentication method will apply to all constrained resources in an application. The login-config element is used to specify the user authentication method to be used for access to web content, the realm in which the user will be authenticated (in the case of basic authentication), and, in the case of form-based login, additional attributes. When specified, the user must be authenticated before access to any resource that is constrained by a security constraint will be granted.
The sub-element auth-method configures the authentication mechanism for the web application. The element content must be either NONE, BASIC, DIGEST, FORM, or CLIENT-CERT. The realm-name element indicates the realm name to use when the basic authentication scheme is chosen for the web application. The form-login-config element specifies the login and error pages that should be used when FORM based login is specified.
Another way to specify form-based authentication is to use the authenticate, login, and logout methods of HttpServletRequest, as discussed in Authenticating Users Programmatically.
When you try to access a web resource that is constrained by a security-constraint element, the web container activates the authentication mechanism that has been configured for that resource. The authentication mechanism you choose specifies how the user is prompted to login. If the <login-config> element is present, and the <auth-method> element contains a value other than NONE, the user must be authenticated before it can access any resource that is constrained by the use of a security-constraint element in the same deployment descriptor (read Specifying Security Constraints for more information on security constraints). If you do not specify an authentication mechanism, authentication of the user is not required.
Before you can authenticate a user, you must have a database of user names, passwords, and roles configured on your web or application server. For information on setting up the user database, refer to Managing Users and Groups on the Enterprise Server in this tutorial or the Sun GlassFish Enterprise Server v3 Administration Guide.
The choices for authentication mechanisms are discussed further in the following sections:
Specifying HTTP Basic Authentication requires that the server request a user name and password from the web client and verify that the user name and password are valid by comparing them against a database of authorized users in the specified or default realm.
When basic authentication is declared, the following actions occur:
A client requests access to a protected resource.
The web server returns a dialog box that requests the user name and password.
The client submits the user name and password to the server.
The server authenticates the user in the specified realm and, if successful, returns the requested resource.
Figure 25–2 shows what happens when you specify HTTP basic authentication.
The following example shows how to specify basic authentication in your deployment descriptor:
<login-config> <auth-method>BASIC</auth-method> <realm-name>file</realm-name> </login-config>
HTTP basic authentication is not a secure authentication mechanism. Basic authentication sends user names and passwords over the Internet as text that is Base64 encoded, and the target server is not authenticated. This form of authentication can expose user names and passwords. If someone can intercept the transmission, the user name and password information can easily be decoded. However, when a secure transport mechanism, such as SSL, or security at the network level, such as the IPSEC protocol or VPN strategies, is used in conjunction with basic authentication, some of these concerns can be alleviated. To specify a secure transport mechanism, use the elements described in Specifying a Secure Connection.
Example: Basic Authentication with JAX-WS is an example application that uses HTTP basic authentication in a JAX-WS service.
Form-based authentication allows the developer to control the look and feel of the login authentication screens by customizing the login screen and error pages that an HTTP browser presents to the end user. When form-based authentication is declared, the following actions occur:
A client requests access to a protected resource.
If the client is unauthenticated, the server redirects the client to a login page.
The client submits the login form to the server.
The server attempts to authenticate the user.
If authentication succeeds, the authenticated user’s principal is checked to ensure it is in a role that is authorized to access the resource. If the user is authorized, the server redirects the client to the resource using the stored URL path.
If authentication fails, the client is forwarded or redirected to an error page.
Figure 25–3 shows what happens when you specify form-based authentication.
The following example shows how to declare form-based authentication in your deployment descriptor:
<login-config> <auth-method>FORM</auth-method> <realm-name>file</realm-name> <form-login-config> <form-login-page>/logon.jsp</form-login-page> <form-error-page>/logonError.jsp</form-error-page> </form-login-config> </login-config>
The login and error page locations are specified relative to the location of the deployment descriptor. Examples of login and error pages are shown in Creating the Login Form and the Error Page.
Form-based authentication is not particularly secure. In form-based authentication, the content of the user dialog box is sent as plain text, and the target server is not authenticated. This form of authentication can expose your user names and passwords unless all connections are over SSL. If someone can intercept the transmission, the user name and password information can easily be decoded. However, when a secure transport mechanism, such as SSL, or security at the network level, such as the IPSEC protocol or VPN strategies, is used in conjunction with form-based authentication, some of these concerns can be alleviated. To add a protected transport in your application, use the elements described in Specifying a Secure Connection.
The section Example: Form-Based Authentication with a Servlet is an example application that uses form-based authentication.
When creating a form-based login, be sure to maintain sessions using cookies or SSL session information.
As shown in Form-Based Authentication, for authentication to proceed appropriately, the action of the login form must always be j_security_check. This restriction is made so that the login form will work no matter which resource it is for, and to avoid requiring the server to specify the action field of the outbound form. The following code snippet shows how the form should be coded into the HTML page:
<form method="POST" action="j_security_check"> <input type="text" name="j_username"> <input type="password" name="j_password"> </form>
HTTPS Client Authentication requires the client to possess a Public Key Certificate (PKC). If you specify client authentication, the web server will authenticate the client using the client’s public key certificate.
HTTPS Client Authentication is a more secure method of authentication than either basic or form-based authentication. It uses HTTP over SSL (HTTPS), in which the server authenticates the client using the client’s Public Key Certificate (PKC). Secure Sockets Layer (SSL) technology provides data encryption, server authentication, message integrity, and optional client authentication for a TCP/IP connection. You can think of a public key certificate as the digital equivalent of a passport. It is issued by a trusted organization, which is called a certificate authority (CA), and provides identification for the bearer.
Before using HTTP Client Authentication, you must make sure that the following actions have been completed:
Make sure the client has a valid Public Key Certificate. For more information on creating and using public key certificates, read Working with Digital Certificates.
Make sure that SSL support is configured for your server. If your server is the Sun GlassFishEnterprise Server v3, SSL support is already configured. If you are using another server, consult the documentation for that server for information on setting up SSL support. More information on configuring SSL support on the application server can be found in Establishing a Secure Connection Using SSL and the Sun GlassFish Enterprise Server v3 Administration Guide.
The following example shows how to declare HTTPS client authentication in your deployment descriptor:
<login-config> <auth-method>CLIENT-CERT</auth-method> </login-config>
An example demonstrating HTTPS client authentication may be available in Part VII, Security, in The Java EE 6 Tutorial, Volume II.
With mutual authentication, the server and the client authenticate one another. There are two types of mutual authentication:
Certificate-based mutual authentication (see Figure 25–4)
User name- and password-based mutual authentication (see Figure 25–5)
When using certificate-based mutual authentication, the following actions occur:
A client requests access to a protected resource.
The web server presents its certificate to the client.
The client verifies the server’s certificate.
If successful, the client sends its certificate to the server.
The server verifies the client’s credentials.
If successful, the server grants access to the protected resource requested by the client.
Figure 25–4 shows what occurs during certificate-based mutual authentication.
In user name- and password-based mutual authentication, the following actions occur:
A client requests access to a protected resource.
The web server presents its certificate to the client.
The client verifies the server’s certificate.
If successful, the client sends its user name and password to the server, which verifies the client’s credentials.
If the verification is successful, the server grants access to the protected resource requested by the client.
Figure 25–5 shows what occurs during user name- and password-based mutual authentication.
Like HTTP Basic Authentication, HTTP Digest Authentication authenticates a user based on a username and a password. However, unlike HTTP Basic Authentication, HTTP Digest Authentication does not send user passwords over the network. In HTTP Digest authentication, the client sends a one-way cryptographic hash of the password (and additional data). Although passwords are not sent on the wire, HTTP Digest authentication requires that clear text password equivalents be available to the authenticating container so that it can validate received authenticators by calculating the expected digest.
The following example shows how to declare HTTP Digest authentication in your deployment descriptor:
<login-config> <auth-method>DIGEST</auth-method> </login-config>
In an application, a role is an abstract name for a group of users. A role can be compared to a key that can open a lock. Many people might have a copy of the key. The lock doesn’t care who you are, only that you have the right key.
For example, in a corporation, you might have the roles Director, Manager, HR, and Employee. When an application developer is creating an internal payroll website, the developer would use the same set of data for all of its corporate users, but would allow different access to the data depending on the role the user is in. For example, a person in the role of HR would have permission to create new Employees, and to modify the payroll information for Employees. The Employee would be able to view their own payroll information, but would not be able to change some of the data, such as their pay rate, but could change some other data, such as their address or dependent information. The users' assigned role determines what permissions that user is granted for access to a particular set of resources in an application.
The following elements in a deployment descriptor use security roles in some capacity:
<security-role>
A security role element is used to define the security roles that will comprise the entire set of security roles used in the application. The sub-element role-name designates the name of the security role. All role names that are used in an application should be specified in its deployment descriptor.
<security-role-ref>
The security role reference element is used in conjunction with the HttpServletRequest.isUserInRole(String role) programmatic security option. When a call is made to isUserInRole, the caller identity is tested for membership in this role. If a security-role-ref has been defined, the caller is tested for membership in the role linked, or mapped, to the role name.
The security role name specified here is the security role name used in the application code. The value of the role-name element must be the String used as the parameter to the HttpServletRequest.isUserInRole(String role) method. The container uses the mapping of security-role-ref to security-role when determining whether or not the user is authorized to access the requested information.
The security role link specified here contains the value of the name of the security role that the user may be mapped into. The role-link element is used to link a security role reference to a defined security role. The role-link element must contain the name of one of the security roles defined in the security-role elements.
For more information about using security-role-ref with the isUserInRole method, read Declaring and Linking Role References.
If you read Working with Realms, Users, Groups, and Roles, you will remember the following information:
On the Enterprise Server, the following concepts need to be understood in order to work with security roles.
A realm is a complete database of users and groups that identify valid users of a web application (or a set of web applications) and are controlled by the same authentication policy. For more information, read What Is a Realm?.
A user is an individual (or application program) identity that has been defined in the Enterprise Server. On the Enterprise Server, a user generally has a user name, a password, and, optionally, a list of groups to which this user has been assigned. For more information, read What Is a User?.
A group is a set of authenticated users, classified by common traits, defined in the Enterprise Server. For more information, read What Is a Group?.
A principal is an entity that can be authenticated by an authentication protocol in a security service that is deployed in an enterprise.
For more information on configuring users on the Enterprise Server, read Managing Users and Groups on the Enterprise Server.
During deployment, the deployer takes the information provided in the application deployment descriptor and maps the roles specified for the application to users and groups defined on the server using the Enterprise Server deployment descriptors sun-web.xml, sun-ejb-jar.xml, or sun-application.xml.
For more information, read Mapping Security Roles to Enterprise Server Groups.
The concepts of users, groups, principals, and realms exist in most application or web servers, but might use different names in different products. If you are using a server other than Enterprise Server, consult your product's documentation for the terminology specific to that server.
You can declare security role names used in web applications using the security-role element of the deployment descriptor. Use this element to list all of the security roles that you have referenced in your application, and also in conjunction with the security-role-ref element (see Declaring and Linking Role References.)
The following snippet of a deployment descriptor is taken from the simple sample application. This snippet declares the roles that will be used in the application using the security-role element, and specifies which of these roles is authorized to access protected resources using the auth-constraint element.
<security-constraint> <web-resource-collection> <web-resource-name>Protected Area</web-resource-name> <url-pattern>/jsp/security/protected/*</url-pattern> <http-method>PUT</http-method> <http-method>DELETE</http-method> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>manager</role-name> </auth-constraint> </security-constraint> <!-- Security roles used by this web application --> <security-role> <role-name>manager</role-name> </security-role> <security-role> <role-name>employee</role-name> </security-role>
In this example, the security-role element lists all of the security roles used in the application: manager and employee. This enables the deployer to map all of the roles defined in the application to users and groups defined on the Enterprise Server.
The auth-constraint element specifies the role, manager, that can access the HTTP methods PUT, DELETE, GET, POST located in the directory specified by the url-pattern element (/jsp/security/protected/*).
To map security roles defined in applications to Enterprise Server principals and groups, use the security-role-mapping element in the runtime deployment descriptor (DD). The runtime deployment descriptor is different from the application deployment descriptor file. The runtime deployment descriptor is an XML file that contains information such as the context root of the web application and the mapping of the portable names of an application’s resources to the Enterprise Server resources. The Enterprise Server web application runtime DD is located in the /WEB-INF/ directory along with the web application deployment descriptor. Runtime deployment descriptors are named sun-web.xml, sun-application.xml, or sun-ejb-jar.xml.
The following example demonstrates how to do this mapping in the sun-web.xml file, which is the file used for web applications:
<sun-web-app> <security-role-mapping> <role-name>CEO</role-name> <principal-name>Schwartz</principal-name> </security-role-mapping> <security-role-mapping> <role-name>Admin</role-name> <group-name>director</group-name> </security-role-mapping> ... </sun-web-app>
A role can be mapped to specific principals, specific groups, or both. The principal or group names must be valid principals or groups in the current default realm, or in the realm specified in the login-config element. In this example, the role of CEO that is used in the application is mapped to a principal named Schwartz that exists on the application server. Mapping a role to a specific principal is useful when the person occupying that role may change. For this application, you would only need to modify the runtime deployment descriptor and not search and replace throughout the application for references to this principal.
Also in this example, the role of Admin is mapped to a group of users who are assigned the group name of director. This is useful because the group of people authorized to access director-level administrative data only has to be maintained on the Enterprise Server. The application developer does not need to know who these people are, just define the group of people who will be given access to the information.
The role-name must match the role-name in the security-role element of the corresponding application deployment descriptor (web.xml, ejb-jar.xml) or the role name defined in an @DeclareRoles annotation.
Sometimes the role names used in the application are the same as the group names defined on the Enterprise Server. Under these circumstances, you can use the Admin Console to define a default principal-to-role-mapping that applies to the entire Enterprise Server instance. From the Admin Console, select Configuration, then Security, then check the Enable box beside Default Principal to Role Mapping. For more information, read the Sun GlassFish Enterprise Server v3 Administration Guide.
Programmatic security is used by security-aware applications when declarative security alone is not sufficient to express the security model of the application. The following topics are discussed in this section:
Servlet 3.0 specifies the following methods of the HttpServletRequest interface that enable you to authenticate users for a web application programmatically:
authenticate
The authenticate method allows an application to instigate authentication of the request caller by the container from within an unconstrained request context. A login dialog box displays and collects the user's name and password for authentication purposes.
login
The login method allows an application to collect username and password information as an alternative to specifying form-based authentication in an application deployment descriptor.
logout
The logout method is provided to allow an application to reset the caller identity of a request.
The following example code shows how to use the login and logout methods:
package test; import java.io.IOException; import java.io.PrintWriter; import java.math.BigDecimal; import javax.ejb.EJB; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="TutorialServlet", urlPatterns={"/TutorialServlet"}) public class TutorialServlet extends HttpServlet { @EJB private ConverterBean converterBean; /** * Processes requests for both HTTP <code>GET</code> * and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { out.println("<html>"); out.println("<head>"); out.println("<title>Servlet TutorialServlet</title>"); out.println("</head>"); out.println("<body>"); request.login("TutorialUser", "TutorialUser"); BigDecimal result = converterBean.dollarToYen(new BigDecimal("1.0")); out.println("<h1>Servlet TutorialServlet result of dollarToYen= " + result + "</h1>"); out.println("</body>"); out.println("</html>"); } catch (Exception e) { throw new ServletException(e); } finally { request.logout(); out.close(); } } }
This code sample shows how to use the authenticate method:
package com.sam.test; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class TestServlet extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { request.authenticate(response); out.println("Authenticate Successful"); } finally { out.close(); } }
In general, security management should be enforced by the container in a manner that is transparent to the web component. The security API described in this section should be used only in the less frequent situations in which the web component methods need to access the security context information.
Servlet 3.0 specifies the following methods of the HttpServletRequest interface that enable you to verify a caller's identity programmatically, and to use that information to grant or deny access to data:
The HttpServletRequest interface provides the following methods that enable you to access security information about the component’s caller:getRemoteUser: Determines the user name with which the client authenticated. The getRemoteUser method returns the name of the remote user (that is, the caller) associated by the container with the request. If no user has been authenticated, this method returns null.
isUserInRole: Determines whether a remote user is in a specific security role. If no user has been authenticated, this method returns false. This method expects a String user role-name parameter.
The <security-role-ref> element should be declared in the deployment descriptor with a <role-name> sub-element containing the role name to be passed to the method. Using security role references is discussed in Declaring and Linking Role References.
getUserPrincipal: Determines the principal name of the current user and returns a java.security.Principal object. If no user has been authenticated, this method returns null. Calling the getName method on the Principal returned by getUserPrincipal returns the name of the remote user.
Your application can make business logic decisions based on the information obtained using these APIs.
The following code demonstrates the use of programmatic security for the purposes of programmatic login.
package enterprise.programmatic_login; import java.io.*; import java.net.*; import javax.annotation.security.DeclareRoles; import javax.servlet.*; import javax.servlet.http.*; @DeclareRoles("javaee6user") public class LoginServlet extends HttpServlet { /** * Processes requests for both HTTP GET and POST methods. * @param request servlet request * @param response servlet response */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { String userName = request.getParameter("txtUserName"); String password = request.getParameter("txtPassword"); out.println("Before Login"+"<br><br>"); out.println("IsUserInRole?.." + request.isUserInRole("javaee6user")+"<br>"); out.println("getRemoteUser?.." + request.getRemoteUser()+"<br>"); out.println("getUserPrincipal?.." + request.getUserPrincipal()+"<br>"); out.println("getAuthType?.." + request.getAuthType()+"<br><br>"); try { request.login(userName, password); }catch(ServletException ex) { out.println("Login Failed with a ServletException.." + ex.getMessage()); return; } out.println("After Login..."+"<br><br>"); out.println("IsUserInRole?.." + request.isUserInRole("javaee6user")+"<br>"); out.println("getRemoteUser?.." + request.getRemoteUser()+"<br>"); out.println("getUserPrincipal?.." + request.getUserPrincipal()+"<br>"); out.println("getAuthType?.." + request.getAuthType()+"<br><br>"); request.logout(); out.println("After Logout..."+"<br><br>"); out.println("IsUserInRole?.." + request.isUserInRole("javaee6user")+"<br>"); out.println("getRemoteUser?.." + request.getRemoteUser()+"<br>"); out.println("getUserPrincipal?.." + request.getUserPrincipal()+"<br>"); out.println("getAuthType?.." + request.getAuthType()+"<br>"); } finally { out.close(); } } /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. */ public String getServletInfo() { return "Short description"; } }
This servlet displays the name of the user who is currently logged in, then prompts a user for login, and prints out the information again, then logs out the user and prints the information again in order to demonstrate the effect of the login and logout methods. The application deployment descriptor, web.xml, includes a login-config element that specifies basic authentication. The runtime deployment descriptor, sun-web.xml, includes a role-mapping of the user of the application to a group of the same name on the Enterprise Server.
A security role reference defines a mapping between the name of a role that is called from a web component using isUserInRole(String role) and the name of a security role that has been defined for the application. If no <security-role-ref> element is declared in a deployment descriptor, and the isUserInRole method is called, the container defaults to checking the provided role name against the list of all security roles defined for the web application. Using the default method instead of using the security-role-ref element limits your flexibility to change role names in an application without also recompiling the servlet making the call.
The security-role-ref element is used when an application uses the HttpServletRequest.isUserInRole(String role) method. The value passed to the isUserInRole method is a String representing the role name of the user. The value of the role-name element must be the String used as the parameter to the HttpServletRequest.isUserInRole(String role) method. The role-link must contain the name of one of the security roles defined in the security-role elements. The container uses the mapping of security-role-ref to security-role when determining the return value of the call.
For example, to map the security role reference cust to the security role with role name bankCustomer, the syntax would be:
<servlet> ... <security-role-ref> <role-name>cust</role-name> <role-link>bankCustomer</role-link> </security-role-ref> ... </servlet>
In this case, if the servlet called by a user belonging to the bankCustomer security role made the API call, isUserInRole("cust") would return true.
The <role-link> element in the security-role-ref element must match a <role-name> defined in the <security-role> element of the same web.xml deployment descriptor, as shown here:
<security-role> <role-name>bankCustomer</role-name> </security-role>
A security role reference, including the name defined by the reference, is scoped to the component whose deployment descriptor contains the security-role-ref deployment descriptor element.
Web Services Security: SOAP Message Security (WS-Security) is an international standard for interoperable Web Services Security that was collaboratively developed in OASIS by all the major providers of web services technology (including Sun Microsystems). WS-Security is a message security mechanism that uses XML Encryption and XML Digital Signature to secure web services messages sent over SOAP. The WS-Security specification defines the use of various security tokens including X.509 certificates, SAML assertions, and username/password tokens to authenticate and encrypt SOAP web services messages. The WS-Security specification can be viewed at http://www.oasis-open.org/committees/download.php/3281/WSS-SOAPMessageSecurity-17-082703-merged.pdf
WS-Security incorporates security features in the header of a SOAP message, working in the application layer. Message security differs from transport layer security (which is what is discussed in this chapter) in that message security can be used to decouple message protection from message transport so that messages remain protected after transmission, ensuring end-to-end security.
Sun's implementation of WS-Security is part of Metro, a web service stack. In the past, web services have relied on transport-based security such as SSL to provide point-to-point security. Metro implements the WS-Security specification to provide interoperable message content integrity and confidentiality, even in the presence of intermediaries. Metro also provides an implementation of the WS-Trust specification as a means for issuing, renewing, and validating security tokens used by WS-Security, and to establish and broker trust relationships. That portion of Metro is known as WSIT (Web Services Interoperability Technologies). Metro's WSIT subsystem is an implementation of a number of open web services specifications to support enterprise features. In addition to security, reliable messaging, and atomic transactions, Metro includes a bootstrapping and configuration technology.
Message security is not part of the Java EE 6 platform, but can be used with and by Java EE 6 applications by following the instructions from the Metro User's Guide at https://metro.dev.java.net/guide/.
There is some basic setup required before any of the example applications will run correctly. Refer to Setting Up Your System for Running the Security Examples to make sure you have completed these steps prior to continuing with the examples.
The following examples use annotations, programmatic security, and/or declarative security to demonstrate adding security to existing web applications:
Here are some links to other locations where you will find examples of securing different types of applications:
Example: Using the isCallerInRole and getCallerPrincipal Methods
GlassFish samples: https://glassfish-samples.dev.java.net/
To set up your system for running the security examples, you basically need to configure a user database that can be used by the application for authenticating users. Here are the steps you need to complete before continuing:
If you have not already done so, make sure you have read and followed the directions for installing the tutorial examples, Ant, and NetBeans IDE, and that you understand how to start the Enterprise Serverand Administration Console. These instructions can be found in Chapter 2, Using the Tutorial Examples.
If you have not already done so, add an authorized user to the Enterprise Server. For this example, add users to the file realm of the Enterprise Server and assign the user to the group TutorialUser. Be sure to write down the user name and password for the user you create so that you can use it for testing the example applications. Authentication is case-sensitive for both the user name and password, so write down the user name and password exactly. This topic is discussed more in Managing Users and Groups on the Enterprise Server.
Set up Default Principal to Role Mapping on the Enterprise Server. From the Admin Console, select Configuration, then Security, then check the enable box beside Default Principal to Role Mapping.
This example discusses how to use basic authentication with a servlet. With basic authentication of a servlet, the web browser presents a standard login dialog that is not customizable. When a user submits their name and password, the server determines if the user name and password are those of an authorized user and sends the requested web resource if the user is authorized to view it.
In general, the following steps are necessary for adding basic authentication to an unsecured servlet, such as the one described in Chapter 3, Getting Started with Web Applications. In the example application included with this tutorial, many of these steps have been completed for you and are listed here simply to show what needs to be done should you wish to create a similar application. The completed version of this example application can be found in the directory tut-install/examples/web/hello2_basicauth/.
Follow the steps in Setting Up Your System for Running the Security Examples.
Create a web module as described in Chapter 3, Getting Started with Web Applications for the servlet example, hello2.
Add the appropriate security elements to the web.xml deployment descriptor. The deployment descriptor for the example application can be viewed at tut-install/examples/web/hello2_basicauth/web/WEB-INF/web.xml. The security elements are described in Specifying Security in the Deployment Descriptor.
Build, package, and deploy the web application by following the steps in Building, Packaging, and Deploying the Servlet Basic Authentication Example Using NetBeans IDE or Building, Packaging, and Deploying the Servlet Basic Authentication Example Using Ant.
Run the web application by following the steps described in Running the Basic Authentication Servlet.
If you have any problems running this example, refer to the troubleshooting tips in Troubleshooting the Basic Authentication Example.
The elements of the deployment descriptor that add basic authentication to this example tells the server or browser to perform the following tasks:
Send a standard login dialog to collect user name and password data
Verify that the user is authorized to access the application
If authorized, display the servlet to the user
Deployment descriptors elements are described in Introduction to Web Application Deployment Descriptors.
The following sample code shows the security elements for the deployment descriptor used in this example of basic authentication, which can be found in tut-install/examples/web/hello2_basicauth/web/WEB-INF/web.xml.
<security-constraint> <display-name>SecurityConstraint</display-name> <web-resource-collection> <web-resource-name>WRCollection</web-resource-name> <url-pattern>/greeting</url-pattern> </web-resource-collection> <auth-constraint> <role-name>TutorialUser</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>file</realm-name> </login-config> <security-role> <role-name>TutorialUser</role-name> </security-role>
This deployment descriptor shows that all the request URI /greeting can only be accessed by users who have entered their user name and password and have been authorized to access this URL because they have been verified to be in the role TutorialUser. The data will be sent over a protected transport in order to keep the user name and password data from being read in transit.
To build, package, and deploy the web/hello2_basicauth example application using NetBeans IDE, follow these steps:
Follow the steps in Setting Up Your System for Running the Security Examples.
Open the project in NetBeans IDE by selecting File->Open Project.
Browse to the tut-install/examples/web/hello2_basicauth/ directory.
Make sure that Open as Main Project is selected.
Select Open Project.
Right-click hello2_basicauth in the Projects pane, then select Clean and Build.
Right-click hello2_basicauth in the Projects pane, then select Deploy.
To run the servlet, follow the steps in Running the Basic Authentication Servlet.
To build, package, and deploy the web/hello2_basicauth example using the Ant tool, follow these steps:
Follow the steps in Setting Up Your System for Running the Security Examples.
From a terminal window or command prompt, change to the tut-install/examples/web/hello2_basicauth/ directory.
Build and package the web application by entering the following command at the terminal window or command prompt:
ant |
To deploy the example using Ant, enter the following command at the terminal window or command prompt:
ant deploy |
The deploy target in this case gives you an incorrect URL to run the application. To run the application, please use the URL shown in Running the Basic Authentication Servlet.
To run the web application, follow the steps in Running the Basic Authentication Servlet.
To run the web client, follow these steps:
Open a web browser.
Enter the following URL in your web browser:
https://localhost:8181/hello2_basicauth/greeting
You may be prompted to accept the security certificate for the server. If so, accept the security certificate.
A default login form displays. Enter a user name and password combination that corresponds to a user that has already been created in the file realm of the Enterprise Server and has been assigned to the group of TutorialUser.
Basic authentication is case-sensitive for both the user name and password, so enter the user name and password exactly as defined for the Enterprise Server.
The server returns the requested resource if all of the following conditions are met:
There is a user defined for the Enterprise Server with the user name you entered.
The user with the user name you entered has the password you entered.
The user name and password combination you entered is assigned to the group of TutorialUser on the Enterprise Server.
The role of TutorialUser, as defined for the application, is mapped to the group of TutorialUser, as defined for the Enterprise Server.
When these conditions are met, and the server has authenticated the user, the application will display as shown in Figure 25–6.
Enter your name and click the Submit button. Because you have already been authorized, the name you enter in this step does not have any limitations. You have unlimited access to the application now.
The application responds by saying “Hello” to you, as shown in Figure 25–7.
For repetitive testing of this example, you may need to close and reopen your browser. You should also run the ant clean and ant undeploy targets or the NetBeans IDE Clean and Build option to get a fresh start.
When doing iterative development with this web application, follow these steps if you are using NetBeans IDE:
Close your web browser.
Clean and recompile the files from the previous build by right-clicking hello2_basicauth and selecting Clean and Build.
Redeploy the application by right-clicking hello2_basicauth and selecting Undeploy and Deploy.
Open your web browser and reload the following URL:
https://localhost:8181/hello2_basicauth/greeting
Follow these steps if you are using the Ant tool:
Close your web browser.
Undeploy the web application. To undeploy the application, use the following command in the directory:
ant undeploy |
Clean out files from the previous build, using the following command:
ant clean |
Recompile, repackage, and redeploy the application, using the following commands:
ant ant deploy |
Open your web browser and reload the following URL:
https://localhost:8181/hello2_basicauth/greeting
This section discusses how to configure a JAX-WS-based web service for HTTP basic authentication. When a service that is constrained by HTTP basic authentication 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.
For this tutorial, you will add the security elements to the JAX-WS service; build, package, and deploy the service; and then build and run the client application.
This example does not include a finished application, but provides instructions in the event that you want to secure a JAX-WS web service, such as the one that can be found in the directory tut-install/examples/jaxws/helloservice and is discussed in Creating a Simple Web Service and Client with JAX-WS. You build on this simple application by adding the necessary elements to secure the application using basic authentication.
In general, the following steps are necessary to add basic authentication to a JAX-WS web service.
Create an application like the one in Creating a Simple Web Service and Client with JAX-WS.
Follow the steps in Setting Up Your System for Running the Security Examples.
Add security elements that specify that basic authentication is to be performed to the application deployment descriptor, web.xml. This step is discussed in Adding Security Elements to the Deployment Descriptor.
Build, package, and deploy the web service. See Building and Deploying helloservice with Basic Authentication Using NetBeans IDE or Building and Deploying helloservice with Basic Authentication Using Ant for the steps to accomplish this.
Build and run the client application. See Building and Running the helloservice Client Application with Basic Authentication Using NetBeans IDE or Building and Running the helloservice Client Application with Basic Authentication Using Ant for the steps to accomplish this.
To enable basic authentication for the service, add security elements to the application deployment descriptor, web.xml. The security elements that need to be added to the deployment descriptor include the <security-constraint>, <login-config>, and <security-role> elements. These security elements are discussed in more detail in Introduction to Web Application Deployment Descriptors and in the Java Servlet Specification. The code is added to the original deployment descriptor to enable HTTP basic authentication. The resulting deployment descriptor looks like this:
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>HelloService</display-name> <listener> <listener-class> com.sun.xml.ws.transport.http.servlet.WSServletContextListener </listener-class> </listener> <servlet> <display-name>HelloService</display-name> <servlet-name>HelloService</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloService</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <session-config> <session-timeout>30</session-timeout> </session-config> <security-constraint> <display-name>SecurityConstraint</display-name> <web-resource-collection> <web-resource-name>WRCollection</web-resource-name> <url-pattern>/hello</url-pattern> </web-resource-collection> <auth-constraint> <role-name>TutorialUser</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <login-config> <auth-constraint>BASIC</auth-constraint> <realm-name>file</realm-name> </login-config> <security-role> <role-name>TutorialUser</role-name> </security-role> </web-app>
This security constraint protects resources at the URI /hello. Anyone who tries to access this resource will be prompted for their user name and password and must be authenticated by the Enterprise Server before they will be granted access to the resource. The request is sent over a protected transport to ensure that the username and password are not intercepted in transit.
To build, package, and deploy the example using NetBeans IDE, follow these steps, or the steps described in Building, Packaging, and Deploying the Service.
Follow the steps in Setting Up Your System for Running the Security Examples.
In NetBeans IDE, select File->Open Project.
In the Open Project dialog, navigate to the project.
Click Open Project.
In the Projects tab, right-click the project and select Clean and Build.
In the Projects tab, right-click the project and select Deploy.
This step builds and packages the application into a WAR file, and deploys this war file to your Enterprise Server instance.
To build, package, and deploy the project using the Ant tool, follow these steps, or the steps described in Building, Packaging, and Deploying the Service.
Follow the steps in Setting Up Your System for Running the Security Examples.
From a terminal window or command prompt, go to the project directory.
Build, package, and deploy the JAX-WS service by entering the following at the terminal window or command prompt in the project directory:
ant all |
You can test the service in the Admin Console. For more information on how to do this, read Testing the Service without a Client.
To build and run the client application using NetBeans IDE, follow these steps. The service must be deployed onto the Enterprise Server before compiling the client files. For information on deploying the service, read Building and Deploying helloservice with Basic Authentication Using NetBeans IDE.
In NetBeans IDE, select File->Open Project.
In the Open Project dialog, navigate to the project.
Click Open Project.
In the Projects tab, right-click the project and select Clean and Build.
In the Projects tab, right-click the project and select Run.
You will be prompted for your user name and password.
Enter the user name and password of a user that has been entered into the database of users for the file realm and has been assigned to the group of TutorialUser.
If the username and password you enter are authorized, you will see the output of the application client in the Output pane.
To build and run the client application using the Ant tool, follow these steps. The secured service must be deployed onto the Enterprise Server before you can successfully compile the client application. For more information on deploying the service, read Building and Deploying helloservice with Basic Authentication Using Ant.
Build the client by changing to the project directory and entering the following at the terminal window or command prompt:
ant |
This command calls the default target, which builds and packages the application into a JAR file.
Run the client by entering the following at the terminal window or command prompt:
ant run |
A Login for User dialog displays.
Enter a user name and password that correspond to a user set up on the Enterprise Server with a group of TutorialUser. Click OK.
This example discusses how to use form-based authentication with a basic servlet. With form-based authentication, you can customize the login screen and error pages that are presented to the web client for authentication of their user name and password. When a user submits their name and password, the server determines if the user name and password are those of an authorized user and, if authorized, sends the requested web resource.
In general, the steps are necessary for adding form-based authentication to an unsecured servlet are similar to those described in Example: Basic Authentication with a Servlet, so just follow all of the steps in Example: Basic Authentication with a Servlet, except use the deployment descriptor described in Specifying Security in the Deployment Descriptor instead and create the login form and login error form pages as described in Creating the Login Form and the Error Page. The completed version of this example application can be found in the directory tut-install/examples/web/hello2_formauth/.
When using form-based login mechanisms, you must specify a page that contains the form you want to use to obtain the user name and password, as well as which page to display if login authentication fails. This section discusses the login form and the error page used in this example. The section Specifying Security in the Deployment Descriptor shows how you specify these pages in the deployment descriptor.
The login page can be an HTML page, a JSP page, or a servlet, and it must return an HTML page containing a form that conforms to specific naming conventions (see the Java Servlet 3.0 specification for more information on these requirements). To do this, include the elements that accept user name and password information between <form></form> tags in your login page. The content of an HTML page, JSP page, or servlet for a login page should be coded as follows:
<form method=post action="j_security_check" > <input type="text" name= "j_username" > <input type="password" name= "j_password" > </form>
The full code for the login page used in this example can be found at tut-install/examples/web/hello2_formauth/web/loginform.html. An example of the running login form page is shown later in Figure 25–8. Here is the code for this page:
<html> <head> <title>Login Page</title> </head> <h2>Hello, please log in:</h2> <br><br> <form action="j_security_check" method=post> <p><strong>Please Enter Your User Name: </strong> <input type="text" name="j_username" size="25"> <p><p><strong>Please Enter Your Password: </strong> <input type="password" size="15" name="j_password"> <p><p> <input type="submit" value="Submit"> <input type="reset" value="Reset"> </form> </html>
The login error page is displayed if the user enters a user name and password combination that is not authorized to access the protected URI. For this example, the login error page can be found at tut-install/examples/web/hello2_formauth/web/loginerror.html. For this example, the login error page explains the reason for receiving the error page and provides a link that will allow the user to try again. Here is the code for this page:
<html> <head> <title>Login Error</title> </head> <body> <c:url var="url" value="/index.jsp"/> <h2>Invalid user name or password.</h2> <p>Please enter a user name or password that is authorized to access this application. For this application, this means a user that has been created in the <code>file</code> realm and has been assigned to the <em>group</em> of <code>TutorialUser</code>. Click here to <a href="${url}">Try Again</a></p> </body> </html>
This example takes a very simple servlet-based web application and adds form-based security to this application. All security for this example is declared in the deployment descriptor for the application. A security constraint is defined in the deployment descriptor that tells the server to send a login form to collect user data, verify that the user is authorized to access the application, and, if so, display the JSP page to the user.
Deployment descriptor elements are described in Introduction to Web Application Deployment Descriptors.
The following sample code shows the deployment descriptor used in this example of form-based login authentication, which can be found in tut-install/examples/web/hello2_formauth/web/WEB-INF/web.xml.
<!-- FORM-BASED LOGIN AUTHENTICATION EXAMPLE --> <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>hello2_formauth</display-name> <servlet> <display-name>index</display-name> <servlet-name>index</servlet-name> <jsp-file>/index.jsp</jsp-file> </servlet> <security-constraint> <display-name>SecurityConstraint</display-name> <web-resource-collection> <web-resource-name>WRCollection</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>TutorialUser</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/loginform.html</form-login-page> <form-error-page>/loginerror.html</form-error-page> </form-login-config> </login-config> <security-role> <role-name>TutorialUser</role-name> </security-role> </web-app>
To build, package, and deploy this application using NetBeans IDE, follow these steps:
Follow the steps in Setting Up Your System for Running the Security Examples.
Open the project in NetBeans IDE by selecting File->Open Project.
Browse to the tut-install/examples/web/hello2_formauth/ directory.
Make sure that Open as Main Project is selected.
Select Open Project.
Right-click hello2_formauth in the Projects pane, then select Clean and Build.
Right-click hello2_formauth in the Projects pane, then select Deploy.
Follow the steps in Testing the Form-Based Authentication Web Client.
To build, package, and deploy this application using the Ant tool, follow these steps:
Follow the steps in Setting Up Your System for Running the Security Examples.
From a terminal window or command prompt, change to the tut-install/examples/web/hello2_formauth/ directory.
Enter the following command at the terminal window or command prompt:
ant |
This target will spawn any necessary compilations, copy files to the tut-install/examples/web/hello2_formauth/build/ directory, create the WAR file, and copy it to the tut-install/examples/web/hello2_formauth/dist/ directory.
Deploy the WAR named hello2_formauth.war onto the Enterprise Server using Ant by entering the following command at the terminal window or command prompt:
ant deploy |
Follow the steps in Testing the Form-Based Authentication Web Client.
To run the web client, follow these steps:
Open a web browser.
Enter the following URL in your web browser:
https://localhost:8181/hello2_formauth
The login form displays in the browser, as shown in Figure 25–8.
Enter a user name and password combination that corresponds to a user that has already been created in the file realm of the Enterprise Server and has been assigned to the group of TutorialUser.
Click the Submit button. Form-based authentication is case-sensitive for both the user name and password, so enter the user name and password exactly as defined for the Enterprise Server.
If you entered My_Name as the name and My_Pwd for the password, the server returns the requested resource if all of the following conditions are met:
There is a user defined for the Enterprise Server with the user name of My_Name.
The user with the user name of My_Name has a password of My_Pwd defined for the Enterprise Server.
The user My_Name with the password My_Pwd is assigned to the group of TutorialUser on the Enterprise Server.
The role of TutorialUser, as defined for the application, is mapped to the group of TutorialUser, as defined for the Enterprise Server.
When these conditions are met, and the server has authenticated the user, the application will display as shown in Figure 25–9.
Enter your name and click the Submit button. Because you have already been authorized, the name you enter in this step does not have any limitations. You have unlimited access to the application now.
The application responds by saying “Hello” to you, as shown in Figure 25–10.
For additional testing, close and reopen your browser, enter the application URL, and enter a username and password that are not authorized to see the login error page generated.
For repetitive testing of this example, you may need to close and reopen your browser. You should also run the ant clean and ant undeploy commands to ensure a fresh build if using the Ant tool, or select Clean and Build then Undeploy and Deploy if using NetBeans IDE.