Chapter 7: Security

Overview

Security is an important aspect of many enterprise applications. Building a secure application from the ground up, without any support, is an arduous task and certainly not one you would consider doing in a hurry. Thankfully, Java provides an excellent security model that reduces the burden on developers, and puts the creation of secure applications within the grasp of mere mortals .

In this chapter, we'll show you how the J2EE security model is implemented in Oracle 10g AS. Specifically, we'll cover the following:

  • J2EE security model. Here you'll learn some of the core concepts of the J2EE security model, including authorization, authentication, principals, and roles.

  • Java Authentication and Authorization Service (JAAS). This section introduces JAAS and looks at what features the JAAS security model offers.

  • J2EE and JAAS. This section looks at how the JAAS security model works with J2EE as well as where JAAS-based security moves outside the bounds of the basic J2EE security model.

  • JAAS support with JAZNUserManager . The JAZNUserManager is an implementation of the OC4J security model and uses JAAS as the underlying model. It comes complete with two storage mechanisms: XML and Lightweight Directory Access Protocol (LDAP). Much of this chapter is focused on using the JAZNUserManager along with some associated tools.

  • DataSourceUserManager . This offers an alternative to the JAAS-based JAZNUserManager and uses a data source to access user credentials. This chapter provides information about how to use the DataSourceUserManager in your application.

  • Customizing security. At the end of the chapter we'll discuss the options that are available if you want to provide your own security implementation.

Don't worry if some of the things in that list don't make sense yet; all will become apparent as you read the chapter. Although we'll give you a cursory introduction to JAAS, full coverage is outside the scope of this book. If you require more information on JAAS check out the documentation for Java 1.4 provided by Sun (see http ://java.sun.com/products/jaas/overview.html ).

The security documentation for Oracle 10g AS is composed of over ten different manuals and is full to bursting with reference detail on all things related to security. Rather than reproduce that information here, we'll focus on the practical aspects of building and configuring a secure application and refer you to the manual when necessary. If you have trouble finding the security manual online (and you will), the following link will take you straight there: http://download-uk.oracle.com/docs/cd/B10464_02/web.htm . Use the tabs at the top of the screen to navigate to the J2EE, Web Services, & Internet Apps and Management & Security sections, where you'll find individual manuals covering specific topics.

Introduction to J2EE Security

In the J2EE security model, a principal is essentially any entity that could possibly be allowed access to the J2EE server, whether it's an end user, an application, or a device. Whenever you use the term , user, you're typically referring to the principal, which represents that user. Although, in security, a user is always represented as a principal, principals do not always represent users, and may be used to represent groups of users or devices. In the J2EE model, and indeed many other security models, the means of regulating access to the server is based around the following two core concepts:

  • Authentication. This is the process by which a principal asserts its identity to the J2EE container. An end user might enter his username and password; an application might present an SSL certificate; a device might use its IP address.

  • Authorization. This is the process of determining whether or not a principal is allowed to do something within the context of the container.

Within the Servlet container, authorization is URL based. In other words, it's possible to restrict access to certain resources, based on their URL, to a specific set of principals. In the EJB container it's possible to restrict access to bean methods to one or more principals. Both of these authorization mechanisms are configured declaratively within your application's deployment descriptor.

The final piece in the J2EE security puzzle is security roles (or simply, roles ). A role, in J2EE terms, is simply a logical grouping of principals. When configuring J2EE security declaratively you do not mandate a resource or method on a principal-by-principal basis: instead you use roles.

For example, within the Servlet container you would restrict access to the www.foo.com/secure URL to principals Bob and Fred only, instead you would restrict access to that URL to the manager's role, of which Bob and Fred are members .

Introduction to the Java Authentication and Authorization Service

JAAS is a standard API used for building secure applications, and it's fully integrated with OC4J. When you're working with security in an Oracle 10g AS context, most of your interaction with JAAS will be transparent, with the majority of JAAS code working under the hood of the application server.

The JAAS specification allows you to define the authentication and authorization procedures for your application. Using the identity provided during the authentication phase, JAAS will check that the principal (or any of the roles to which the principal is a member) has permission to execute the attempted action.

Authorization in JAAS is much more fine-grained than in J2EE. Using JAAS, you can grant specific permissions to principals using a permission policy . Permissions are implemented as subclasses of the java.security.Permission class, and associated with each Permission class are list of permissible actions. For example, the java.io.FilePermission class defines four permissions: read, write, execute , and delete . Permissions-based security has been around in Java for a long time, but JAAS adds the ability to grant permissions based on the principal, not just on what code is running. When associating a permission with a principal, you specify a target, the meaning of which is permission specific, followed by the actions you wish to allow for that permission. For instance if you want to grant read access to the file /tmp/foo.txt (the target) to the principal Bob, then you would use a Policy similar to this:

 grant {     permission java.io.FilePermission "/tmp/foo.txt", "read"; }; 

This is the standard Sun policy file format. As you'll see later in the chapter, it's also possible to define permissions using an Oracle-specific XML format. Although permissions aren't part of the J2EE specification, they do allow security to be managed at a particularly fine-grained level, which may be useful in some scenarios. However, the main problem with relying on permissions to enforce security in your application is that you're relying on a nonstandard featurenot all application servers use JAAS for security. Since permissions aren't part of the core J2EE security model, we won't be spending much time discussing them, other than to demonstrate how to configure them when using Oracle's JAAS Provider.

JAAS Providers

The JAAS specification provides support for the concept of Pluggable Authentication Modules (PAM). The idea behind PAM is that the authentication logic of the security system is pluggable and can be transparently replaced by different implementations .

In JAAS, you create an authentication module by implementing the javax.security.auth.spi. LoginModule interface. The LoginModule interface is used by JAAS to control authentication of principals. It's the LoginModule implementation that's actually invoked when a user attempts to authenticate with a system. Implementers can choose any mechanism for storing and retrieving principal data. As you'll see, the Oracle JAAS Provider supports both XML and LDAP as a storage mechanism.

Oracle's JAAS Provider also provides custom implementations of the javax.security.auth.login.Configuration and java.security.Policy classes. JAAS uses an instance of the Configuration class to decide which LoginModule implementation to use. By using the Oracle implementation of Configuration , you're telling JAAS to use the Oracle implementation of the LoginModule interface.

The Policy class is used across the whole Java 2 security framework to represent the system's security policy. A security policy in the traditional J2SE sense is the definition of which pieces of code are granted which permissions. JAAS extends this by allowing permissio n s to be granted not only to code but also to principals as part of the system security policy. The default implementation of Policy , reads the security policy from a file in the Sun policy format. Oracle's implementation of Policy allows you to specify which permissions to grant to which prinicipals as part of your application configuration files.

JAAS and J2EE

JAAS is an important specification, and it's useful to be aware of it and to know when to use it. However, although JAAS is now a standard part of the J2SE specification, there's no requirement in the J2EE 1.3 specification for application servers to use JAAS to support the J2EE security mechanism. Although many application server providers, including Oracle, have chosen to do so, their implementations may not be as compatible as you would like due to the exclusion of certain key areas from the JAAS specification. Key omissions from the specification include a definition of how user and role data should be stored, and a standard interface to define management operations such as the creation and deletion of roles and users. As you'll see, the Oracle JAAS Provider provides two storage mechanisms, XML and LDAP, as well as a custom mechanism for managing the data contained in these stores.

Oracle Application Server Security Overview

Figure 7-1 shows the basic setup of security in Oracle 10g AS.

image from book
Figure 7-1: Security in Oracle 10g AS

As you can see in Figure 7-1, clients , whether they're Servlets, standalone applications, or EJBs, are authenticated using the com.evermind.security. UserManager interface. UserManager is an interface of the underlying OC4J container, which provides a uniform mechanism for user and role management. Oracle 10g AS comes with a selection of UserManager implementations, the most widely used being JAZNUserManager and DataSourceUserManager . OC4J also comes with the XMLUserManager , but this is now depreciated in favor of using the JAZNUserManager . In a similar way to the interfaces defined in the JAAS specification, UserManager , and its associated set of interfaces, define a standard mechanism for user authentication and authorization in OC4J.

The JAZNUserManager

Java Authorization (JAZN) is the old, but still widely used, name of the Oracle JAAS Provider. The JAZNUserManager is built on top of JAAS, and as such supports not only the role-based security mechanism of J2EE, but also performs further authorization based on a permission policy (as we mentioned earlier, we won't focus too much on permission policies, other than to cover the syntax required to grant permissions to a user).

The JAZNUserManager is the default UserManager in Oracle 10g AS and, in general, it will suffice for most applications. Since JAAS doesn't specify a mechanism for user storage or management, Oracle has adopted the notion of a realm , which is suggested in the JAAS reference implementation. A realm can be thought of as a logical grouping of users and roles. The JAZNUserManager provides two storage mechanisms for realm data: an XML provider and an LDAP provider. We'll discuss the relative benefits of each of these providers once you have had a chance to see them in action, and see them in the context of the other UserManager implementations available.

Note 

The LDAP provider should really be called the pseudo-LDAP provider. You can only use the LDAP provider if you have Oracle Internet Directory (OID) installed, and it depends on the OID client libraries for communication.

The realm data for JAZNUserManager can be managed using the JAZN Admintool commandline utility. An example of this is shown later.

The XMLUserManager

XMLUserManager is a UserManager implementation that stores user and role data in an XML file. XMLUserManager is built entirely independently of JAAS.

When using the XMLUserManager you store your user and role details in a file called principals.xml , which can be found in the $J2EE_HOME/config directory. XMLUserManager is now considered obsolete and is included for backward compatibility only. If you wish to use XML to store user and role data, then use the XML provider for JAZNUserManager instead. JAZNUserManager allows you to use XML for user and role data storage, and in addition, also provides a simple mechanism for scaling up to OID in the future. This, taken with the fact that you can use any JAAS-compliant LoginModule with the JAZNUserManager , makes it hard to think of any reason why you would want to use XMLUserManager . JAZNUserManager provides all features of XMLUserManager and many, many more.

If you have an application that is using XMLUserManager already, then you should consider migrating this application to JAZNUserManager . To do this you need to move the data contained in principals.xml and add it to the JAZNUserManager configuration. The XML formats used by XMLUserManager and JAZNUserManager aren't identical but converting from one to the other is straightforward.

The DataSourceUserManager

DataSourceManager allows for user and role data to be stored in a database. This is a popular method of storage and can be useful when you want to keep user and role data near your application data. As with XMLUserManager , DataSourceUserManager is built entirely separately from the JAAS framework.

Creating and Configuring a Secure Application

Rather than simply giving you a copy of the data in the manual for each of the UserManager s, you're going to build a simple web application and secure it using the JAZNUserManager , with both XML and LDAP providers. The application will have two J2EE Security roles: sr_admins and sr_users . These roles will be mapped to the admins and users JAAS roles. Then you'll give the admin user membership to the admins role and the user user membership to the users role. Also, you'll see how to make one role a member of another, effectively making all members of the first role members of the second one.

In the final part of this section you'll look at an alternative to the JAZNUserManager , Data-SourceUserManager , which allows you to store your user and role data in a relational database.

Java Virtual Machine Configuration Parameters

Before you begin looking at the example it's important to ensure that you've configured the JVM you use to run Oracle 10g AS correctly. Specifically, the JAAS configuration for the JVM needs to have the JAAS Configuration and Policy classes set to use the Oracle implementations. As we discussed earlier, the use of the Oracle-specific implementations of these classes is a must if you want to use the JAZNUserManager , otherwise JAAS won't be configured to use the correct LoginModule implementations, nor will it be able to read policy information contained in your configuration files. For OC4J you need to set the following lines in the ${JAVA_HOME}/jre/lib/security/java.security file:

 auth.policy.provider=oracle.security.jazn.spi.PolicyProvider login.configuration.provider=oracle.security.jazn.spi.LoginConfigProvider 
Note 

If you're using Java, Standard, or Enterprise Edition and you're using the JVM that came with your edition then you don't need to perform this configuration step. It's already done for you.

If either of these properties is already defined in your java.security file with a different value, then be sure to comment them out or remove them all together.

The HelloServlet Application

The example application is a simple Servlet that displays Hello World, along with some information about the current security context. In order to demonstrate the authentication and authorization processes, you'll set access rights to this Servlet based on the URL of the requesting client.

The code for the HelloServlet class, which is shown here, is very simple:

 package com.apress.oracle10g.security; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HelloServlet extends HttpServlet {     protected void doGet(HttpServletRequest request,             HttpServletResponse response) throws ServletException, IOException {         response.setContentType("text/html");         ServletOutputStream output = response.getOutputStream();         output.println("<html>");         output.println("<head><title>HelloServlet</title></head>");         output.println("<body>");         output.println("<h1>Hello World!</h1>");         output.println(request.getRemoteUser() + "<br>");         output.println("In sr_users role? " + request.isUserInRole("sr_users")                 + "<br>");         output.println("In sr_admins role? "                 + request.isUserInRole("sr_admins") + "<br>");         output.println("</body>");         output.println("</html>");     } } 

As you can see the code processes a GET request and will output "Hello World" , followed by the name of the current user and then a summary of the user's membership in the sr_users and sr_admins roles. You will not create these roles yet, so you can see what happens when you run the application without them. The web.xml file simply configures the Servlet and then maps it to the /* URL pattern, as follows :

 <?xml version="1.0"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app>    <display-name>Hello Servlet Application</display-name>    <distributable />    <servlet>       <servlet-name>helloServlet</servlet-name>       <description>Hello Servlet</description>       <servlet-class>com.apress.oracle10g.security.HelloServlet</servlet-class>    </servlet>    <servlet-mapping>       <servlet-name>helloServlet</servlet-name>       <url-pattern>/*</url-pattern>    </servlet-mapping>    <servlet-mapping>       <servlet-name>helloServlet</servlet-name>       <url-pattern>j_security_check</url-pattern>    </servlet-mapping>  </web-app> 

You should compile and try the application now. You should see that instead of the name of the user, the output is null. The reason for this is that the application isn't subject to any security and that you haven't presented your identity to the Servlet at all.

Note 

If you have trouble building and deploying the application, you can download all the code along with an Ant build script from the Apress website.

Configuring J2EE Security

Configuring the security for the application is simply a matter of selecting the roles that the application will use, specifying the access rights for each role, and then identifying the authentication method. To specify the roles used, you define the security roles, sr_users and sr_admins , in the web.xml file, as follows:

 <!--Configure the roles -->    <security-role>    <role-name>sr_users</role-name>    </security-role>    <security-role>    <role-name>sr_admins</role-name>    </security-role> 

Within a web application, access to resources is restricted to certain roles that are using a URL pattern, as shown here:

 <security-constraint>     <web-resource-collection>       <web-resource-name>Users</web-resource-name>       <url-pattern>/users/*</url-pattern>     </web-resource-collection>     <!--authorization -->     <auth-constraint>       <role-name>sr_users</role-name>     </auth-constraint>   </security-constraint>   <security-constraint>     <web-resource-collection>       <web-resource-name>Administrators Only</web-resource-name>       <url-pattern>/admin/*</url-pattern>     </web-resource-collection>     <!--authorization -->     <auth-constraint>       <role-name>sr_admins</role-name>     </auth-constraint>   </security-constraint> 

In the previous code sample, we have restricted access to any resources with a URI that matches the pattern /users/* to the sr_users role. Likewise access to resources matching /admin/* is restricted to the sr_admins role. If this were an EJB-based application then we could restrict access to certain methods on the EJB to certain roles in the EJB deployment descriptor.

Note 

If you're unfamiliar with how EJB security works then you should read Enterprise JavaBeans 2.1 by Stefan Denniger, Ingo Peters, and Rob Castaneda. (Apress, 2003).

The last step in configuring the J2EE portion of the web application security is to set the authentication method. For web applications the Servlet container takes care of requesting authentication details and validating them using the configured UserManager , in this case JAZNUserManager . Once the Servlet container authenticates your identity, it will use the identity to determine whether or not you're authorized to access certain resources. For this application you'll use BASIC authentication, as follows:

 <login-config>    <auth-method>BASIC</auth-method> </login-config> 

When using BASIC authentication, the users' browsers will prompt them for a username and password that will be transmitted in clear text to the Servlet container. Table 7-1 lists the four types of authentication mechanisms available.

Table 7-1: J2EE Web Application Authentication Methods

Method

Description

BASIC

Basic authentication is performed between the browser and Servlet. The browser will pop up a small window prompting you for a username and password, which are sent to the Servlet in UU-encoded format. This method is insecure unless all communication with the Servlet takes place over SSL. In most cases you won't use BASIC authentication, because FORM -based authentication allows for a much friendlier interface to be presented to users. However, for the sake of this example, BASIC is the simplest authentication method to set up.

CLIENT-CERT

Client certificate authentication is very secure, but is also difficult to configure and not for use in B2C applications. Using CLIENT-CERT , the client browser presents the server with an SSL certificate that asserts the users identity without the need for them to enter any details at all.

DIGEST

From a user perspective, DIGEST authentication functions very much like BASIC authentication. However, the password is passed to the server in a format that isn't easily decrypted.

FORM

Form authentication allows for you to present a friendly, usually HTML-based, form to your users for them to enter their credentials into. As with BASIC authentication, this method of authentication is insecure unless SSL communication is used.

SSO

Single Sign-On isn't a standard J2EE authentication method and relies on Oracle SSO being available in your environment. SSO is great when you have bunch of applications that can be accessed by the same set of users. Using SSO, they sign into a single application and they're automatically signed in to all the applications using SSO.

You cannot specify the use of SSO in the web.xml file; instead, you must specify SSO usage in the orion-web .xml file, like so:

 <jazn-web-app auth-method="SSO" /> 

The use of the Oracle SSO is covered in more detail in Chapter 20.

Configuring the XML Provider

By default JAZNUserManager is configured to use the XML provider as the data store for realm data. You can choose to store your realm data either in the master jazn-data.xml file in the $J2EE_HOME/config directory or in a file local to your application. You can even change the file-name if you wish, although it's probably a good idea to stick with jazn-data.xml to make it easier for other developers working with your application. If you choose to use the master file, you can change its location by modifying the following entry in $J2EE_HOME/config/jazn.xml :

 <jazn provider="XML" location="./jazn-data.xml" /> 

Storing realm data locally for your application means that you don't have to play around with the global configuration files and you can keep all your application data together in one place. However, using a local file does make manipulating the data using the JAZN Admintool slightly more difficult, although not impossible . At the end of the day you're free to use whichever implementation is best suited to your environment. It may be that you have a lot of applications using different security realms, in which case using application-specific files makes sense. However, if you have a few applications all sharing the same realm data, then using the global file is probably the best option.

To configure JAZN to use the XML provider and a local realm data store, add the following entry to your orion-application.xml file:

 <jazn provider="XML" location="./jazn-data.xml"/> 

This line specifies that the application will be using the XML provider and that the realm data will be stored in a file called jazn-data.xml in the same directory as orion-application.xml .

Configuring Users and Roles in jazn-data.xml

Now you need to actually define the realms, users (principals), and JAAS roles that will make up the application. For the purpose of this application the security configuration will be as follows:

  • You will create a single realm called helloServlet , which contains two roles: administrators and users ; and two users: admin and user .

  • The user called user will be a member of the users role.

  • The user called admin will be a member of the administrators role.

  • The administrators role will be a member of the users role, so that all members of the administrators role are implicitly members of the users role.

Later you'll define a mapping between these JAAS roles, configured in jazn-data.xml , and the sr_admins and sr_users J2EE roles configured earlier in the web.xml file.

Note 

If you're using Java, Standard, or Enterprise Edition then you can configure the JAZN realm data using the Application Server Control (ASC) utility. As with Admintool you're unable to configure users if you're using the LDAP provider; instead, you must use the Delegated Administrative Service (DAS) to create users in OID.

The format of the jazn-data.xml file is quite complicated, so we'll include the code in full punctuated by explanations of the individual pieces, as follows:

 <?xml version="1.0" standalone='yes'?> <!DOCTYPE jazn-data PUBLIC "JAZN-XML Data" "http://xmlns.oracle.com/ias/dtds/jazn-data.dtd"> <jazn-data> <!--JAZN Realm Data --> <jazn-realm>     <realm>         <name>helloServlet</name> 

The file starts by declaring the realm and giving it a name, in this case, helloServlet . Next come the user definitions, as shown here:

 <users>    <user>       <name>admin</name>       <display-name>Administrator</display-name>       <credentials>!pwd</credentials>    </user>    <user>       <name>user</name>       <display-name>User</display-name>       <credentials>!pwd</credentials>    </user>    <user>       <name>anonymous</name>       <description>The default guest/anonymous user</description>    </user> </users> 

The XML for creating users is pretty simple to understand: Each user is given a name, which is the username used when authenticating with the system, and a display name that's displayed in the ASC. The <credentials> tag specifies the user password, prefixed by a ! character, which indicates that the password is in plain text. When you deploy the application, Oracle 10g AS will encrypt the password in the deployed instance of the system. If you use JAZN Admintool (shown later) to add a user to a realm then the password is already encrypted for you. The same is true when you're using ASC in Java, Standard, or Enterprise Edition.

Now that you've created the users, all that's left for this configuration file is to create the roles, as shown here:

 <roles>     <role>         <name>administrators</name>         <display-name>Administrator Role</display-name>         <members>             <member>                         <type>user</type>                         <name>admin</name>                     </member>                 </members>             </role>             <role>                 <name>users</name>                 <display-name>User Role</display-name>                 <members>                     <member>                         <type>user</type>                         <name>user</name>                     </member>                     <member>                         <type>role</type>                         <name>administrators</name>                     </member>                 </members>             </role>         </roles>     </realm> </jazn-realm> 

Again the XML is fairly self-explanatory. The main point of interest here is that for the administrators role, we've specified one member: the admin user. However, for the users role, we've specified two members: the user with username user , and the administrators role. This means that instead of having to add a new administration user to both the administrators and users roles, we just need to add them to the administrators role.

The remaining elements are unimportant at this point, but here's how it looks:

 <!--JAZN Policy Data --> <jazn-policy> </jazn-policy> <!--Permission Class Data --> <jazn-permission-classes> </jazn-permission-classes> <!-Principal Class Data --> <jazn-principal-classes> </jazn-principal-classes>' <!--Login Module Data --> <jazn-loginconfig> </jazn-loginconfig> </jazn-data> 

The <jazn-policy> element is used to assign specific permissions to a principal. So if you wanted to allow all users in the helloServlet realm to access EJBs using their remote interfaces they would need to be granted the login action of com.evermind.server.rmi.RMIPermission , as follows:

 <grant>    <grantee>       <principals>          <principal>             <realm-name>helloServlet</realm-name>             <type>role</type>             <class>oracle.security.jazn.spi.xml.XMLRealmRole</class>             <name>helloServlet/users</name>          </principal>       </principals>    </grantee>    <permissions>       <permission>          <class>com.evermind.server.rmi.RMIPermission</class>          <name>login</name>       </permission>    </permissions> </grant> 

The <class> and <name> of the <permission> are specific to the resource that you're granting permission to, and they correspond to the name of the permission implementation class and the action you wish to grant. The <principal> tag specifies which user or role the permission is being granted to. In this case it's the users role in the helloServlet realm.

An example of how to use <jazn-policy> can be found in the global jazn-data.xml file. The <jazn-permission-classes> and <jazn-principal-classes> appear to be entirely undocumented. Outside of code examples containing them as empty elements, there's no mention of either element on the Oracle site and a Google search displays very little. The <jazn-login-config> tag is used to map LoginModules to different applications. Later on in the chapter you'll see how this tag is used when configuring a custom LoginModule .

Mapping J2EE Roles to JAAS Roles

In the last section you created the users and administrators roles, and assigned users to each role. In this section you'll see how to map these JAAS roles to the J2EE roles specified in the web.xml file. Doing so is remarkably easy, requiring just a few extra entries in the orion-application.xml file, as shown here:

 <security-role-mapping name="sr_users">    <group name="users" /> </security-role-mapping> <security-role-mapping name="sr_admins">    <group name="administrators" /> </security-role-mapping> 

Each <security-role-mapping> element in the preceding example links one J2EE Security role to one JAAS role. In actual fact you're mapping to an OC4J group, part of the UserManager infrastructure, but the JAZNUserManager maps these one to one with JAAS roles specified in the jazn-data.xml file. So you can see that the users JAAS role is mapped to the sr_users J2EE security role and the administrators JAAS role is mapped to the sr_admins J2EE security role.

Try Out the Application

You're now ready to deploy the application and try it out. Once deployed point your browser at http://localhost:8888/helloServlet (or the URL appropriate to your environment) as shown in Figure 7.2.

image from book
Figure 7-2: No authentication

Notice that the username is null and that your membership in both roles is false. Now visit a resource under the /users/* URI. You'll be prompted by your browser to provide the username and password. Use the username, user , and the password, pwd , to log in as user in the users role as shown below in Figure 7.3.

image from book
Figure 7-3: Authenticated as a member of the users role

Now you can see that the username is set to helloServlet/user (the realm-qualified user-name), and that your membership in the sr_users role shows up as true. Remember that the sr_users J2EE role is mapped to the users JAAS role. Now visit a resource under the /admin/* URI. You're prompted again for a username and password, even though you already specified one. The reason for this is that even though your identity has been authenticated by the application server, the application has determined that you're not authorized to view resources under the /admin/* URI. Enter the user name, admin , and the password, pwd , as shown in Figure 7-4.

image from book
Figure 7-4: Authenticated as a member of the administrators role

Now you can see that username is set to helloServlet/admin and that you're a member of both roles.

Administering the HelloServlet Application with JAZN Admintool

JAZN Admintool is a command-line utility that allows you to configure JAZN realm data without the need to modify the XML configuration file directly. Admintool can be used to manage realm data for both the XML and LDAP providers. However, when using the LDAP provider you're unable to add or remove any users using Admintool. Instead you must use the DAS, as discussed later in the chapter in the "Configuring Oracle Internet Directory" section.

Unfortunately, the documentation doesn't explain how to use the JAZN Admintool to configure applications that store realm data in local XML files. However, it's possible to use the JAZN Admintool to manage your application, and we're going to show you how. The JAZN Admintool has a wide array of commands. We'll demonstrate the most useful here, and details on the rest can be found in the documentation. You should note that OC4J doesn't need to be running to use the JAZN Admintool.

First of all, open up a terminal or command window and change to the $J2EE_HOME directory. The basic command syntax for JAZN Admintool is as follows:

 java jar jazn.jar user <user_name> password <passsword> <admintool_command> <admintool_options> 

By default Admintool looks in the global jazn.xml file to determine the location of the global jazn-data.xml file. This is the file it will write its changes to. To change the config file that's used to locate the jazn-data.xml file you can set the oracle.security.jazn.config system property when running the tool. The username and password are required when using Admintool to manage XML realm data. When managing application-specific files, you can use any username and password combination from the file. So to list all the realms defined for the Hello Servlet application you would use the following:

 java -Doracle.security.jazn.config=application-deployments/helloServlet /orion-application.xml / -jar jazn.jar -user admin -password pwd -listrealms 

Notice that we've pointed Admintool to the orion-application.xml file instead of the global jazn.xml file. The oracle.security.jazn.config property should point to the file that contains the <jazn> element; from there Admintool will locate the correct jazn-data.xml file.

The last part of the command, listrealms , is the important part. This is the Admintool command. Whenever you run Admintool the first part of the command text will always be the same up to specifying the password regardless of which Admintool command you wish to run. All that changes is what comes after your password.

The -listrealms command isn't very useful. You already know what realms are specified by the HelloServlet application (it's the helloServlet realm). It's useful, however, to be able to retrieve a list of users and roles in a particular realm. This is achieved by using the listusers and listroles commands, each of which takes the realm name as a parameter. Consider the following command:

 .. listuser helloServlet 

We've excluded the first part of the command since it never changes. For the HelloServlet application this would yield the following:

 user admin 

To find out which roles a particular user is a member of, use the listroles command, which specifies both the realm and the user, as shown here:

 > ..-listroles helloServlet admin users administrators 

The command you're likely to use most often is the adduser command. To add a user with username foo and password bar to the helloServlet realm, use the following command:

 > ..-adduser helloServlet foo bar 

A nice part of Admintool is that it will automatically encrypt the user's password for you. To make the foo user and member of the user role use the grantrole command, as follows:

 >..-grantrole users helloServlet foo 

Changes made to the XML realm data store aren't picked up until you restart OC4J, so do that now and then try to log in to the HelloServlet application using the foo user.

Using the JAZNUserManager LDAP Provider

In the previous section you created a basic secure application using the Oracle JAAS Provider (JAZN) and the JAZN XML provider. In this section you'll reconfigure the application to make use of the LDAP provider instead.

Configuring Oracle Internet Directory

The first step is to configure the OID, adding the appropriate users and roles to the directory. If you're unfamiliar with how to install OID then see Chapters 20 and 21 to obtain installation and startup instructions.

Configuring the OID for the HelloServlet application is a trivial job. You need to add two users: user and admin , and then add two groups: users and administrators.

To add the groups, log in to the OID DAS and click the Directory tab on the home page. After logging in through SSO page, click the User tab, and then click Create as shown in Figure 7-5.

image from book
Figure 7-5: Create User page

On the Create User page, enter all the resource information for the user user under the Basic Information section. Be aware that the minimum size for passwords is five characters . Once you're finished, click the Submit button in the top right of the screen. Repeat this process to create the directory entry for the admin user.

The next task is to create the users group. Click the Group tab at the top of the screen and then click the Create button, as shown in Figure 7-6.

image from book
Figure 7-6: Create Group page

Under the Basic Information section enter the information for the users group, and then scroll down to the Members section, as shown in Figure 7-7.

image from book
Figure 7-7: Create Group Members section

Click the Add User button to display the Select User page. On the Select User page click the Go button to display a list of all users. Select the user user and then click the Select button. Back on the Create Group page, click either of the Submit buttons to complete the process. Repeat the process for the administrators group.

Configuring the HelloServlet Application

With the user and group data created for the LDAP provider, all that remains is to configure the HelloServlet application to use the LDAP provider instead of the XML provider. To do this you simply replace the existing <jazn> tag in orion-application.xml with the following: <jazn provider="LDAP" />

This is all that's required. Redeploy the application and try to log in using the usernames and passwords for the users you created in OID. Once you're logged in you should get something like what's shown in Figure 7-8.

image from book
Figure 7-8: Authenticated using LDAP provider

Notice that realm of the username has changed from helloServlet to the name of the OID instance, in the case of the following image, tiger .

Using DataSourceUserManager

Until now you've been working solely under the Oracle JAAS Provider, JAZNUserManager . However, as we mentioned earlier, the main security mechanism in OC4J is the UserManager . Oracle is pushing the JAZNUserManager extensively, which in the long term may prove to be useful, but currently, there's still place for the other UserManager s as well for custom UserManager s in your J2EE applications. In this section you'll see how you can use the DataSourceUserManager to store user details in a database. The main reason you would want to use the DataSourceUserManager is if you're already storing user credentials in a database. This is a pretty common occurrence in web-based applications and it may be that you aren't ready to move to OID just yet. In this case DataSourceUserManager should be able to help you out. However, if you're starting from scratch and wondering where best to store your user credentials, then we would definitely recommend that you investigate using OID. OID provides a highly scalable solution, and the directory-based data structures are optimized for data that is read mostly, which most user data typically is, especially login credentials.

DataSourceUserManager Overview

The setup of DataSourceUserManager is quite strange . Rather than storing everything in the database, the DataSourceUserManager stores the roles (called groups in UserManager terms) in the same XML file used by the XMLUserManager, principals.xml , and stores the users along with their membership of the various roles, in the database. At first this sounds like a limiting factor, but only to a small degree. We find that in most applications the actual roles change very rarely; often they're defined during the creation of the application and never change. However, if a new role is required and you want to limit access to some resources based on membership in that role, then you're going to have to update the deployment descriptors of your application anyway, so what is the harm in adding the role declaration to an XML file? When configured correctly you can also manage the DataSourceUserManager using ASC.

Creating the Tables

The database needs two different tables, one to hold the user data and the other to hold data to link the users to their roles.

The users table requires at least two fields, one to store the user name and the other to store the passwords. A typical SQL command to create this table will look like this:

 CREATE TABLE user (username varchar(64) PRIMARY KEY, password varchar(64) NOT NULL); 

The names are arbitraryyou can call them what you like. The table for mapping users to their roles also requires two fields, one to store the username and the other to store the role name, as follows:

 CREATE TABLE usergroups (username varchar(64) NOT NULL, groupname varchar(64) NOT NULL, PRIMARY KEY(username, groupname)); 

Again the names you use are completely arbitrary.

Creating the Data Source

Since this is the DataSourceUserManager , you're going to need a data source. Create an entry in data-sources.xml for the data source containing the tables you just created:

 <data-source    class="com.evermind.sql.DriverManagerDataSource"    name="OracleDS"    location="jdbc/OracleCoreDS"    xa-location="jdbc/xa/OracleXADS"    ejb-location="jdbc/OracleDS"    connection-driver="oracle.jdbc.driver.OracleDriver"    username="user"    password="pwd"    url="jdbc:oracle:thin:@80.176.127.94:1521:orcl"    inactivity-timeout="30" /> 

You're not limited to using just the Oracle database; you can point your data source at any database that has a JDBC driver.

Configuring the HelloServlet Application

Configuring the HelloServlet application is relatively easy. The first job is to create the principals.xml file, and specify the basic roles available:

 <?xml version="1.0" standalone='yes'?> <!DOCTYPE principals PUBLIC "//Evermind -Orion Principals//" "http://xmlns.oracle.com/ias/dtds/principals-9_04.dtd"> <principals>    <groups>       <group name="administrators">          <description>administrators</description>          <permission name="administration" />       </group>       <group name="users">          <description>users</description>          <permission name="rmi:login" />       </group>    </groups> </principals> 

Notice that we've defined two roles: users and administrators . Also notice that we've assigned the RMI login permission to members of the user's role, thereby allowing them to access EJBs running over remote interfaces. This is synonymous with the RMI permission given to this group in jazn-data.xml . Again, the permission isn't part of the J2EE security, but instead it's part of the underlying security model of OC4J.

To tell OC4J where the principals.xml file is, you need to add a <principals> element to the orion-application.xml file, as shown here:

 <principals path="./principals.xml"/> 

The next job is configure the UserManager itself, again in the orion-application.xml file, as follows:

 <user-manager class="com.evermind.sql.DataSourceUserManager">         <property name="dataSource" value="jdbc/HelloServletDS"/>         <property name="table" value="users"/>         <property name="debug" value="true"/>         <property name="userNameField" value="username"/>         <property name="passwordField" value="password"/>         <property name="groupMembershipTableName" value="usergroups"/>         <property name="groupMembershipGroupFieldName" value="groupname"/>         <property name="groupMembershipUserNameFieldName" value="username"/>     </user-manager> 

All UserManager s require that the class attribute of the <user-manager> tag is specified. The <property> tags are specific to the individual UserManager . Here you can see that we have parameters for the data source, the tables in the database, and the names of the fields in the tables. We've also set the debug parameter to true, which is helpful when you're trying to set up the DataSourceUserManager .

That's the final piece of configuration; all you need to do is add some sample data to the database, defining some users and their membership in the users and administrators roles, and you're ready to deploy the application and try it out.

Customizing Security

As you've seen Oracle 10g AS provides full support for J2EE security through the use of UserManager s. Oracle is pushing JAZNUserManager in a big way, and it has the fullest support for creating a secure application. The other main UserManager is DataSourceUserManager , but this suffers from the problem that the passwords are stored in plain text in the database. However, it's possible to extend the support for user authentication and authorization in two ways: by using a custom UserManager or a custom JAAS LoginModule .

Custom UserManagers

If you require custom authentication for your application and you want to take advantage of the ASC management tool, then you need to create a custom UserManager . Creation of a custom UserManager is outside the scope of this chapter, but you can find an excellent article on the topic at http://kb.atlassian.com/content/orionsupport/articles/usermanager.html?printable=true . Custom UserManager s are configured in the same way as DataSourceUserManager , using the <user-manager> tag in the orion-application.xml file.

Custom LoginModules

If you don't require the ASC support, then you may want to consider creating a custom JAAS LoginModule that can be used in conjunction with the JAZNUserManager . The LoginModule interface only considers the authentication of users and matching them to roles. There's no consideration for managing the user store and no integration with ASC. However, custom LoginModule s are portable between application servers that have JAAS-based security methods. We aren't going to show you how to create a custom LoginModule . That is certainly outside the scope of this chapter, although you'll find plenty of information about the subject on the Web. To use a custom LoginModule , such as the com.sun.security.auth.module.UnixLoginModule , which is included in the JDK, within your application you must be using the JAZNUserManager with the XML provider. In the jazn-data.xml file, you need to configure the LoginModule using the <jazn-loginconfig> tag, as follows:

 <jazn-loginconfig>    <application>       <name>helloServlet</name>       <login-modules>          <login-module>             <class> com.sun.security.auth.module.UnixLoginModule </class>             <control-flag>required</control-flag>          </login-module>       </login-modules>    </application> </jazn-loginconfig> 

UserManager or LoginModule

Choosing whether or not to use UserManager or LoginModule for your custom security provider can be a difficult decision, however, it's a decision you may not need to make. Both UserManager and LoginModule are interfaces, so there's nothing stopping from you creating a class that uses the same internal logic to implement both interfaces. Indeed, if you're intending to implement UserManager in order to integrate with the ASC, then it will require little effort to implement the LoginModule interface as well. If you're primarily developing a LoginModule for use on multiple application servers, then creating a fully functional UserManager will require that you create much more logic in order to support the user and role creation functions of the UserManager . However, it's likely that you will need to create a login in order to support user management, so you should consider encapsulating this as part of the UserManager interface.

Choosing Your Security Method

Oracle 10g AS gives you a wide range of security choices for your applications. Making the decision can be quite difficult, but in general there are only a few different scenarios. For development purposes, the XML provider of JAZNUserManager is generally the best choice. It makes it simple for developers to work and test in isolation. My preference for deployment is almost always the OID and JAZNUserManager combination, especially in enterprise settings. Directory-based storage is generally faster than database for applications that are predominately read only. In an enterprise setting, aside from the initial data population, the number of users won't change that often. Certainly you shouldn't expect to see more than a handful of modifications each day (unless your enterprise has particularly bad staff retention!). In a Business-to-Customer (B2C) setting, especially in Internet applications, where you allow users to register their own details (think Amazon.com), it may be wise to consider the use of a relational database, in which case the DataSourceUserManager will suffice. Still, you may want to consider a custom implementation that will encrypt passwords for storage in the database. However, even in this scenario the OID choice might still be valid, but you'll want to do some performance testing before you commit to this.

Of course if you have specific storage requirements then you're going to have to build a custom implementation. The choice then is which kind of custom implementation, Login-Module or UserManager , but as we mentioned earlier you don't necessarily need to make this choice.



Oracle Application Server 10g. J2EE Deployment and Administration
Oracle Application Server 10g: J2EE Deployment and Administration
ISBN: 1590592352
EAN: 2147483647
Year: 2004
Pages: 150

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net