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.