Defining Realms in SJSAS
The application server supports five kinds of realms, but three of them are used most often: file realms, JDBC realms, and certificate realms.
File Realm
In a file realm, users and groups are stored in a file. This realm is represented by the following class:
com.sun.enterprise.security.auth.realm.file.FileRealm
By default, SJSAS contains two file realms:
- file has the following corresponding file:
{SJSAS_HOME}\domains\domain1\config\keyfile
- admin-realm has the following corresponding file:
{SJSAS_HOME}\domains\domain1\config\admin-keyfile
Initially, admin-realm contains the administrator's username and password (in an encrypted format), and the group to which this user belongs, which is asadmin by default.
JDBC Realm
In a JDBC realm, users and groups are stored in a database. This realm is represented by the following class:
com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm
By default, SJSAS doesn't contain JDBC realms.
Certificate Realm
In a certificate realm, users' identities are set up in the SJSAS security context and populated with user data obtained from cryptographically verified client certificates. This realm is represented by the following class:
com.sun.enterprise.security.auth.realm.certificate.CertificateRealm
By default, SJSAS contains a realm named certificate.
Creating a File Realm in SJSAS
Following are the basic steps to declare a new file realm in SJSAS:
- Start the Sun Java System Application Server.
- Launch the Admin Console in your favorite browser (by default, the URL is http://localhost:4848/asadmin).
- Log into the Admin Console. Provide a name and the password of a user in the admin-realm who belongs to the asadmin group.
- In the Admin Console tree (left pane), expand the Configuration > Security node and select the Realms node. In the right pane, you should see a table with the available realms (see Figure 1).
- Click the New button above the table to open the New Realm wizard.
- In this wizard, we need to fill in some fields. Start by entering a realm name in the Name field (for example, type MyFileRealm).
- Next, select the realm type. From the drop-down list, select the option com.sun.enterprise.security.auth.realm.file.FileRealm. This will indicate that the new realm is a file realm.
- Continue by indicating a Java Authentication and Authorization Service (JAAS) context. By default, this context is fileRealm, and it's best to leave this setting unmodified. (We won't go into this option in detail here.)
- In the last mandatory field, enter the path and name of the file that stores usernames and passwords. To indicate a file path relative to the SJSAS installation folder, use the property ${com.sun.aas.instanceRoot} (for example, my setup uses C:\Sun\SDK\domains\domain1 folder). Our filename is myFile and it's stored in the folder ${com.sun.aas.instanceRoot}/config (this file will be created automatically).
- At this point, we could assign a group to the realm (using the Assign Group field), but let's just leave this field empty for this example.
- Click OK to finish configuring the new file realm (see Figure 2).
The new file realm is added to the table of realms. Follow these steps to manage the realm's users:
- Click the MyFileRealm link and then click the Manage Users button.
- In the resulting wizard, users are listed/added in the Users table. (This table is empty because we hadn't added any users in the previous procedure.) Click the New button above the Users table to launch the New File Realm User wizard.
- For each new user you want to add, specify the user's name (user ID), group (if desired, since it's not mandatory to put users into groups), and password. For this example (see Figure 3), create a user in the SERVLET-USERS group (username MaryJane, password mary2008) in the left pane. In the right pane, create a user in the JSP-USERS group (username TimmyTom, password tom2008). Click OK to add each user.
- After you add the users, they're listed in the Users table (see Figure 4).
- Restart the Sun Java System Application Server to make sure that the new realm is configured and recognized.
Creating a JDBC Realm in SJSAS
A JDBC realm provides a dynamic environment for managing users and groups, based on a simple database containing two tables: One table stores the users and the other stores the groups. Both tables use the username (ID) as the primary key. The SJSAS knows how to relate the two tables for extracting the corresponding information and accomplishing the authentication phase. SJSAS accepts most of the popular relational database management systems (RDBMS)—PostgreSQL, MySQL, Oracle, DB2, and so on. We chose to use PostgreSQL for this example. Follow these steps to start creating a new JDBC realm:
- Use the following SQL statements to create the realm database and the two tables:
CREATE DATABASE secure CREATE TABLE grouptable (USERID VARCHAR(255) NOT NULL, GROUPID VARCHAR(255), PRIMARY KEY (USERID)) CREATE TABLE usertable (USERID VARCHAR(255) NOT NULL, PASSWORD VARCHAR(255), PRIMARY KEY (USERID))
- Populate the tables with a set of users, using the following SQL statements:
INSERT INTO usertable (USERID, PASSWORD) VALUES ('MarchusRuhl', 'marchus2008') INSERT INTO usertable (USERID, PASSWORD) VALUES ('ShawnRay', 'shawn2008') INSERT INTO grouptable (USERID, GROUPID) VALUES ('MarchusRuhl', 'SERVLET-USERS') INSERT INTO grouptable (USERID, GROUPID) VALUES ('ShawnRay', 'JSP-USERS')
In real life, you would provide a JSP/HTML interface for exposing to users the possibility of creating/deleting accounts in the database. A possible scenario might involve two entity EJBs for the two tables, a persistence.xml to reveal a persistence unit (through JTA, for example), and a stateless EJB that would take care of managing the database (creating/deleting accounts). Developing such a complete application is beyond the scope of this series, but we can provide the main pieces of code (you just have to put them together in a Java EE application). For example, the two entity EJBs might look like Listings 5 and 6.
Listing 5 UserAccount.java.
package ejbs.entities;
import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table;
@Entity @Table(name = "usertable") public class UserAccount implements java.io.Serializable {
@Id private String userID;
private String password;
public UserAccount() { }
public String getUserID() { return userID; }
public void setUserID(String userID) { this.userID = userID; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; } }
Listing 6 UserGroup.java.
package ejbs.entities;
import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table;
@Entity @Table(name = "grouptable") public class UserGroup implements java.io.Serializable {
@Id private String userID;
private String groupID;
public UserGroup() { }
public String getUserID() { return userID; }
public void setUserID(String userID) { this.userID = userID; }
public String getGroupID() { return groupID; }
public void setGroupID(String groupID) { this.groupID = groupID; } }
The persistence.xml might look like Listing 7.
Listing 7 persistence.xml.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="ManageAccounts" transaction-type="JTA"> <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider> <jta-data-source>auth/jdbc</jta-data-source> <class>ejbbook.examples.ejbs.entities.UserAccount</class> <class>ejbbook.examples.ejbs.entities.UserGroup</class> <properties> <!-- <property name="toplink.logging.level" value="INFO"/> --> <property name="toplink.target-database" value="PostgreSQL"/> <property name="toplink.ddl-generation" value="drop-and-create-tables"/> <property name="toplink.application-location" value="{your_app_path}\DDLs\"/> <property name="toplink.create-ddl-jdbc-file-name" value="createDDL.sql"/> <property name="toplink.drop-ddl-jdbc-file-name" value="dropDDL.sql"/> <property name="toplink.ddl-generation.output-mode" value="both"/> </properties> </persistence-unit> </persistence>
Moreover, the stateless EJB may contain a simple method like the following to store users (we're using the MD5 algorithm to encrypt the password, but SHA-256 is also supported):
... @PersistenceContext(unitName="ManageAccounts") protected EntityManager manager; ... public String storeUser(String user_email, String user_password, String user_group) {
try { MessageDigest md = MessageDigest.getInstance("MD5"); md.reset();
byte[] bytes = md.digest(user_password.getBytes()); StringBuilder sb = new StringBuilder(2 * bytes.length); for (int i = 0; i < bytes.length; i++) { int low = (int)(bytes[i] & 0x0f); int high = (int)((bytes[i] & 0xf0) >> 4); sb.append(HEXADECIMAL[high]); sb.append(HEXADECIMAL[low]); }
user_password = sb.toString();
UserAccount newAccount = new UserAccount();
newAccount.setUserID(user_email); newAccount.setPassword(user_password);
manager.persist(newAccount);
if(!user_group.equals("user (no group)")) { UserGroup userGroup = new UserGroup();
userGroup.setUserID(user_email); userGroup.setGroupID(user_group);
manager.persist(userGroup); }
return "Success";
} catch (Exception e) { return "Error:" + e.getMessage(); } }
At this point, you're ready for more steps:
- Start the Sun Java System Application Server and launch the Admin Console (usually the URL is http://localhost:4848/asadmin).
- Next, you need to create a connection pool (see Figure 5). Expand the Resources > JDBC node and select the Connection Pool node. In the Pools table, click the New button. Provide a name for the connection pool (for example, AuthPool), a resource type (for example, select javax.sql.DataSource from the drop-down list), and a database vendor (for example, select PostgreSQL from the drop-down list if you have a PostgreSQL distribution installed and ready to go). Click Next.
- Now you have to choose some core settings for the connection pool. Most of these settings have default values, which are rarely modified. Your main job here is related to the Properties table (bottom of the page in the Transaction section). In this table, you have to provide important settings for your realm database: database name, RDBMS port, database user and password, etc. Figure 6 shows an example of how to fill in these fields for a PostgreSQL secure database:
- After you finish this table of properties, your job is nearly done. Click Finish. Open your new connection pool in the Pools table and click the Ping button at the top of the page to see if the database connection works. Before going further, you must receive a message such as Ping Succeeded.
- You're ready to create a JDBC resource. Expand the Resources > JDBC node and select the JDBC Resources node. In the Resources table, click the New button. Provide a Java Naming and Directory Interface (JNDI) name (for example, auth/jdbc) and a connection pool (select AuthPool from the drop-down list). Select the Enabled check box to activate the new JDBC resource (see Figure 7). Click OK.
- The next step is to create a JDBC realm based on the JDBC resource. Expand the Configuration > Security node and select the Realm node. In the Realms table, click the New button. Indicate a realm name in the Name field (for example, MyJDBCRealm) and choose the realm class from the Class Name drop-down list (for example, select com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm).
- Fill in the rest of the information or use the default settings for the secure database, as shown in Figure 8. (We type none for the digest algorithm because we've provided the user's passwords in simple text; if you want to use a digest algorithm, MD5 and SHA-256 are supported.) When you're finished, click OK to add the new realm to the Realms table.
- Restart the Sun Java System Application Server to make sure that the new realm is configured and recognized.
Editing the Certificate Realm
By default, SJSAS defines a certificate realm that supports the SSL authentication mechanism. Later you'll see how to activate the SSL support, but for now it's important to know that this realm populates the SJSAS security context with user data obtained from cryptographically verified client certificates in the keystore (by default, ${com.sun.aas.instanceRoot}/config/keystore.jks) and truststore (by default, ${com.sun.aas.instanceRoot}/config/cacerts.jks) files. In addition, this realm sets up the user identity in the SJSAS security context
Since we're in the development phase, we'll show you how to create a self-signed certificate and how to create/indicate a new keystore and truststore. This is a job for http://java.sun.com/j2se/1.3/docs/tooldocs/win32/keytool.html". Follow these steps:
- Create the keystore (our keystore name is mykeystore.jks and it's placed in the ${com.sun.aas.instanceRoot}/config folder). Open a command prompt and point to the ${com.sun.aas.instanceRoot}/config folder. Run the following keytool statement:
keytool –genkey –alias s1as –keyalg RSA –keypass changeit –storepass changeit –keystore mykeystore.jks
When you press Enter, keytool prompts you to enter the first and last name, organizational unit, organization, locality, state, and country code. For the first and last name, type the server name. In our case, this is localhost.
- Export the generated server certificate in mykeystore.jks into the file myserver.cer:
keytool –export –alias s1as –storepass changeit –file myserver.cer –keystore mykeystore.jks
- Create a truststore named mycacerts.jks and add the server certificate (myserver.cer) to it:
keytool –import –v –trustcacerts –alias s1as –file myserver.cer –keystore mykeystore.jks –keypass changeit –storepass changeit
- When you press Enter, you'll see a list of details about the certificate. Based on these details, you have to decide whether the certificate is a trust certificate. Obviously, we have to accept the certificate as trusted, so type yes to this question and press Enter.
- Our certificate is ready to use in the development phase. If you want to go further, in the production phase, than you have to obtain digitally signed certificate from a certificate authority.
Now we have to indicate to the SJSAS to use mykeystore.jks instead of keystore.jks, and mycacerts.jks instead of cacerts.jks. Follow these steps:
- Start the SJSAS, launch the Admin Console (usually the URL is http://localhost:4848/asadmin), and log into the Admin Console.
- Click the Application Server node.
- Switch to the JVM Settings tab.
- Switch to the JVM Options tab.
- Find the keystore property:
-Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/keystore.jks
- Modify the property as follows:
-Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/mykeystore.jks
- Find the truststore property:
-Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/cacerts.jks
- Modify the property as follows:
-Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/mycacerts.jks
- Click Save.
- Restart the Sun Java System Application Server to make sure that the modifications are added and recognized.
Creating a New Certificate Realm
Follow these steps to create a new certificate realm:
- Expand the Configuration > Security node and select the Realm node.
- In the Realms table, click the New button.
- In the New Realm wizard, provide a name for this realm (for example, MyCertificateRealm) and select its corresponding class:
com.sun.enterprise.security.auth.realm.certificate.CertificateRealm
- (Optional) If desired, assign a group to this realm and/or specify a list of additional properties in the Additional Properties table.