GlassFish Security

By Masoud Kalali
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Java EE Security Model

About this book

Security was, is, and will be one of the most important aspects of Enterprise Applications and one of the most challenging areas for architects, developers, and administrators. It is mandatory for Java EE application developers to secure their enterprise applications using Glassfish security features.

Learn to secure Java EE artifacts (like Servlets and EJB methods), configure and use GlassFish JAAS modules, and establish environment and network security using this practical guide filled with examples. One of the things you will love about this book is that it covers the advantages of protecting application servers and web service providers using OpenSSO.

The book starts by introducing Java EE security in Web, EJB, and Application Client modules. Then it introduces the Security Realms provided in GlassFish, which developers and administrators can use to complete the authentication and authorization setup. In the next step, we develop a completely secure Java EE application with Web, EJB, and Application Client modules.

The next part includes a detailed and practical guide to setting up, configuring, and extending GlassFish security. This part covers everything an administrator needs to know about GlassFish security, starting from installation and operating environment security, listeners and password security, through policy enforcement, to auditing and developing new auditing modules.

Before starting the third major part of the book, we have a chapter on OpenDS discussing how to install, and administrate OpenDS. The chapter covers importing and exporting data, setting up replications, backup and recovery and finally developing LDAP based solutions using OpenDS and Java.

Finally the third part starts by introducing OpenSSO and continues with guiding you through OpenSSO features, installation, configuration and how you can use it to secure Java EE applications in general and web services in particular. Identity Federation and SSO are discussed in the last chapter of the book along with a working sample.

Publication date:
May 2010
Publisher
Packt
Pages
296
ISBN
9781847199386

 

Chapter 1. Java EE Security Model

Java EE is the mainstream platform for implementing applications in a broad range of use cases starting from high transaction backend for rich clients to a complex integration and mixture of web, transaction processing, and EIS integration layers.

Security is one of the main concerns of software developers whether in small and mid-scale range or in large-scale, distributed software. Starting from the smallest application to the largest one, all may need a similar set of security measures such as authentication, authorization, non-reputability, and transport security.

Java EE as a modular platform for developing enterprise-scale applications provides a great deal of functionalities and features to address security requirements in a declarative way instead of an intrusive code-changing way.

In this chapter we will discuss how we can secure different Java applications either by describing the security model using the declarative security or by manually enforcing the security needs using the API exposed by Java EE containers to access the security enforcement layers programmatically. In Chapter 3 we will put into practice all that we will discuss in this and the next chapter to build a secure Java EE application.

A detailed list of what you will learn in this chapter is as follows:

  • Java EE architecture

  • Authentication and authorization

  • Transport security

  • Web module security

  • EJB module security

  • Programmatic and declarative security

We will discuss security annotations and programmatic security in addition to looking at security description elements, which we can include in the deployment descriptors.

Overview of Java EE architecture

Java EE platform is the dominant platform for developing enterprise-scale applications and in the past three years developers have started looking at Java EE for developing small and mid-scale applications.

We can define Java EE as a set of libraries and tools, developed on top of what Java SE provides as a language and platform. A Java EE application usually consists of three different modules, which include Web module and EJB module residing in the server, and the Application Client Module which is designated for the client applications. Each module is assembled from different components and deployed in a designated container or server. These containers are well integrated with each other and form the Java EE application server.

Note

We have another type of module called connector module; we will not include it in our discussion as it is not widely used compared to three other module types. The connector module allows developers connect different application servers together or connect application servers to EIS systems.

Each of these containers provides a unique set of functionalities in the overall application server architecture. We may use one or two types of containers to form our application without involving the other containers.

 

Overview of Java EE architecture


Java EE platform is the dominant platform for developing enterprise-scale applications and in the past three years developers have started looking at Java EE for developing small and mid-scale applications.

We can define Java EE as a set of libraries and tools, developed on top of what Java SE provides as a language and platform. A Java EE application usually consists of three different modules, which include Web module and EJB module residing in the server, and the Application Client Module which is designated for the client applications. Each module is assembled from different components and deployed in a designated container or server. These containers are well integrated with each other and form the Java EE application server.

Note

We have another type of module called connector module; we will not include it in our discussion as it is not widely used compared to three other module types. The connector module allows developers connect different application servers together or connect application servers to EIS systems.

Each of these containers provides a unique set of functionalities in the overall application server architecture. We may use one or two types of containers to form our application without involving the other containers.

 

Understanding a typical Java EE application


We briefly discussed the Java EE architecture and we said it consists of three main modules which are deployed in different application server containers. The Web module running inside the Web container sits in front of an EJB module deployed in the EJB (Enterprise Java Beans) container. The EJB module drives the system's business logic and provides transaction processing capabilities. This middle layer, which is formed by EJBs, may interact with a database or any other EIS (Enterprise Information System) through a connector module.

The last module is an application client module, which is a Java-based client application that directly interacts with middle layer through a specific container named Application Client Container (ACC). Following diagram shows a Java EE application which uses Web, EJB, and Application Client Container.

The previous figure assumes that no security measure is applied on user interaction with application or the interactions between different application modules. Each of these modules can be deployed independently or one or more of them can be included in a larger logical bundle named Enterprise Application Archive (EAR) and deployed together into the application server. Application server will decompose the archive and deploy each module into its designated container.

Each Java EE application, depending on which set of modules it uses, can have as few as one deployment descriptor or half a dozen. The deployment descriptors basically instruct the application server on how to deal with the application components. The following figure illustrates location and names of the deployment descriptors for a typical Java EE application designated for GlassFish application server.

As you can see we have files with similar names, one without the sun- prefix and one with the prefix.

Files without the prefix are standard to Java EE and use the same schema across all Java EE application servers. These standard files deal with the configuration elements of a Java EE application and have nothing to do with the container the application is going to be deployed into. For example, definition of a Servlet, a Servlet filter, an EJB, and an EJB security constraint, among others can be configuration elements of the standard deployment descriptors.

The files prefixed with sun- specify the application server-specific configurations related to the application components. For example, mapping the Java EE security to application server-specific capabilities is one of functions of these files.

Note

Web browsers are the prominent clients for Java EE application and a fair deal of effort is devoted to secure and facilitate accessing Java EE applications through the browser without involving application client modules.

 

Accessing protected resource inside a Web module


A Web module represents resources inside the application server accessible using HTTP protocol. Each Web module is a deployable archive that contains JSP, Servlet, EJBs, and static contents like HTML page and graphical resources. A Web module is a ZIP file with WAR extension, a specific structure as shown in the previous figure, and one or more deployment descriptors.

The Web container responds to each HTTP request by executing doPost or other request processing methods of Servlet, processing a JSP or sending back a piece of static content like an HTML page. The following figure shows how users can access a protected resource in a Java EE application server.

The previous figure illustrates steps the clients need to go through when they try to access some restricted resources. The Web container protects the Web module content by checking the requested URLs and decides whether it should send back the corresponding response or prevent the request going through the normal procedure until it ensures that the entity which requested the resource is permitted to access that specific resource.

Requests can be placed in one of the six different HTTP methods. Deciding on whether a specific method is acceptable for a resource or not is another factor which we can use to restrict access to a resource.

Web applications are complex and multi-purpose applications, which tons of different users may need to access. Each one of these users may need to have their own set of permissions and restrictions to specify which resources they can access and which resources they cannot.

To decide whether a request can get its corresponding response or not we should check who is requesting that specific resource and whether the requester is permitted to access the resource they are trying to reach.

An example can be a human resource manager, a role in the organization. We should validate his identity before we let him access the resources which are only available to a human resource department manager, such as an employee's contract record. At the same time we should prevent an accounting department employee, who in reality should only be able to issue the payrolls, from editing an employee's contract record.

To accomplish the identity validation and access authorization we should have a system to define users, assign one or more roles to each user, and later on define which roles and users are permitted to access different sets of our system functionalities. When it comes to users of our application, the users may already be defined in the organization where we want to deploy our application, thus we should be able to use already established identity storages when required.

We develop enterprise applications to ease the overall procedure of day-to-day tasks which an organization's employee needs to perform. We do not know whether the employee is going to access the application from an internal network or the communication between the employee and the application will go through an open network like the Internet.

We might be operating over an unknown open network where our requests and responses travel through many different nodes until they reach their destinations. So we need to think about our transport security as well as protecting our resources from unauthorized access. Transport security protects our content from unauthorized eyes that may be sitting between our clients trying to extract information from the transmitted packets.

To protect our information when we are operating in an unsecured network, we should apply some transport-level protection to ensure that our data travels in the unknown zone safely and no one can either monitor the content or tamper the requests or responses to manipulate our system in his or her favor.

Deployment descriptors

A Web module, which is an assembly of several different components, needs to have a deployment descriptor instructing the Web container the structure of the module, what its relation to external resources is, and what security measures the Web container must apply to protect the application resources. The deployment descriptor for a Web application is composed of two XML files and zero or more annotations directly placed in the components source codes. Two deployment descriptor files named web.xml and sun-web.xml are placed inside the WEB-INF directory of the Web application archive.

  • The web.xml file contains all standard deployment instructions shared between all application servers. This file contains all instructions which an application server should apply internally.

  • The sun-web.xml file contains GlassFish vendor-specific instructions, which can differ between different application servers. The instructions included in this file usually configures application server interaction with external resources in regard to the deployed application.

In the following sections we will see what features of the Java EE platform we can use to define access restriction on resources that need protection from unauthorized access.

Understanding Java EE security terms

Before we dig deep into Java EE application security we need to define some basic terms and the relation between these terms. They are:

  • User: A user is an individual identity, which is defined in the identity storage. The individual can either be a program or a software operator. A user may be member of zero or more groups.

  • Group: A group is a set of users classified with a set of common characteristics that usually leads to a set of common permissions and access levels. Individual users can be members of zero or more groups.

  • Security realm: A security realm is the access channel for the application server to an identity storage system like a database or a flat file which contains user's authentication and grouping information. A sample of a security realm and authentication information storage can be the combination of a relation database as the users and groups information storage and GlassFish JDBC realm as the connector of Application server to this storage.

  • Role: A role is an application-level concept that we have in almost every business application that we use. A role maps the access level defined in the Java EE application to users and groups defined in the security realm. Java EE platform provides the required functionalities to define roles and forms the access-level structure based on the defined roles.

  • Principal: A principal is an identity that can be authenticated using an authentication protocol. The principal needs to have credentials to provide when it is going to the authentication process.

  • Credential: A credential contains or references information used to authenticate a principal A password is a simple credential used for authentication.

The following figure shows an illustration of roles, users, groups and realms which we use to define the security view of our applications.

Defining constraints on resources

Java EE platform allows us to define constraints on a URL or a set of URLs specified using wildcard characters. To define the constraints we determine which roles and users have the permission to access the URLs. An example of defining constraints on a set of JSP files is shown as follows:

<security-constraint>
<web-resource-collection>
<web-resource-name>HR Management</web-resource-name>
<url-pattern>/jsp/hr/*</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>hr_management_role</role-name>
<role-name>top_level_manager_role</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>hr_management_role</role-name>
</security-role>
<security-role>
<role-name>top_level_manager_role</role-name>
</security-role>

This code snippet instructs the application server to check every incoming request to any URL matching /jsp/hr/* and only allows the request to go through when the user has one of the hr_management_role or top_level_manager_role roles.

We include the above listing in a deployment descriptor, deploy the application and try to hit a matching URL. The application server will forward us to the default HTTP 403 error page which you can see in the following figure:

Why did the application server forward us to an access denied page? The reason is that the application server is not configured to authenticate the user and therefore it cannot determine what roles have been assigned to our user, so we need a way to instruct the application server to check our user identification information and decide whether the request should go through or not.

Authenticating and authorizing users

To make it simple, authentication is ensuring the users are who they claim they are by checking the credentials provided by them. Authorization is checking whether an authenticated user has the right to access the resource they requested to access. We perform authorization after we validate the user's identity.

The Java EE platform provides a broad range of options for enforcing the authentication procedure. Three different authentication methods are already provided in application servers and can be extended to cover the new requirements when they emerge.

In previous sections we discussed how access to some resources can be restricted to specific roles and users and we came to the conclusion that we should authenticate our users to check their permissions on accessing different system resources.

To address this requirement, authentication comes into play. Using authentication we can check whether a user is known to our system or not and if they are known, whether the requester is really who they claim to be or an imposter trying to get illegal access into our system.

The authentication process kick-starts when a user tries to access a restricted resource. If the user is not authenticated, the system will ask for his authentication information, including the username and password and commence with checking the username and password against the determined security realm. If the user fails to provide correct authentication information, the system will forward him to a HTTP 403 status page.

After the user is successfully authenticated, the system will continue the authorization process by checking whether the user has any of the roles permitted to access the requested resource. If user has one of the roles the request will go through. Otherwise, the user will be forwarded to a HTTP 401 status page.

The good news about Java EE authentication and authorization system is the login once feature, which ensures that when a user is authenticated he will not need to go through the authentication process again unless we discard the authentication token which the system assigned to the user after a successful authentication.

Note

We can configure our applications to use username-password pair, biometric tokens, X.509 digital certificates, Kerberos token, or any other form of authentication mechanism supported by the application server. Here we will discuss username and password as it is the most widely used authentication method.

Adding authentication to a Web application

To add authentication to a Web application we only need to include the required elements in the deployment descriptor. In the deployment descriptor we can determine which type of authentication we want the system to perform and which security realm we want the user to be authenticated against. The following code snippet shows the required elements that we can add to web.xml to enforce authentication where required.

<login-config>
<auth-method>BASIC</auth-method>
<realm-name>JDBC_REALM</realm-name>
</login-config>

The code snippet simply provides instructions for the application server to conduct a HTTP Basic Authentication when an unauthenticated user tries to access a restricted resource. The application server will check the provided credentials against a realm named JDBC_REALM. If we do not define which realm we want to use, the application server will use the default security realm. In GlassFish this realm is named file and its content are stored in a plain text file.

We will discuss application server realms in more detail in Chapter 2. For now consider the JDBC_REALM as a set of two tables that contains users, groups, and user to group association information.

The auth-method element specifies which authentication method we want to use. Different authentication methods provide different levels of security and protection. Four different authentication methods are provided in Java EE specification which vendors must implement. These four different authentication methods provided by application servers are listed in the following table.

Authentication method

Description

Pros and cons

HTTP BASIC Authentication (BASIC)

Server requests a username and password from the web client. The authentication dialog is standard.

  • Easiest to implement.

  • Credentials transmitted in plain text if SSL or other network-level encryptions are not in place.

Form-Based Authentication (FORM)

We should provide a login form to ask username and password along with an authentication failed page in case authentication fails.

  • Very flexible in look and feel.

  • Need extra work to develop required pages.

  • Password transmitted in plain text if SSL or other network-level encryptions are not in place.

HTTPS Client Authentication (CLIENT-CERT)

Both server and client or client alone will need to possess digital certificates to identify themselves.

  • Very secure.

  • More expensive than other methods.

  • More complex in implementation and administration.

Digest Authentication (DIGEST)

Similar to HTTP BASIC Authentication with security enabled for transmitting credentials.

  • Easy to implement but not widespread.

  • Credentials are encrypted prior to transmission.

If we do not specify an authentication method and therefore a security realm, GlassFish will automatically use HTTP BASIC Authentication (BASIC) for the authentication method and a built-in realm named file as the security realm. We will discuss file realm in more detail in Chapter 2.

We will discuss these authentication methods along with how we can configure the application server to support them in more detail in Chapter 2.

Authorizing using deployment descriptor

In the previous two sections we talked about roles and how we can configure the deployment descriptor to only let some of our web application resources be accessible to specific roles. But do these roles map to real world users and groups that security realms contain?

In the figure included in the Understanding security terms of Java EE section we saw a representation of the users and groups mapping to Java EE roles. To instruct the application server to perform these mappings we should use deployment descriptors to map a role to specific users or to groups (or both).

We define the mapping in the vendor-specific deployment descriptor (sun-web.xml) as it is where we should include the vendor-dependent deployment plan details. The following snippet assigns the hr_management_role role to HR_ADMIN user and all members of the HR_MANAGER group. The HR_MANAGER group and all of its possible members are stored in the security realm represented by the JDBC_REALM.

<security-role-mapping>
<role-name>hr_management_role</role-name>
<principal-name>HR_ADMIN</principal-name>
<group-name>HR_MANAGER</group-name>
</security-role-mapping>

So far we have provided instructions for the application server to protect some of our resources and only allow specific roles to access those resources. But we still need to safeguard our application data on the open network from unauthorized eyes that may intercept our communication channels.

Managing session information

We discussed how when a user is authenticated they will stay authenticated unless we discard the authentication information or the validity period of the authentication information expires.

Here we can define a new term named session that can hold all kind of information either required by the programmer or by the application server during the time a visitor or a user is interacting with our system. Some examples for using session are holding the authentication information, the shopping cart content, the visited URLs, and so on. This information can be stored in different ways, including:

  • Cookies: We can use cookies to store the session information on the client side. We usually encrypt sensitive information before setting it as a client-side cookie.

  • URL Rewriting or server side: In this method we store the session information on the server side and assign each visitor a unique identifier to extract the session information when required. We usually append a field at the end of URLs which includes the session ID of that particular client.

  • Hidden form fields: We can use hidden HTML fields like<INPUT TYPE="HIDDEN" NAME="session" VALUE="..."> to transmit the session information.

Note

The hidden form fields method's disadvantage is that all pages we use should be dynamically generated in order for us to include the session information as a hidden field along with other information. Unless we always know how many required fields are placed in the session, we create a placeholder field for them.

Java EE Servlet API provides a profound API for session management. We can access the session information using the HttpSession interface. An example of using HttpSession interface is as follows:

HttpSession session = request.getSession(true);
session. setAttribute("refPage",request.getHeader("Referrer"));
ShoppingCart sc = (ShoppingCart)session.getAttribute("sc");
sc.addItem(anItem);

We can put any serializable object into session and expect the application server to keep our session alive until we discard the session or the session times out and expires. But there are some pitfalls and best practices associated with using session to store our required properties. A short list of these precautions is as follows:

  • Use session-config element of the web.xml to tune the session management capabilities of the application server

  • Use HttpSessionListener to perform the necessary tasks after a session is created or invalidated

  • Do not use long-term values like user IDs as a session identifier; instead use randomly generated short-lived tokens

  • Do not store anything in the session unless it is encrypted with a proven encryption method.

  • Invalidate all session variables after an absolute time like 10 hours or after a period of inactivity like 30 minutes

  • Provide logout functionality to allow the users to logout when they want to, which is provided in Servlet 3 specification as a part of Java EE 6

  • Do not store unnecessary information in the session and remove any variable which is no longer required from the session

The list can go on but the basics instruct us to use the server memory efficiently and make sure that our users' data will not get compromised if our session information is turned into the wrong hands.

Note

Different application servers may provide additional session management capabilities like specifying session maintaining method, cookies domain, cookies length, and so on. GlassFish application server stays with the standard to ensure that your application can be ported to any Java EE-compliant server if required.

Adding transport security

In many enterprise applications, transmitting information over open networks is inevitable. An open network like the Internet has its drawbacks alongside the many benefits that it brings to organizations. A drawback which can affect our applications is the unsecure nature of the data pathway between the client and the server. To address this drawback we should use some sort of encryption mechanism like secure VPNs, IPSec, manual encryptions, and so on.

Java EE application servers implement the required functionalities specified by the Java EE specification in providing SSL-based encryption for transferring sensitive data between the application server and its clients. The specification and the implementations make it as simple as adding required elements to the deployment descriptor for instructing the application server to use HTTPS for communication with clients. Here is a example snippet to add encryption support for a set of resources:

<security-constraint>
<web-resource-collection>
<web-resource-name>HR Management</web-resource-name>
<url-pattern>/jsp/hr/*</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>
<user-data-constraint>
<description/>highest supported transport security level </description>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>

</user-data-constraint>
</security-constraint>

Java EE specification followed by application servers provides different levels of transport guarantee on the communication between clients and the application server. The three levels follow:

  • Data Confidentiality (CONFIDENTIAL): We use this level to guarantee that all communication between client and server goes through the SSL layer and connections won't be accepted over a non-secure channel.

  • Data integrity (INTEGRAL): We can use this level when a full encryption is not required but we want our data to be transmitted to and from the client in a way that if anyone changed the data we could detect the change.

  • Any type of connection (NONE): We can use this level to enforce the container to accept connections on HTTP and HTTPs.

Applying transport security measures brings additional overhead to perform the encryption and decryption. The amount of overhead greatly depends on the cipher suite we use in our HTTPS communication. If we use ciphers with longer key length our encryptions are harder to break compared to when using cipher suites with shorter keys. But we pay a price for better security and this price is more overhead on the server for encryption and decryption of data. We should always use cryptography with care not to introduce additional load on our systems. For example, where it is absolutely required to have data confidentiality, like when we are transmitting credit card numbers, we should use CONFIDENTIAL level, but when we are transmitting a set of numbers for calculation we can use INTEGRAL to ensure that our data is tamper-proof.

Note

In production environment, we usually front the application server with a Web server or a dedicated hardware appliance to accelerate the SSL access among other tasks, such as hosting static content, load distribution, decorating HTP headers, and so on.

For security purpose, the frontend Web server or appliance (like a Cisco PIX 535, F5 Big IP, and so on) can be used to accelerate SSL certificate processing, unify the access port to both HTTP and HTTPS, act as a firewall, and so on.

Using programmatic security in web applications

Sometimes the declarative security in not enough to cope with a complex security requirement and we need to take control and program some security procedures instead of declaring them. There are seven methods of HTTPServletRequest class that we can use to extract security-related attributes of the request and decide manually about how to process the request. These methods are included in the following table.

Method

Description

String getRemoteUser()

If the user is authenticated returns the username, otherwise returns null.

boolean isUserInRole(String role)

Returns whether the user has the specified roles or not.

Principal getUserPrincipal()

Returns a java.security.Principal object containing the name of the current authenticated user.

String getAuthType()

Returns a String containing the authentication method used to protect this Servlet.

Method

Description

void login(String username, String password)

This method authenticates the provided username and password against the security realm which the application is configured to use. We can say this method does anything that the BASIC or FORM authentication does but it also gives the developer total control over how it is going to happen.

Void logout()

Establishes null as the value returned when getUserPrincipal, getRemoteUser, and getAuthType is called on the request.

String getScheme()

Returns the schema portion of the URL, for example HTTP or HTTPS.

We can use these methods when we are processing a request to decide what kind of response we should send back to our user. The programmatic login and logout is included in Java EE 6 and did not exist in Java EE 5 and previous versions.

We can use more descriptive names when we call the isUserInRole method to increase the readability of our source code. But we will need to include linking description for the role name we used in our source code to real names defined in the Web application descriptor, the web.xml file. The following sample snippet shows how we check the user role and decide where to redirect them:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (request.isUserInRole("human_resource_manager")) response.sendRedirect("/hr/index.jsp");
else response.sendRedirect("/guests/index.jsp");
}

We can use different aliases for a role name to make our code easier to read and maintain. For example, imagine we are using human_resource_manager in our source code to alias the hr_management_role role name. In case we use this sort of aliasing we should include security-role-ref elements in our deployment descriptor to describe the link between the aliases and names. For example, to describe the above aliasing we can use:

<security-role-ref>
<role-name>human_resource_manager</role-name>
<role-link>hr_management_role</role-link>
</security-role-ref>

If we do not include the security-role-ref element, the application server will assume that any role name we used in our source code is a role defined using security-role element and will look for its mapping in the sun-web.xml file.

We must include this referencing inside the Servlet element of the Servlet, where we used the alias in its implementation.

Using security annotations

Annotations included in Java EE starting from version 5 allows developers to use metadata to affect the way that a program is treated and interpreted by application servers, tools, and libraries. There are several annotations which we can use in configuring a Web application security.

@DeclareRoles({"ROLE_1", "ROLE_2", "ROLE_N"}): We can use this annotation on a Servlet class to define the roles that we are referring to them from that Servlet. To make it simple, this annotation is a replacement for security-role element of the web.xml file. We can declare one or more roles using this annotation.

@RunAs(value="ROLE_NAME"): Using this annotation we ask the container to only assign the given role to the current security identity for any outgoing invocation. For example, if placed on a Servlet, independent of what the current principal role is, the container will assign this role to the current security identity to access any resource. This annotation is the metadata twin of the run-as element, which we can use in deployment descriptor.

Note

We use the run-as element or its counterpart annotation to assign an specific role to all outgoing calls of a Servlet or an EJB. We use this element to ensure that an internal role which is required to access some secured internal EJBs is never assigned to a client and rather stays fully in control of the developers. Note that the role of the current principal does not change the current identity as seen by the getCallerPrincipal() method of the EJBContext, or getUserPrincipal() of the HTTPServletRequest will return the actual roles.

@ServletSecurity: Using this annotation we can define the security and access control of a Servlet right inside the source code instead of using the deployment descriptor security-constraint element. The @ServletSecurity can optionally get a @HttpMethodConstraint and @HttpConstraint as its parameters. The @HttpMethodConstraint is an array specifying the HTTP method-specific constraint while @HttpConstraint specifies the protection for all HTTP methods which are not specified in the @HttpMethodConstraint.

For example we can use the following annotation:

@ServletSecurity(@HttpConstraint(rolesAllowed = {"employee", "manager"}))

This allows only users with a manager or employee role to access this Servlet. This one single line of code is equal to the following deployment descriptor elements.

<security-constraint>
<web-resource-collection>
<url-pattern>/ourServlet</url-pattern>
</web-resource-collection>
<auth-constraint>
<security-role-name>manager</security-role-name>
<security-role-name>employee</security-role-name>
</auth-constraint>
</security-constraint>

In the next section we will discuss EJB annotations, learn more about these annotations, different types of target (class and method), and what kind of components (EJB or Servlet) can be annotated using security annotations.

With this we've finished with the basics of Web module security; we will discuss the Web module security in further detail in Chapter 3 when we will develop a secure application using Java EE. Now it is time to take a look at EJB module security.

 

Understanding the EJB modules


We saw that a Web module is mostly responsible for interactive with users, including receiving the requests as HTTP methods, processing the requests, calling business logic when required to generate the response, and finally sending the generated response back to clients.

The EJB modules are simple ZIP files with JAR extension, with a predefined structure, formed by several Enterprise JavaBeans implementations, which are called enterprise beans. Three types of EJBs defined by the specification and supported by different application servers are Session Beans, Entity Beans, and Message-Driven Beans (MDB).

Message-Driven Beans are provided to process the JMS messages in the context of enterprise application to support complex transaction schemas. There is no security constraint which we may need to define for an MDB.

Java EE specification followed by application servers provides a complete security model for Entity Beans and Session Beans as they are in direct contact with the clients either through the Application Client Container, through a web application, or from another container developed by third-party companies to integrate a new container in a Java EE application server.

We can define constraints on Entity Beans and Session Beans in two ways—by adding required elements to deployment descriptor or adding necessary annotations to the EJB's source code.

These annotations or deployment descriptor elements instruct the application server about which roles are allowed to access the EJB as a whole or one or more methods of the business interface, home interface, component interface, and/or web service endpoints.

If you are thinking about the authentication, I should say that authentication process usually happens in the first layer of user's interaction with application. In our case this is the Web module or the application client module. Thus we are not involved with authentication in the EJB layer and instead we rely on the authentication information we receive from the Web layer and we only go through the authorization process in the EJB layer. Following figure illustrates how EJB container relies on Web container or Application Client Container for authentication process.

Whenever the Web container needs to invoke some methods from an EJB module in the EJB container it sends the authenticated user's principal to the EJB container, which goes through authorization to see whether the current user has the permission to invoke the method or not.

Similar to Web modules where we could use annotation and deployment descriptor elements to instruct the container to apply constraints on our resources, we can use annotation and deployment descriptor to define constraints on EJBs. Through this section we will use Entity Beans to demonstrate how we can define constraints either by using annotation or through the deployment descriptor. The listing below shows the Employee Entity Bean.

@Entity
public class Employee implements Serializable {
public String getName() {
return "name";
}
public void promote(String toPosition) {
//promote the employee
}
public List<EvaluationRecords> getEvaluationRecords() {
List<EvaluationRecords> evalRecord;
//return a list containing all
// EvaluationRecords of
//this employee
return evalRecord;
}
public List<EvaluationRecords> getEvaluationRecords(Date from, Date to) {
List<EvaluationRecords> evalRecord;
//return a list containing all
//productivity evaluation of
//this employee
return evalRecord;
}
@Id
private Integer id;
public Employee() {
}
}

The Employee Entity Bean has several methods and we should only allow certain roles to invoke them. The getName method can be accessed by any caller that has the employee_role role. The promote and getEvaluationRecords method can be called by any employee with the hr_management_role role assigned to them. Finally, we should allow all top-level managers to invoke different overloads of the getEvaluationRecords method. For instructing the application server to protect our entity bean with the security view we have just defined, we should provide the corresponding declaration in the ejb-jar.xml file. The following listing shows how we should add the security view we defined to our ejb-jar.xml file.

<security-role>
EJB modulessecurity view, adding<description>human_resource_manager
</description>
<role-name>hr_management_role</role-name>
</security-role>
<security-role>
<description> top level managers
</description>
<role-name>top_level_manager_role</role-name>
</security-role>
<method-permission>
<role-name>hr_management_role</role-name>
<method>
<ejb-name>Employee</ejb-name>
<method-name>getName</method-name>
</method>
</method-permission>
<method-permission>
<role-name>hr_management_role</role-name>
<method>
<ejb-name>Employee</ejb-name>
<method-name>*</method-name>
</method>
</method-permission>
<method-permission>
<role-name>top_level_manager_role</role-name>
<method>
<ejb-name>employee</ejb-name>
<method-name>getEvaluationRecords</method-name>
<method-params>
<method-param>from</method-param>
<method-param>to</method-param>
</method-params>
</method>
</method-permission>

This snippet shows some basic instructions for application servers to restrict access to different methods of Employee bean for certain roles.

Using security-role we can define roles which we want to use in the EJB module. By using the method-permission element we can define which roles can access one or all methods in our entity bean. The role-name is the name of the rule which we want to define its permissions in the current security-role element. The value can either be a role name or it can be unchecked to permit all roles to invoke methods we determine by using the method-name element. In the method-name element we can use a method name or we can use * to grant permission for invoking all of our EJB methods to the roles we set in method-name element.

In our entity bean we have two overloads of the getEvaluationRecords method and sometimes we just need to let different roles invoke different overloads. In such a condition we distinguish different overloads by providing the list of parameters for the method for which we want to define permission.

Like in web applications, we sometimes need to assign a specific role to all outgoing calls of an EJB. To do this, we can use the run-as element of the standard deployment descriptor as shown in the following snippet:

<enterprise-beans>
<entity>
<ejb-name>employee</ejb-name>
<ejb-class>book.glassfish.security.chapter01.Employee </ejb-class>
<security-identity>
<run-as>
<role-name>payroll_dept</role-name>
</run-as>
</security-identity>
</entity>
</enterprise-beans>

This sample code instructs the application server to assign the payroll_dept to all outgoing calls from Employee bean using the payroll_dept role. Using the run-as element does not change the current authenticated user or their role, but it's just in case the method invocation uses the given role.

Securing EJB modules using annotations

Annotations play an important role in Java EE 5 and later releases, especially in the EJB layer. We can almost forget about the standard deployment descriptor, ejb-jar.xml, and define every runtime aspect of EJBs using annotations. Although using annotations lifts the necessity of the ejb-jar.xml presence, we still need to have vendor-specific descriptor sun-ejb-jar.xml in place to define dependency of our EJB module to external resources like security realms.

The following table below shows important security-related annotations in Java EE 6 that we can use to secure different components of enterprise applications.

Annotation

Class Level

Method Level

EJB

Servlet

Description

@PermitAll

X

X

X

 

Permitting everyone to access the annotated method. In case of class-level annotation, all methods of annotated EJB are accessible to all roles unless the method is annotated with a @RolesAllowed annotation.

@DenyAll

 

X

X

 

If placed on a method, no one can access that method. In case of class-level annotation, all methods of annotated EJB are inaccessible to all roles unless a method is annotated with a @RolesAllowed annotation.

@RolesAllowed

X

X

X

 

In case of method-level annotation, it permits the included roles to invoke the method. In case of class-level annotation, all methods of the annotated EJB are accessible to included roles unless the method is annotated with a different set of roles using @RolesAllowed annotation.

@DeclareRoles

X

X

X

Defines roles used by the application. It is similar to using the security-role element of the deployment descriptor.

@RunAs

X

X

X

Specifies the run-as role for the given components. We discussed how this annotation works in the Using security annotations section.

Some of the security annotations cannot target a method like @DeclareRoles while some others can target both methods and classes like @PermitAll. Annotation applied on a method will override the class-level annotations. For example, if we apply @RolesAllowed("employee") on an EJB class, and we apply @RolesAllowed("manager") on one specific method of that EJB, only *admin* role will be able to invoke the marked method while all other methods will be available to the employee role.

You should remember two of these annotations from the Web module section and now you are going to learn four other security-related annotations. Let's rewrite the Employee entity bean using annotations. A revision of the Employee entity bean enriched by annotation is in the following listing:

@Entity
@DeclareRoles({"employee_role","hr_management_role"top_level_manager_role})
@RolesAllowed(" hr_management_role")
public class Employee implements Serializable {
@RolesAllowed("employee_role")
public String getName() {
return "name";
}
public void promote(String toPosition) {
//promote the employee
}
@RolesAllowed("top_level_manager_role ")
public List<EvaluationRecords> getEvaluationRecords() {
List<EvaluationRecords> evalRecord = null;
//return a list containing all
// EvaluationRecords of
//this employee
return evalRecord;
}
@RolesAllowed("top_level_manager_role ")
public List<EvaluationRecords> getEvaluationRecords(Date from, Date to) {
List<EvaluationRecords> evalRecord = null;
//return a list containing all
// EvaluationRecords of
//this employee
return evalRecord;
}
@Id
private Integer id;
public Employee() {
}
}

We simply used @DeclareRoles({"employee_role","hr_management_role","top_level_manager_role}) to define all roles that we are going to use in our EJB and then we used @RolesAllowed("top_level_manager_role") to permit the top_level_manager_role role to invoke all methods in the Employee EJB. Finally, we defined which roles can invoke individual methods by marking them with different @RolesAllowed annotations.

To instruct the application server to execute the EJB methods using a specified role instead of the caller role, we can place @RunAs(value="payroll_dept") on the EJB class level.

Mapping roles to principals and groups

In the Web applications we saw that we should define the mapping between roles, principals, and groups in the sun-web.xml, which is the vendor-specific deployment descriptor for web applications. In the same way, we need to define the role mapping in the EJB applications to ensure that application server can determine whether a user has a required role assigned to it or not. The following snippet of the sun-ejb-jar.xml shows how we can map the hr_management_role role to an individual user and a group of the realm.

<security-role-mapping>
<role-name>hr_management_role</role-name>
<principal-name>HR_ADMIN</principal-name>
<group-name>HR_Manager</group-name>
</security-role-mapping>

This role mapping declaration, hr_management_role is assigned to HR_Manager group as well as for an individual user, identified by HR_ADMIN username.

Accessing the security context programmatically

Similar to web applications for which we had some level of programmatic access to the context security information, we have some methods which allow us to access the security context and extract the required information when the declarative security and annotations are not enough.

The javax.ejb.EJBContext interface provides two methods for accessing the security information. First, getCallerPrincipal method which lets us access the caller principal and second, the already introduced isCallerInRole method to check a specific role against the roles assigned to the caller. It is highly recommended that we only use the annotations and deployment descriptor and turn to programmatic security only when we have no other way to address our requirement. Imagine that our Employee bean has a new method named raisePaygrade(int amount, String raisedBy), this method needs the username of the manager who will raise the pay grade of the employee. When we are calling this method of Employee bean we can extract the caller principal and use it when we are invoking this method.

@Stateless
public class EmployeeServiceBean
{
@Resource
SessionContext ctx;
public void raiseEmployeePaygrade(int amount, long empID){
Employee employee = null;
//find the employee
String raisedBy =ctx.getCallerPrincipal().getName();

employee.raisePayGrade(850000, raisedBy);
//persist the employee
}
}

We simply extract the principal of the caller and store who raised the pay grade for our employee. Our sample method only accepts two parameters; while it may be way more complex than this, the concept and the procedure is the same.

We should follow the same rules when we are using the isCallerInRole method, meaning that we need to either use the role name as defined in the deployment descriptor, or we should define the link between the role name we used in the source code and real name of the role which is defined in the security-role element.

Using EJB interceptors for auditing and security purposes

We can use AroundInvoke interceptor to intercept EJB business method calls. Intercepting the call lets us access the method name, its parameters, and EJB context (and therefore isCallerInRole and getCallerPrincipal methods). We can perform tasks such as security check, logging and auditing, or even changing the values of method parameters using interceptors.

public class SampleInterceptor {
@Resource
private EJBContext context;
@AroundInvoke
protected Object audit(InvocationContext ctx) throws Exception {
Principal p = context.getCallerPrincipal();
if (userIsValid(p)) {
//do some logging...
}else{
//logging and raising exception..
}
return ctx.proceed();
}
}

To use this interceptor we only need to place an annotation on the designated EJB. For example to intercept any method call on EmployeeServiceBean we can do the following:

@Interceptors(SampleInterceptor.class)
@Stateless
public class EmployeeServiceBean {
// Source code omitted.
}

The @Interceptors can target classes, methods, or both. To exclude a method from a class-level interceptor we can use @ExcludeClassInterceptors annotation for that method.

We can use interceptor element of ejb-jar.xml deployment descriptor to specify interceptors if preferred.

Enforcing authentication in EJB modules

So far we have assumed that the EJB module itself does not require conducting an authentication and relies on authentication information it receives from the caller container. But we may need to instruct the EJB container to commence with authentication process when necessary by including required configuration elements to sun-ejb-jar.xml file.

We usually require enforcing authentication in the EJB layer when we know that client applications, which may access our EJBs, are deployed into other containers like ACC or another application server's different containers.

The EJB container uses Inter-ORB security standards to declare constraints over EJBs which have some level of constraints applied on them. A simple configuration to ensure that any call to a constraint method of the Employee entity bean will go through authentication is similar to the following listing.

<sun-ejb-jar>
<enterprise-beans>
<unique-id>1</unique-id>
<ejb>
<ejb-name>employee</ejb-name>
<jndi-name>employee</jndi-name>
<ior-security-config>
<transport-config>
<integrity>NONE</integrity>
<confidentiality>NONE</confidentiality>
<establish-trust-in-target>
NONE
</establish-trust-in-target>
<establish-trust-in-client>
NONE
</establish-trust-in-client>
</transport-config>
<as-context>
<auth-method>USERNAME_PASSWORD</auth-method>
<realm>default</realm>
<required>true</required>
</as-context>
</ior-security-config>
</ejb>
</enterprise-beans>
</sun-ejb-jar>

The snippet simply means that we want to have authentication of HTTP Basic type in place when a user tries to access a constrained part of our EJB. Using IOR we can declare transport security in addition to authentication, but I leave it to you to study the sun-ejb-jar.xml to see what else we can do using IOR declarations. In Chapter 3 we will discuss sun-ejb-jar.xml in more detail.

 

Understanding the application client module


Application client modules are regular Java programs that directly interact with the EJB modules. These modules depend on another type of container named Application Client Container for the services that are required for operation. Each application client module is assembled in a JAR file that contains a deployment descriptor named application-client.xml.

The application-client.xml descriptor file determines how the application accesses enterprise beans and web resources. When the resources which the application client requires to access are secure the client will be authenticated accordingly.

Assume that we have a Swing application interacting with an EJB module with several constrained EJBs that we need to use during our application runtime. As we want to access a secure resource, we should go through the authentication and authorization phases. In order to go through these two phases we should provide our authentication information to the container so it can validate our identity and check whether we have a role permitted to invoke the EJB method we want to invoke.

When we want to access a constraint EJB resource from an application client module, the ACC will perform the authentication and send the authenticated subject along with the context when it accesses the EJB. Then the EJB module performs the authorization to check whether we have the required access permission (we have the required role) to further proceed with the invocation.

Note

There is no standard authentication API for plain (not application clients) Java SE applications to access the EJB module. So, if we have a plain Java SE application and we need to access a secured EJB, we should either use the vendor-specific solutions or we should change the Java SE application into a application client module.

Forget about how we can develop the client application which runs on the ACC; we can talk about deployment descriptors which we should make it possible for our client application to send the authentication information to the server, so an authorized user can access what it is authorized to access. These configurations are provided through different deployment descriptor files. The first file is the standard Java EE deployment descriptor for the application client named application-client.xml and a companion vendor-specific deployment descriptor named sun-application-client.xml. We use these two files to configure a callback handler which asks the user to provide specific credentials like username and password or a digital certificate, or it can use the credential which the user used to log into his operation environment.

Two files are bundled with our application client module and deal with internals of our application client such as which resources our application wants to use and how it responds to an authentication request coming from the server.

We need another descriptor file to define where our server is located, how secure our communication channel should be, and which security realm our user should be checked against. This deployment descriptor which provides us with a fair deal of security-related configuration is named sun-acc.xml but we can change the name to something more meaningful.

This file is not bundled with the application client module but rather we pass this file as an argument of the Application Client Container launcher when we want to launch our client application. If we do not pass this file address as an argument, the ACC launcher will try to use a default one. We discuss more about this file in Chapter 3.

By default the Application Client Container uses a simple Swing dialog to collect the username and password when we try to access a restricted EJB from our client application. But we can override the configuration and instruct the Application Client Container to use our own callback handler to collect the authentication information. We may show a very polished Swing frame to collect the username and password or collect any other necessary credentials. The following snippet is a part of the application-client.xml file that instructs the Application Client Container to use our callback handler instead of showing the default dialog box.

<callback-handler>
book.glassfish.security.chapter1.SwingCallbackHandler
</callback-handler>

We simply let the ACC know what the callback handler is and the ACC takes care of initiating and calling its methods when necessary. In addition to a lazy authentication that kick-starts the authentication when we try to access a resource, we can specify a default username and a password for each one of the resources that our client application can access in the sun-application-client.xml file. For example:

<resource-ref>
<res-ref-name>TaskQueueFactory</res-ref-name>
<jndi-name>jms/TaskQueueFactory</jndi-name>
<default-resource-principal>
<name>user</name>
<password>password</password>
</default-resource-principal>
</resource-ref>

The GlassFish application server or any other application server has a default realm which Web Container, EJB container, or ACC will authenticate the users against when an authentication is defined, but for all of them we can override this default realm name with the realm name we require using different types of deployment descriptors.

We can use the sun-acc.xml file for declaring several types of security measures, starting from the authentication down to transport-level security. You may study which options are available in this file to increase you understanding of available ACC security measures.

 

Declaring security roles in Application level


So far we discussed several types of deployment descriptors for Web, EJB, and application client modules. But we know that we usually deploy an archive including all three types of modules known as an enterprise application module. This module is again a ZIP file with EAR extension.

The enterprise application module has its own deployment descriptors named application.xml and sun-application.xml for the vendor-specific deployment descriptor, which in addition to the application structure we can include declarations common between different modules inside them.

In our case, one of the common declarations are security role declarations which are defined using the security-role element inside the application.xml, which is the standard deployment descriptor.

The other common declarations are role-to-group and individual mapping using security-role-mapping element. We put this declaration, which is a vendor-specific declaration, inside the application vendor-specific deployment descriptor, the sun-application.xml file.

We can use sun-application.xml to specify the default authentication realm for the entire application. The default realm specified in the sun-application.xml will be used if an included module does not specify which authentication realm it wants to use. Following snippet shows how we can specify the authentication realm in sun-application.xml.

<sun-application>
<realm>JDBC_REALM</realm>
</sun-application>
 

Summary


Java EE security is a very broad topic which can address small and day-to-day security requirements to large, complex, and unique issues which only can rise for large-scale complex applications.

In this chapter we briefly introduced Web modules, EJB modules, and application client module's security in different levels including authentication, authorization, and transport security. We discussed users, groups, and role mapping down to a good level of detail, along with small topics like HTTP session and performance issues of using cryptography.

In next chapter, we will discuss JAAS and GlassFish security realm in more detail to complete the basic information we need to develop a secure enterprise application in Chapter 3.

About the Author

  • Masoud Kalali

    Masoud Kalali is a Consulting Member of Technical Staff at Oracle. He is the author of Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON published in 2013 and GlassFish Security books published in 2010. He is the author of numerous articles and quick references from Java.Net to Dzone.

    Since 2001, when he started working in different software development roles, he has been blessed enough to work on multiple loosely coupled architecture for high throughput message-based systems with JMS at heart and the rest of the components forming the stops around the JMS as the main messaging bus.

    Performance analysis and performance consulting on architecture, design, code, and deployment configuration is another challenge he has spent some time working on.

    RESTful services and use of RESTful endpoints for data integration is one of the other practices he worked on for data integration for industry leading software systems, IJC and TIBCO Spotfire, during his work at ChemAxon.

    Masoud has worked on security integration as another area, specifically in integration OpenSSO with a solid SOA framework used for developing BPEL flow oriented software

    At his current position at ORACLE he works as the lead engineer in the design and development of application server and PaaS infrastructure of the ORACLE cloud service on top of both OVM/OVAB and Nimbula virtualization providers.

    Masoud’s Twitter handle is @MasoudKalali if you want to know what he is up to.

    Browse publications by this author