BEA Logo BEA WebLogic Server Release 5.0

  Corporate Info  |  News  |  Solutions  |  Products  |  Partners  |  Services  |  Events  |  Download  |  How To Buy

Using WebLogic Realms and Acls

I. Introduction
WebLogic Server access control
WebLogic security realms
About Access Control Lists (Acls)
About alternative security realms

II. Realm administration
Setting up Users, Groups, and Acls in the WebLogic realm
Permissions for WebLogic services

III. WebLogic Security SPI
Overview of WebLogic Security SPI

IV. Implementing with the WebLogic Security SPI
Connecting to WebLogic Server from a Java class
SSL two-way authentication from a Java client
Using custom Acls
Mapping a client certificate to a WebLogic user
Auditing security events
Filtering network connections
Creating a custom security realm
Delegating to multiple realms

Other related documents
Guide to WebLogic Server security documentation
Installing WebLogic (non-Windows)
Installing WebLogic (Windows)
Administering the WebLogic caching realm
Administering the WebLogic LDAP security realm
Administering the WebLogic Windows NT security realm
Administering the WebLogic UNIX security realm
Using WebLogic SSL
Developers Guides
API Reference Manual
Code examples
Glossary

I. Introduction

WebLogic Server access control

WebLogic Server includes a powerful and flexible access control system to protect your applications and the back-end services that your clients access via WebLogic Server. The access control system is built on standard Java APIs that represent users, groups, permissions, and Acls (Access Control Lists).

A Weblogic Server user is the server account of the end-user of an application. A user presents a username and credential (usually a password) to WebLogic Server. If WebLogic Server can authenticated the username and credential, it associates the user with the server threads that execute code on behalf of the user. Before a thread begins executing its code, it checks pertinent Acls, testing whether the user has the permission required to continue.

A WebLogic Server group is a named list of users. Groups simplify security administration. You can mix group names and user names wherever a list of principals is permitted. WebLogic Server evaluates each item in a list of principals by looking first for a group, and testing whether the user is a member of the group, and then looking for a user.

An Acl (access control list) guards an object or service in WebLogic Server. Acls can guard Servlets and JSP pages, JMS queues and topics, EJBs, JDBC connection pools, JNDI contexts, and ZAC packages. You can also create custom Acls for use in your applications. An Acl holds a list of AclEntries, each with the set of permissions for a user or group. A permission is an action that can be performed on the protected resource--for example, "execute", "lookup", "read", or "write". The exact permissions available depend on the type of resource the Acl protects. For example, a Servlet requires "execute" permission, and a JMS queue requires "read" or "write" permission.

WebLogic Server has an extended Acl-testing capability for files that it serves. You can also create custom Acls and check permissions from within your server-side applications. There is more on Acls in the section About Acls.

WebLogic security realms

A realm is a Java class that provides access to a store of Users, Groups, Acls, and related services. WebLogic Server uses a realm as a service, calling into the realm to retrieve Users, Groups, and Acls as Java objects.

The default realm, WLPropertyRealm, uses the weblogic.properties file as the underlying security store. When WebLogic Server starts up, WLPropertyRealm creates User, Group, and Acl objects from properties read from the weblogic.properties file. (See About the default WebLogic realm in this document for help with setting these properties.)

You can use a different security store by installing an alternate realm. Alternate realms can support some or all of the services WebLogic Server requires of a realm. If a realm does not support a particular method, WebLogic Server calls the backup realm, WLPropertyRealm. Most alternate realms provide access to a store of Users and Groups and an authentication service, but fall back on WLPropertyRealm for Acls.

WebLogic Server includes alternative realms for Windows NT, UNIX, and LDAP servers such as Microsoft Site Server, Netscape Directory Server, and Novell NDS. The RDBMSRealm example is a working realm that retrieves Users, Groups, and Acls, from a database management system.

WLPropertyRealm is a static realm--it reads properties at startup time only and creates Java objects that remain as long as WebLogic Server is running. This is both an advantage and a disadvantage. The cost of creating realm objects is incurred at startup time only, so WLPropertyRealm has lower overhead than an alternate realm. But with WLPropertyRealm, you must restart WebLogic Server whenever you modify a user, group, or Acl.

Most alternate realms are dynamic; they retrieve Users, Groups, and Acls as-needed from an external source. If the data changes in the external store, the realm retrieves an updated value.

To reduce the overhead of calling into an alternate realm, WebLogic Server can cache results retrieved from the realm. (Caching is not needed for WLPropertyRealm, since all users, groups, and Acls are loaded into server memory at startup.) Realm caching is itself implemented as a realm, which is named CachingRealm. When you install an alternate realm, WebLogic Server calls into CachingRealm and CachingRealm calls into the alternate realm.

Although WebLogic Server always uses CachingRealm to host alternative realms, CachingRealm does not cache by default. You can enable caching, and set the size of the cache and the time-to-live of cached results by setting properties in the weblogic.properties file. (See Administering the WebLogic caching realm for more information.)

About Acls

Acls protect resources that are accessed through WebLogic Server. An Acl grants a permission on a resource, or class of resources, to a list of Users and Groups.

Each protected resource has one or more grantable permissions. For example, Servlets have "execute" permission, while JDBC connection pools have "reserve" and "reset" permissions.

Security for Enterprise JavaBeans (EJBs) differs from other kinds of WebLogic Server resources in a few important ways. First, EJB Acls are configured in the access control properties of a bean's deployment descriptor. Second, permissions can be granted on individual methods of a bean; there are no predefined permissions. Finally, EJB permissions are granted to Roles, which should be mapped to a WebLogic Server group. See BEA WebLogic Server Enterprise JavaBeans for more about EJB security.

In the WLPropertyRealm, Acls are specified with weblogic.allow properties in the weblogic.properties file. For example, the Acl that grants "reserve" permission on the JDBC connection pool named "demoPool" to users "Alex", "Ed", "Jim", and "John" is specified with a property like this:

 weblogic.allow.reserve.weblogic.jdbc.connectionPool.demoPool=\
      Alex,Ed,Jim,John

The permission to be granted follows the weblogic.allow prefix.

The list to the right of the equals sign can include usernames and group names.

The portion of the property name between the permission and the equals sign specifies the resource or group of resources governed by the Acl. The string describes a node in a hierarchical list of Acls. The following illustration shows a portion of an Acl hierarchy with the path to weblogic.jdbc.connectionPool.demoPool in red:

Acl Hierarchy

A permission can be granted on a single object, such as "demoPool" above, or on a class of objects, such as all JDBC connection pools. WebLogic Server uses the most specific Acl it can find for a protected resource. This means that you can create Acls that grant default permissions for a class of resources, and then create more restrictive Acls for specific resources. The default weblogic.properties file uses this technique. It contains the Acls:

  weblogic.allow.execute.weblogic.servlet=everyone
  weblogic.allow.execute.weblogic.servlet.AdminMain=system

The first Acl allows anyone to execute any servlet. This default Acl is overridden for some servlets, such as the AdminMain servlet, which can only be executed by the "system" user.

There are more details about setting up access control lists for the WebLogic realm in the WebLogic Administrators Guide, Setting WebLogic properties.

About alternative security realms

WebLogic Server may defer authentication and/or authorization to an alternative realm, which is specified by setting the weblogic.security.RealmClass property to the alternative realm's Java classname. Alternative realms are not called directly; instead, WebLogic Server calls into an internal realm named CachingRealm, and CachingRealm calls the alternative realm. CachingRealm provides needed default users, groups, and Acls and caches the results of lookups in the alternative realm.

WebLogic provides the following alternative realms:

LDAPRealm
LDAPRealm provides authentication from a Lightweight Directory Access Protocol (LDAP) server. Instead of defining users and groups with weblogic.password and weblogic.group properties, you define them in an LDAP server on your network, such as Netscape Directory Server or Microsoft Site Server. You still define Acls in the weblogic.properties file with weblogic.allow properties. See Administering the WebLogic LDAP security realm for help with setting up and administering the LDAPRealm.

NTRealm
NTRealm provides authentication from a Windows NT security domain. Instead of defining users and groups with weblogic.password and weblogic.group properties, you define them in a Windows NT domain. You still define Acls in the weblogic.properties file with weblogic.allow properties. See Administering the WebLogic Windows NT security realm for help with setting up and administering NTRealm.

UnixRealm
UnixRealm provides authentication from UNIX operating system authentication services. On platforms that support PAM (Pluggable Authentication Modules), UnixRealm runs a small binary, written to the PAM specification, to retrieve users and groups and to authenticate users. On UNIX platforms without PAM support, the native code uses the operating system password mechanism, including shadow passwords where supported. You still define Acls in the weblogic.properties file with weblogic.allow properties. See Administering the WebLogic UNIX security realm for help with setting up and administering UnixRealm.

RDBMSRealm
RDBMSRealm is an example that reads users, groups, and Acls from a relational database. The example shows how you can create a custom realm implementation that provides authentication and authorization services for WebLogic Server. See the javadocs for RDBMSRealm for the instructions on setting up RDBMSRealm.

When you use an alternative realm, you can set properties in the weblogic.properties file to set the size of CachingRealm's cache and the length of time that cached lookups remain valid. See Administering the WebLogic caching realm for details on tuning the cache.

The section Writing a custom realm provides help with creating a custom realm.

II. Realm administration

Setting up Users, Groups, and Acls in the WebLogic realm

In the default WebLogic realm, users, groups, and Acls are represented with properties in the weblogic.properties file.

To add a user to the default WebLogic realm, add a weblogic.password property to the weblogic.properties file, as in this example, which adds users "billc", "sam", and "don":

  weblogic.password.billc=whiterabbit
  weblogic.password.sam=madhatter
  weblogic.password.don=cheshirecat

To add a group to the WebLogic realm, add a weblogic.security.group property listing the group members. This example adds group "regusers" with members "billc", "sam", and "don":

  weblogic.security.group.regusers=billc,sam,don

Permissions for WebLogic services

You can set Acls on the following WebLogic Server services:

  • HTTP Servlets
  • JSP Pages
  • Enterprise JavaBeans
  • WebLogic Events
  • WebLogic JNDI contexts
  • WebLogic JDBC connection pools
  • WebLogic Workspaces
  • WebLogic ZAC packages

You create Acls for these services with weblogic.allow properties in the weblogic.properties file. Each WebLogic service has one or more permissions that can be granted by an Acl.

Service Acl name Permissions
Events weblogic.servlet.topicName send
receive
HTTP Servlets weblogic.servlet.servletName execute
JDBC connection pools weblogic.jdbc.connectionPool.poolName reserve
reset
shrink
JMS destinations weblogic.jms.topic.topicName
weblogic.jms.queue.queueName
send
JNDI resources weblogic.jndi.path lookup
modify
list
ZAC packages weblogic.zac.packageName read
write
WebLogic workspaces
(deprecated)
weblogic.workspace.userName
weblogic.workspace.workspaceName
read
write

WebLogic Server has built-in default Acls which, in most cases, grant all permissions to "everyone". Some of these defaults are overridden with entries in the distributed weblogic.properties file. The following section provides examples of Acls for each service and also describes the default Acl.

Acl examples

WebLogic Events

You can set "send" and "receive" permissions on an WebLogic Event Acls. The default Acl permits "everyone" to send or receive events. The "receive" Permission has a dual purpose; it also controls registration for and filtering of events from subordinate topics.

weblogic.allow.receive.weblogic.event.weather.us.ca.sf=regusers
weblogic.allow.submit.weblogic.event.weather.us.ca.sf=don

WebLogic HTTP Servlets

Servlets have "execute" permission. When a servlet Acl grants "execute" permission to "everyone," anyone can execute the servlet without having to enter a password. If an Acl restricts "execute" permission to one or more users, the web browser prompts the user for a username and password.

weblogic.allow.execute.weblogic.servlet.AdminProperties=system

WebLogic JDBC

The "reserve" permission allows a user to get a connection from a JDBC connection pool. The "reset" permission allows a user to reset the pool, which closes and reopens all of the connections in the pool. The "system" user always has permissions reserve and reset.

weblogic.allow.reserve.weblogic.jdbc.connectionPool.eng=margaret,joe,mary
weblogic.allow.reset.weblogic.jdbc.connectionPool.eng=sysadmin

WebLogic JMS

You can set "send" and "receive" permissions for JMS Queues and Topics. If no Acl is set, both permissions are granted to "everyone" by default.

weblogic.allow.receive.weblogic.jms.topic.stocks=peter,brown,eric
weblogic.allow.send.weblogic.jms.topic.stocks=system
weblogic.allow.send.weblogic.jms.queue.payroll=payrollAdmin

WebLogic JNDI

JNDI has "lookup", "modify", and "list" permissions. If no Acls are set, all permissions are granted to "everyone".
weblogic.allow.lookup.weblogic.jndi.apps=peter,brown,eric
weblogic.allow.modify.weblogic.jndi.apps=peter,brown,eric
weblogic.allow.list.weblogic.jndi.apps=peter,brown,eric

WebLogic Workspaces

Workspaces have "read" and "write" permissions. If not set, WebLogic Server creates an Acl dynamically whenever a user logs in by copying the Acl for weblogic.workspace and adding "read" and "write" Permissions. This allows users to to read and write their own Workspaces without explicit Acls, but allows you to give explicit "read" or "write" permissions on other workspaces.

weblogic.allow.read.weblogic.workspace.T3UserSales=karl,michael,skip,msmith
weblogic.allow.write.weblogic.workspace.T3UserSales=karl,michael,skip,msmith
weblogic.allow.read.weblogic.workspace.myWorkspace=ellen
weblogic.allow.write.weblogic.workspace.myWorkspace=ellen

WebLogic ZAC

You can set "read" and "write" permissions on ZAC packages. If no Acl is set, the default is to allow everyone to read and write a published package.

weblogic.allow.read.weblogic.zac.myApp=karl,michael,skip,msmith
weblogic.allow.write.weblogic.zac.myApp=system

In addition, the Acl weblogic.admin, which is built into the default realm, grants "shutdown" and "reset" permissions to the WebLogic "system" user.

There is a more discussion of setting properties in the WebLogic Administrators Guide, Setting WebLogic properties.

III. The WebLogic Security SPI

Package java.security.acl
Package weblogic.security
Package weblogic.security.acl
Package weblogic.security.audit
Package weblogic.security.net

Overview of the WebLogic Security Service Provider Interface

The WebLogic Security SPI provides APIs that make it possible to:

  • Test custom Acls in server-side programs.

  • Create an alternative security realm to draw WebLogic users, groups, or Acls from an external store.

  • Implement a class to audit security events. WebLogic Server calls the class with information about authentication and authorization requests. The class can filter the events and direct them to a log file or other administrative facility.

  • Create a class that maps client certificates, sent from users' browsers or Java client programs, to WebLogic Server users. This makes it unnecessary for a user with a valid certificate to enter a username and password.

  • Create a class that examines WebLogic Server connection events and allows or denies the connection, based on attributes such as the network origin IP number or domain and protocol.

The JNDI API provides the support needed to submit a username and credential (password or certificate) when getting a connection to WebLogic Server from a Java program. For browser clients, WebLogic Server supports standard HTTP and SSL protocols.

The weblogic.security.acl package is based on the JDK 1.1 java.security.acl API. You can read a high-level summary of this specification in Security in JDK 1.1 on the Sun website.

WebLogic security builds upon the JDK security API, providing implementations and extensions where needed, and a realm interface that collects the security-related APIs into an authentication and authorization service for WebLogic Server.

IV. Implementing with the WebLogic Security SPI

The following sections describe how to use the WebLogic Security SPI for common security tasks:

Connecting to WebLogic Server from a Java class
SSL two-way authentication from a Java client
Using custom Acls
Mapping a client certificate to a WebLogic user
Auditing security events
Filtering network connections
Creating a custom security realm
Delegating to multiple realms

Connecting to WebLogic Server from a Java class

Java client programs and server-side classes use JNDI to access WebLogic Server services. A Java program establishes a connection with WebLogic Server by getting an InitialContext. Then it can use the InitialContext to look up the resources it needs in the WebLogic Server JNDI tree.

You specify a user by setting SECURITY_PRINCIPAL and SECURITY_CREDENTIALS properties in a Hashtable passed to the InitialContext constructor. If you do not specify login information in the Hashtable, WebLogic Server defaults to the "guest" user.

The following code, from Client.java in the examples.security.acl example, demonstrates how to set a username and password in the JNDI Hashtable. This client takes three command-line parameters: the WebLogic Server URL, a login name, and a password. It copies these parameters into the Hashtable.

 Hashtable env = new
Hashtable();
      env.put(Context.INITIAL_CONTEXT_FACTORY,
              "weblogic.jndi.WLInitialContextFactory");
      env.put(Context.PROVIDER_URL,          arg[0]);
      env.put(Context.SECURITY_PRINCIPAL,    arg[1]);
      env.put(Context.SECURITY_CREDENTIALS,  arg[2]);

      ctx = new InitialContext(env);

In WebLogic Server, this generates a call to weblogic.security.acl.Security.getUser(), which, if the username and password are correct, returns a User object. WebLogic Server stores this authenticated User object on the client's thread in the server, and it is used for subsequent authorization requests when the thread attempts to use resources protected by Acls.

SSL two-way authentication from a Java client

WebLogic Server supports SSL connections so that data sent over the wire is encrypted. To negotiate a secure connection, SSL uses certificates. Normally, the server sends a certificate to the client, and the client examines the certificate to ensure that it is authentic, has not expired, and matches the server that presented it. With two-way SSL authentication, the client also presents a certificate to the server. By setting properties in the weblogic.properties file, you can configure WebLogic Server to require client certificates and you can install up to four Certificate Authority root certificates. WebLogic Server only accepts client certificates signed by one of the CA root certificates you install.

For web clients, users install their certificates in their web browsers and WebLogic Server and the web browser coordinate the certificate exchange through the HTTP and SSL protocols.

To use two-way authentication from a Java client, you supply the user's certificate and private key by reading the files from the user's disk into an X509 Object and then setting the X509s in the JNDI Hashtable. A client certificate does not identify a WebLogic user, however, so you can also set the WebLogic username and password in the JNDI Hashtable. See Mapping a certificate to a WebLogic user for more about this; that section describes how to implement a WebLogic interface that lets you map certificates to WebLogic users.

Warning  When you use two-way authentication from a Java client, the SSL connection is established using the client certificate and private key passed in the initial JNDI request to the WebLogic Server SSL listen port. WebLogic Server gets a unique JVM ID for each client JVM so that the connection between the client and WebLogic Server is constant. Unless the connection times out from lack of activity, it persists as long as the client JVM continues to execute. This means that a client cannot reliably renegotiate a new SSL connection using a different client certificate except by stopping the client JVM and running another instance.

A client application running in a JVM with an SSL connection can change the WebLogic Server user identity by supplying the new username and password in the JNDI SECURITY_PRINCIPAL and SECURITY_CREDENTIALS variables for a new JNDI Context. But any client certificates passed after an SSL connection is made are not used. The new WebLogic Server user continues to use the SSL connection negotiated with the initial user's certificate.

If you implement the CertAuthenticator interface, WebLogic Server passes the client certificate to your CertAuthenticator implementation, which maps the certificate to a WebLogic Server user. Since the certificate is only processed on the first connection request from the JVM, it is not possible to set a new user identity when you use the CertAuthenticator feature.

AltClient.java, in the examples.security.acl example, shows how to do two-way SSL authentication in a Java client. AltClient uses weblogic.jndi.Environment, a convenient wrapper on the JNDI Hashtable, to set the connection properties. In other respects, AltClient is similar to the Client program in the same example. When called with three parameters on the command-line, the first is the WebLogic Server URL, the second is the username, and the third is the password. This is the same as the Client program. Additional parameters are filenames for the user's private key, certificate, and an optional certificate chain that terminates in a root certificate WebLogic Server recognizes.

To pass certificates to JNDI, you create an array of InputStreams opened on files containing DER-encoded certificates and set the array in the JNDI Hashtable. The first element in the array contains an InputStream opened on the client's private key. The second element contains an InputStream opened on the client's certificate file (which contains the public key.) Additional elements can contain root CA certificates, each the signer of the preceding certificate. This "certificate chain" allows WebLogic Server to authenticate the client certificate if it was not directly issued by a CA registered in the weblogic.properties file.

AltClient reads certificates stored in .pem files by using weblogic.security.PEMInputStream, a filter that decodes the base 64-encoded DER certificate in a .pem file.

Here is the code for AltClient, with some omissions. Note the use of the WebLogic Environment class and its methods to set variables into the JNDI Hashtable:

package examples.security.acl;

import java.io.FileInputStream;
import java.io.InputStream;
import javax.naming.Context;
import weblogic.jndi.Environment;
import weblogic.security.PEMInputStream;


public class AltClient
{

  public static void main(String[] args)
  {
    Context ctx = null;
    
    String url = args[0];
    try
    {
      Environment env = new Environment();

      env.setProviderUrl(url);

      // The second and third args are username and password
      if (args.length >= 3)
      {
	env.setSecurityPrincipal(args[1]);
	env.setSecurityCredentials(args[2]);
      }

      // Fourth and fifths arguments are private key and
      // public key.
      if (url.startsWith("t3s") && args.length >= 5)
      {
	InputStream[] certs = new InputStream[args.length - 3];
	for (int q = 3; q < args.length; q++)
	{
	  String file = args[q];
	  InputStream is = new FileInputStream(file);

	  if (file.toLowerCase().endsWith(".pem"))
	  {
	    is = new PEMInputStream(is);
	  }
	  certs[q - 3] = is;
	}
	env.setSSLClientCertificate(certs);
      }
      ctx = env.getInitialContext();
      ...

When getInitialContext() is called, the client and WebLogic Server execute the SSL two-way authentication protocol, in the same way that a web browser performs two-way authentication to get a secure web server connection. An exception is thrown if the certificates cannot be validated or if the client's username and password cannot be authenticated in the security realm. The authenticated User is stored on the client's server thread and used for checking the client's permission on any Acl-protected WebLogic Server resources.

Warning  When you use weblogic.jndi.Environment, create a new Environment for each call to Environment.getInitialContext(). Once you set a security principal and security credentials, they remain set in the Environment. If you try to reset them and then call getInitialContext() again, the original security principal and credentials are used.

See Using WebLogic JNDI for more information about using JNDI with WebLogic Server. See Using WebLogic SSL for more about WebLogic Server SSL support.

Mapping a client certificate to a WebLogic Server user

When you perform two-way authentication, the client supplies a certificate, which allows WebLogic Server to authenticate the client. A certificate is not equivalent to a WebLogic Server user, however, so the client must also supply a username and credential to use for permission testing.

If you choose, you can implement the weblogic.security.acl.CertAuthenticator interface to map a client certificate to a WebLogic Server user. Your CertAuthenticator class is installed in WebLogic Server and called after the SSL connection has been established. It can extract data from the client certificate to determine which WebLogic Server user owns the certificate, and then call Security.getUser() to retrieve the authenticated User from WebLogic Server's security realm.

Installing a CertAuthenticator class makes it unnecessary for web browsers to prompt for WebLogic Server user names and unnecessary for Java applications to set a password in the JNDI SECURITY_CREDENTIALS variable.

If you install a CertAuthenticator class and you have Java client applications, beware that they cannot change the WebLogic Server user identity once the SSL connection is established. To supply a new client certificate, you have to stop the client JVM and restart the application in a new JVM instance so that a new SSL connection can be negotiated. See the Warning above for an explanation.

The method for mapping a certificate to a user is up to you. One strategy is to set users' WebLogic passwords to the fingerprint of their certificate. Then you could extract the username from the certificate, calculate the fingerprint, and call Security.getUser() the same way WebLogic Server does when the user submits their name and password.

You install your CertAuthenticator class by setting the weblogic.security.realm.CertAuthenticator property to the name of the class. The class has a public no-arg constructor and an authenticate() method. WebLogic Server calls authenticate() method with a username, which may be null, a Certificate array containing the client's certificate and certificate chain, and a boolean that is true if an SSL handshake succeeded. You can call methods on Certificate to retrieve data from the certificate.

SimpleCertAuthenticator.java, in the weblogic.security.cert example, shows how to implement the CertAuthenticator interface. It extracts the username from the email address in the certificate and calls Security.getUser() to retrieve an authenticated User from the security realm. Since it only examines a portion of the email address, this example is not very secure. Certificates with the same email address at different domains would be mapped to the same WebLogic user and no additional authentication is performed. If you want to implement this feature, you will probably want to add an additional strategy to fully establish the identity of the client.

Here is the source for the SimpleCertAuthenticator example.


package examples.security.cert;


import weblogic.security.Certificate;
import weblogic.security.Entity;
import weblogic.security.X500Name;
import weblogic.security.acl.CertAuthenticator;
import weblogic.security.acl.BasicRealm;
import weblogic.security.acl.Realm;
import weblogic.security.acl.User;

public class SimpleCertAuthenticator
  implements CertAuthenticator
{
  private BasicRealm realm;

  public SimpleCertAuthenticator()
  {
    realm = Realm.getRealm("weblogic");
  }

  
  /**
   * Attempt to authenticate a remote user.
   *
   * @param userName ignored by this example
   * @param certs used to attempt to map from email address to WebLogic
   * user
   * @param ssl if false, this example returns null
   * @return authenticated user, or null if authentication failed
   */
  public User authenticate(String userName, Certificate[] certs, boolean ssl)
  {
    // This implementation only trusts certificates that originate
    // from a successful two-way SSL handshake.
    if (ssl == false)
    {
      return null;
    }
    
    User result = null;
    Certificate cert = certs[0];
    Entity holder = cert.getHolder();

    if (holder instanceof X500Name)
    {
      X500Name x500holder = (X500Name) holder;
      String email = x500holder.getEmail();

      if (email != null)
      {
	int at = email.indexOf("@");

	if (at > 0)
	{
	  String name = email.substring(0, at);

	  // Make sure that the user we've pulled out of the email
	  // address really exists.
	  result = realm.getUser(name);
	}
      }
    }
    
    return result;
  }
}

The constructor for this example shows how to get access to the WebLogic Server security realm in a server-side class. getRealm("weblogic") returns whatever realm WebLogic Server is using, whether it is the WLPropertyRealm or an alternative realm such as LDAPRealm.

The X500Name class has accessor methods to retrieve fields from the Certificate. This example casts the Certificate to an X500Name, calls the getEmail() method, and takes the initial substring of the email address. The getUser(String) realm method retrieves the WebLogic Server user with the computed username. If the user does not exist, authenticate() returns null.

Using custom Acls

WebLogic Server defines standard Acls to protect middle-tier services and resources. If you create an Acl for a resource, WebLogic Server automatically checks permissions before it permits access to a user. Many middle-tier applications can be fully protected with these predefined Acls.

Some middle-tier implement new services in WebLogic Server or require more than one Acl. For example, you could create a servlet that checks user-level permissions before writing certain data to a web page. You can create a custom Acl in the weblogic.properties file and then in your application to call into the WebLogic security realm to test the current user's permissions on the Acl.

The weblogic.security.acl.Security class provides access to realm operations, such as checking an Acl. The Security class is only available to server-side code.

The Security.hasPermission() and Security.checkPermission() methods test whether a user has a given permission. The methods are similar, except that the hasPermission() method returns a boolean (true if the user has the permission) and the checkPermission() method throws java.lang.SecurityException if the user does not have the permission.

The examples.security.acl example shows how to create your own Acls and test them in a server-side class. It protects an RMI class, FrobImpl, with a custom Acl named "aclexample" that has a "frob" permission. Read more about WebLogic RMI architecture in Using WebLogic RMI.

The custom Acl, defined in the weblogic.properties file is:

  weblogic.allow.frob.aclexample=list

where list is a list of WebLogic users or groups.

A server-side class, FrobImpl, is registered in the WebLogic Server JNDI tree with this property:

  weblogic.system.startupClass.frob=examples.security.acl.FrobImpl

The Java client application:

  • gets a JNDI InitialContext from WebLogic Server,
  • looks up FrobImpl using its JNDI name, frob,
  • and executes the frob() method on the RMI stub WebLogic Server returns.

The FrobImpl class contains the server-side code that tests the Acl. The example shows two methods for testing the permission. The first method uses the static checkPermission() method in the weblogic.security.acl.Security class:


Security.checkPermission(Security.getCurrentUser(),
          "aclexample", 
          Security.getRealm().getPermission("frob"), 
          '.');

You would use the second method if you wanted to test Acls in a realm other than the WebLogic Server ("weblogic") realm. With this method, you get the target realm with a getRealm("realm_name") call and then retrieve the Permission and Acl by calling the getPermission() and getAcl() realm methods. Then you test the permission by calling the checkPermission() method on the Acl:

    User p = Security.getCurrentUser();
    BasicRealm realm = Realm.getRealm(REALM_NAME);
    Acl acl = realm.getAcl(ACL_NAME);
    Permission perm = realm.getPermission(PERMISSION_NAME);
    boolean result = acl == null || !acl.checkPermission(p, perm);

The last line tests whether the Acl was found and, if so, whether the current user, p, has the "frob" permission. The sense of the test is reversed; if the Acl exists, and the user has "frob" permission, result is false.

If you audit security events (described in the next section), and you use the second method for testing permissions, you must explicitly call into the static Audit class if you want to audit your permission tests. This call on the static Audit class generates a notification of the permission-checking event to an AuditProvider class installed in WebLogic Server:

    Audit.checkPermission("Frob", acl, p, perm, !result);

See the examples.security.acl Javadocs for instructions on setting up the RMI classes and executing the Frob example.

Auditing security events

The weblogic.security.audit package allows you to create a pluggable auditing service for events that occur in the WebLogic Server security realm. The package includes an interface, AuditProvider, and a static class, Audit, where WebLogic Server sends auditable security events.

To enable auditing, you create a class that implements the AuditProvider interface, and install it in WebLogic Server by setting the weblogic.security.audit.AuditProvider property to the name of your class. WebLogic Server calls the methods on your class when a user attempts to authenticate, when a permission is tested, or when an invalid user certificate or root CA certificate is presented. Your AuditProvider class receives the particulars for each event type and can process the event in whatever way you choose. For example, it could log only unsuccessful authentication requests in the WebLogic Server log file, or record all auditable events in a database table.

The examples.security.audit LogAuditProvider example writes all events it receives in the WebLogic Server log file. It also defines filter methods for each event type, which it calls to decide whether to log a particular event. In the example code, the filter methods always return true so that all events are logged. If you extend this example, you can override the filter methods with methods that select the events you want to log. If you want to take some action other than logging security events in WebLogic Server log, you can use the LogAuditProvider example as a starting point for developing your own provider.

Filtering network connections

Passwords, Acls, and Certificates allow you to secure WebLogic Server applications using some characteristic of a user. You can add an additional layer of security by filtering network connections. For example, you could deny any non-SSL connections originating outside of your corporate network.

To filter network connections, you create a class that implements the weblogic.security.net.ConnectionFilter interface and install it in WebLogic Server so that you can examine and accept or deny connection requests as they occur.

You install a ConnectionFilter class by setting the weblogic.security.net.ConnectionFilter property to the name of your class that implements the ConnectionFilter interface. When a client connects, WebLogic Server constructs a ConnectionEvent and passes it to the accept() method of your ConnectionFilter class. The ConnectionEvent includes the remote IP address, as a java.net.InetAddress, the remote port number, the local WebLogic Server port number, and a String containing the protocol (HTTP, HTTPS, T3, T3S, or IIOP).

Your ConnectionFilter can examine the ConnectionEvent and accept the connection, by returning, or deny the connection by throwing a FilterException.

The examples.security.net.SimpleConnectionFilter example filters connections using a rules file. See the example's documentation for syntax of the file.

The SimpleConnectionFilter example does a fair amount of work to parse the rules file and set up an efficient rule-matching algorithm so that connection filtering adds minimal overhead to a WebLogic Server connection. See the example code for details on the algorithms.

WebLogic Server calls the SimpleConnectionFilter.accept() method with a ConnectionEvent. That method gets the remote address and protocol and converts the protocol to a bitmask to avoid String comparisons in the rule-matching. Then it compares the remote address and protocol to each rule until it finds a match:

  public void accept(ConnectionEvent evt)
    throws FilterException
  {
    InetAddress remoteAddress = evt.getRemoteAddress();
    String protocol = evt.getProtocol().toLowerCase();
    int bit = protocolToMaskBit(protocol);

    // this special bitmask indicates that the
    // connection does not use one of the recognized 
    // protocols
    if (bit == 0xdeadbeef)
    {
      bit = 0;
    }
    
    // Check rules in the order in which they were written.
    
    for (int i = 0; i < rules.length; i++)
    {
      switch (rules[i].check(remoteAddress, bit))
      {
      case FilterEntry.ALLOW:
	return;
      case FilterEntry.DENY:
	throw new FilterException("rule " + (i + 1));
      case FilterEntry.IGNORE:
	break;
      default:
	throw new RuntimeException("connection filter internal error!");
      }
    }
    
    // If no rule matched, we allow the connection to succeed.
    
    return;
  }

The SimpleConnectionFilter example is an efficient, generalized connection filter. You could modify this code if you need to consider the local or remote port number in your filter, or if you want to substitute a more site-specific algorithm to reduce filtering overhead.

Writing a custom realm

You can create your own security realm, perhaps to draw from an existing store of users such as a directory server on the network. The weblogic.security.acl package contains most of the interesting classes and interfaces you need to develop a custom realm.

The BasicRealm, ListableRealm, and ManageableRealm interfaces define capabilities of realms. In earlier WebLogic Server releases, you would create a custom realm by implementing ListableRealm or ManageableRealm and installing your implementation in place of the default WLPropertyRealm as the WebLogic Server realm. To provide a more flexible environment for integrating WebLogic Server with other enterprise systems, WebLogic Server 5.0 offers more robust support for alternative realms.

The new support for custom realms is provided by two realm implementations that make it easier to construct a realm:

AbstractListableRealm and CachingRealm work together to provide a fallback for custom realms. AbstractListableRealm implements the ListableRealm interface, but all if its methods throw an UnsupportedOperationException. CachingRealm catches UnsupportedOperationExceptions and calls the method in WLPropertyRealm, the fallback realm. When you create your realm by extending AbstractListableRealm, you only have to override the methods that access your external security system. Other methods will fall back on WLPropertyRealm automatically using the UnsupportedOperationException mechanism.

Most external security systems provide access to Users and Groups, but not Acls. To implement a custom realm for such a system, you override AbstractListableRealm methods such as getUser() and getGroup(), but leave Acl methods, such as getAcl(), unimplemented. This way, Acls are read from the weblogic.properties file.

Realm methods focus on retrieving data from an external store, constructing the appropriate object, and returning them to WebLogic Server. The following sections describe how realms process users, groups, permissions, and Acls, including the Java classes that represent them and semantic issues. Examples are taken from the RDBMSRealm example, a realm that uses a relational database for its backing store.

RDBMSRealm has a delegate pool architecture that provides benefits similar to a JDBC connection pool. The RDBMSRealm class creates a pool of delegates, each with its own JDBC connection. When WebLogic Server calls into RDBMSRealm, RDBMSRealm selects a delegate from the pool to service the request. This ensures that only one server thread has access to a delegate at any given time, avoiding issues of deadlock and JDBC connection-sharing. If a delegate's JDBC connection goes bad, the delegate throws an exception and RDBMSRealm switches to another delegate, creating a new one if necessary. Because of this delegate architecture, the code that interacts with the database is in the RDBMSDelegate class instead of in the RDBMSRealm class itself. Methods that do not use JDBC are defined in RDBMSRealm.

Most custom realms access an external service through some kind of connection, so the delegate architecture is a good model to emulate. Review the code in RDBMSRealm.java to see how delegates are created an managed.

Realm implementation notes

A custom realm should extend AbstractListableRealm or AbstractManageableRealm, overriding only those methods it supports. Most realm methods are lookups; if the realm cannot retrieve the requested information from its store, it should return null so that the delegation mechanism provided by the Abstract realms and CachingRealm can request the information from another realm, if available.

If your realm supports Users and Groups, there are some semantic conventions you should follow. Some realm methods operate on Principals, an object that can be either a User or a Group. When your getPrincipal() method is called, you should look first for a Group and, if none is found, look for a User. This is consistent with all BEA-provided realms.

WebLogic Server user and group names are case-sensitive, but some custom realms access external stores that are not case-sensitive. Your realm should handle case-sensitivity as required by the external store. However, you should set the boolean weblogic.security.realm.cache.caseSensitive property to false in the weblogic.properties file if the realm is not case-sensitive. This causes CachingRealm to convert names to lowercase before comparing. Acls should be defined with lowercase names in the weblogic.properties file if the users and groups come from a realm that is not case-sensitive.

Your realm should not use WebLogic Server classes or components that can be protected by Acls. For example, you should not use EJBs to represent WebLogic Server users, since the EJB security can interfere with the realm's operation.

Implement the DebuggableRealm interface to help debug your realm. For example:

public class MyRealm
  extends AbstractListableRealm
  implements DebuggableRealm
{
The DebuggableRealm interface lets you send debugging output to the log, which you should declare this way:
  protected LogOutputStream log;

Implement the debug methods in your realm class as follows:

    public void setDebug(boolean enable)
  {
    if (enable && log == null)
    {
      log = new LogOutputStream("My Realm");
    }
    if (!enable)
    {
      log = null;
    }

    delegate.setDebugLog(log);
  }

  public LogOutputStream getDebugLog()
  {
    return log;
  }

In your realm code, send debug messages to the log with a call like this one:

  if (log != null)
      log.debug("my realm says hello");

Realm debugging is enabled by setting the weblogic.security.realm.debug property to "true" in the weblogic.properties file. You can also provide an implementation of the AuditProvider interface to help with debugging.

Implementing users in a realm

The weblogic.security.acl.User class represents a WebLogic Server user. WebLogic Server calls into a realm to retrieve Users, authenticate Users, check Users' permissions, and manipulate Users as members of Groups.

RDBMSRealm extends User to create an RDBMSUser class with support for encrypted passwords. The realm interface has two ways to retrieve a single user from the realm: by name or as a result of an authentication request. The getUser(String name) method in RDBMSDelegate executes the SQL query to retrieve a user from the database. RDBMSRealm SQL queries are JDBC PreparedStatements set up by the RDBMSDelegate constructor. The query to retrieve a user from the database returns a row with two columns: username and password. These results are passed to the createUser() method which creates a new RDBMSUser instance by passing the username and password to the RDBMSUser constructor. Here is the getUser() method:

 RDBMSUser getUser(String name) throws SQLException { if
(realm.log != null) realm.log.debug("getUser(\"" + name + "\")");
    
    getUserStmt.setString(1, name);

    ResultSet rs = getUserStmt.executeQuery();

    try
    {
      // If the ResultSet is empty, the user doesn't exist in the
      // database.
      
      return rs.next()
	? realm.createUser(rs.getString(1), rs.getString(2)) : null;
    }
    finally
    {
      // Politely clean up after ourselves.
      
      rs.close();
    }
  }

The second way to retrieve a User from the realm is via an authentication request. An authentication request occurs when a web browser or Java client provides a username, password, and/or certificates. WebLogic Server creates a weblogic.security.acl.DefaultUserInfoImpl object containing the username and credentials, which may include a password, client certificate, and certificate chain. It calls the realm getUser(UserInfo) method, which returns an authenticated user or null if the user cannot be authenticated.

CachingRealm and AbstractListableRealm deprecate getUser(UserInfo) in favor of authenticate(UserInfo). A call to CachingRealm's getUser(UserInfo) method results in a call to AbstractListableRealm's authenticate(UserInfo) method. The authenticate() method in AbstractListableRealm calls authInternal(), which looks at the contents of the UserInfo and dispatches the request to an authentication method that matches the credentials it finds. authInternal() follows a default dispatch sequence, as follows:

  1. If the UserInfo contains certificates not verified with SSL two-way authentication, call authCertificates() with the username and vector of certificates.
  2. If the UserInfo has a password, call authUserPassword() with the username and password.
  3. If the UserInfo has certificates verified by SSL two-way authentication, call authSSLCertificates() with the username and vector of certificates.

In AbstractListableRealm, each of these authentication methods returns null, so you only have to implement the methods your realm supports. If you want to dispatch requests in a different sequence, you can override authInternal() and implement your own policy.

RDBMSRealm only supports password authentication, and so it overrides the authUserPassword() method in AbstractListableRealm. A client attempting to authenticate in this realm with certificates will not succeed. The code that tests a password is in the RDBMSUser class, so the RDBMSRealm authUserPassword() method retrieves the user with getUser() and calls authenticate() on the RDBMSUser object:

  protected User authUserPassword(String name, String passwd)
  {
    RDBMSUser user = (RDBMSUser) getUser(name);

    if (user != null && user.authenticate(passwd) == false)
    {
      user = null;
    }
    
    return user;
  }

We have already seen getUser(). The RDBMSUser class supports both clear text passwords and passwords encrypted with a one-way hash using an algorithm such as SHA or MD5. An encrypted password starts with the hashing algorithm in braces, for example:

  {SHA}BnoTow0lgQVXT4y8ABQz3xpMJXw=

If the password is encrypted, RDBMSUser.authenticate() compares the hashed or clear text password, as appropriate, with the the password retrieved from the database.

Read the source code for examples.security.rdbmsrealm.RDBMSUser to see how it handles password encryption and authentication. The class also has a main() method that you can run at a command line to generate hashed passwords to store in the database.

Implementing groups in a realm

Groups make it easier to administer security in realms. Internally, WebLogic Server represents a group as a Hashtable containing a list of members, which can be Users or Groups. In the realm interfaces, a Principal represents a group member, and resolves to either a Group or User.

When WebLogic Server calls a realm's getGroup() method, the realm returns a Hashtable containing all of the group's members. In the usual case, a Group is retrieved from the realm when an Acl that references it is retrieved. In the default WebLogic Realm, group membership never changes while WebLogic Server is running, so groups are static. In a custom realm, group membership may change in the underlying store at any time, so you should provide a way to refresh group membership periodically after getGroup() has been called. AbstractListableRealm handles this by using the weblogic.security.acl.FlatGroup class, which stores group members in a cache that expires after a preset time. The default time-to-live for the group cache is five minutes, which means any changes you make in the underlying store will be recognized in WebLogic Server within five minutes. You can tune this value by setting the weblogic.security.groupCacheTTL property to the number of seconds a cached group remains valid.

FlatGroup requires that the realm implement the FlatGroup.Source interface, which defines a getGroupMembers() method. AbstractListableRealm implements this interface for you, so you do not have to. Instead, you must provide a getGroupMembersInternal() method in your realm, which returns a Hashtable containing the current members of the group. It is similar to the realm's getGroup() method, except that it returns a Hashtable instead of a Group object. AbstractListableRealm calls this method when a group cache expires. Here is the getGroupMembersInternal() method from RDBMSRealm.java.

  protected Hashtable getGroupMembersInternal(String name)
  {
    // It's easiest to just call getGroup and use RDBMSGroup's
    // getMembers method to return the membership of this group.
    
    RDBMSGroup grp = (RDBMSGroup) getGroup(name);

    if (grp == null)
    {
      return null;
    } else {
      return grp.getMembers();
    }
  }

This method just calls the RDBMSDelegate.getGroup() method and returns its Hashtable.

Methods that transfer groups from the database to realm objects are in the RDBMSDelegate class. The getGroup() method executes an SQL query that returns a row for each group member. It passes the result set to getGroupsInternal() which constructs the Group. Each member in a group is a Principal, either a User or Group. getGroupsInternal() adds a Hashtable entry with a key that is the user or group name and a value that is the object returned by getPrincipal(). getGroupsInternal() is called by getGroup() and getGroups(), so it includes break logic, based on the internal Finished class, so that it can create multiple Groups from a result set.

getGroup() looks for certain errors of recursion when it constructs a group. It ensures that a group is not added to itself, and after the group is constructed, it ensures that there are no group members that include the constructed group in their members.

The getPrincipal() method returns a User or Group for a name. It calls getUser() first and, if getUser() returns null, it calls getGroup().

Expanding groups can result in recursive calls to getGroup(). Since there is an RDBMS behind RDBMSRealm, some care must be taken with JDBC PreparedStatements and ResultSets. The realm's delegate pool architecture ensures that each call into the realm is handled by an available JDBC connection. Within an RDBMSDelegate, recursive calls to getGroup() may not be able to use the same PreparedStatement, depending on the JDBC driver. The advantage of a PreparedStatement is that the DBMS can compute a query plan one time and then reuse it. But not all DBMSs and JDBC drivers permit using a PreparedStatement for multiple concurrent queries on a connection. RDBMSDelegate can be instructed to create a new PreparedStatement for recursive getGroup() calls. This is accomplished by setting the getGroupNewStatement property to true in the rdbmsrealm.properties file. You should test your JDBC driver by setting this property to false and looking for an SQLException. A good way to exercise the code that is sensitive to this situation is to execute the AdminRealm servlet on your WebLogic Server using a URL such as http://localhost:7001/AdminRealm in your browser.

Implementing Acls in a realm

Acls use the java.security.acl JDK 1.1 package. The weblogic.security.acl package implements the interfaces in this package. To construct an Acl, you create a new AclImpl, set its name, and then add an AclEntryImpl for each Principal (User or Group).

The WebLogic AclImpl imposes an ordering constraint on constructing Acls: you must add all Permissions to an AclEntry before you add the AclEntry the Acl. The code that retrieves an Acl from the database, in RDBMSDelegate, is similar to the code for constructing groups. The rows returned by the Acl query have three columns: A_NAME, A_PRINCIPAL, and A_PERMISSION. The query is required to order the rows by the first two columns to correctly drive the break logic in the getAclInternal() method. getAclInternal() steps through the result set creating an AclImpl, creating an AclEntryImpl for each Principal, and then adding Permissions to the AclEntryImpl. When an AclEntryImpl is finished (triggered by a new A_PRINCIPAL or end of ResultSet), it is added to the AclImpl. When the AclImpl is finished (triggered by a new A_NAME or end of ResultSet), getAclInternal() returns the finished Acl.

Delegating to multiple realms

Using the weblogic.security.realmClass property, you can install a custom realm or one of the alternative realms provided with WebLogic Server. The new realm is hosted by CachingRealm and automatically falls back on the default WLPropertyRealm when a lookup fails in the alternate realm.

You may want more than one alternate realm, however. If you have more than one external store of security information, you could install a security realm for each so that users in each external store can be authenticated in WebLogic Server. Or you may want to install a second alternate realm to act as failover for the primary alternate realm.

The examples.security.delegatingrealm example provides customizable source for a realm that delegates to other realms. This realm is driven from a properties file that lets you specify the realm classes and methods you want to call for each type of realm lookup.

For example, the following properties set DelegatingRealm to retrieve Users and Groups from LDAPRealm and Acls from RDBMSRealm, and to attempt authentication first in LDAPRealm and then in RDBMSRealm:

   getUser = weblogic.security.ldaprealm.LDAPRealm.getUser
   getGroup = weblogic.security.ldaprealm.LDAPRealm.getGroup
   authenticate.1 = weblogic.security.ldaprealm.LDAPRealm.authenticate
   authenticate.2 = examples.security.rdbmsrealm.RDBMSRealm.authenticate
   getAcl = examples.security.rdbmsrealm.RDBMSRealm.getAcl

You install DelegatingRealm by setting the weblogic.security.realmClass property to examples.security.delegatingrealm.DelegatingRealm. This calls CachingRealm into play, so you can enable and tune the cache as described in Using the WebLogic CachingRealm. DelegatingRealm reads the properties in the delegating.properties file and creates a single instance of each realm class it encounters.

You may have to modify realms to allow them to cooperate. If you delegate to LDAPRealm and RDBMSRealm as described above, for example, when retrieving an Acl from RDBMSRealm it is important that the calls to getPrincipal() be serviced by LDAPRealm instead of RDBMSRealm.

 

Copyright © 2000 BEA Systems, Inc. All rights reserved.
Required browser: Netscape 4.0 or higher, or Microsoft Internet Explorer 4.0 or higher.
Last update 3/27/2000