BEA Logo BEA WebLogic Server Release 6.1

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

   Programming WebLogic Security:   Previous Topic   |   Next Topic   |   Contents   

 

Programming with the WebLogic Security SPI

 

This section presents the following topics:

Before You Begin

This section describes programming with application programming interfaces (APIs) in the Security service provider interface (SPI) supplied by WebLogic Server. Before you perform the programming tasks described in this section, the following configuration tasks must be completed:

  1. Specify a security realm (the default, an alternate, or a custom security realm).

  2. Add Users and Groups to the security realm.

  3. Assign ACLs and permissions to the resources in the security realm.

  4. Configure the SSL protocol (an optional step to provide additional protection for network connections or when using certificate authentication).

  5. Configure mutual authentication (optional).

For more information about these configuration tasks, see Managing Security in the Administration Guide.

For information about security in WebLogic EJBs, see Programming WebLogic Enterprise JavaBeans.

WebLogic Security SPI

The WebLogic Security SPI builds upon the Java Developer's Kit (JDK) security SPI: it provides implementations and extensions where needed and a realm interface that collects the security APIs into an authentication and authorization service for WebLogic Server. The authentication scheme in WebLogic Server is based on the Java Authentication and Authorization Service (JAAS). This standard provides the support needed to submit a username and credential (password or digital certificate) when initiating a secure connection to WebLogic Server.

Table 4-1 lists the packages that are used when security is used in the WebLogic Server environment.

Table 4-1 WebLogic Security Packages

This Package. . .

Is Used for. . .

javax.security.auth

Performing JAAS-style LoginContext and Subject based authentication.

weblogic.security

Mapping digital certificates sent from Web browsers and Java clients to WebLogic Server. This class makes it unnecessary for a user with a valid digital certificate to enter a username and password when accessing resources in WebLogic Server.

weblogic.security.acl

Creating custom security realms to access WebLogic Server users, groups, or ACLs from an external store. In addition, this package is used to test custom ACLs in server-side programs.

weblogic.security.audit

Auditing security events. WebLogic Server calls the Audit class with information about authentication and authorization requests. The package can be used to filter the authorization and authentication requests and direct them to a log file or other administrative facility.

weblogic.security.net

Examining connections to WebLogic Server and allowing or denying the connections based on attributes such as the IP address, domain, or protocol of the initiator of the network connection.

Using JAAS Authentication

JAAS is a standard extension to the security in the Java Software Development Kit version 1.3. JAAS provides the ability to enforce access controls based on who runs the code. JAAS is provided in WebLogic Server as an alternative to the JNDI authentication mechanism. It is the preferred method of authentication. In order to use JAAS, you need to have the Java SDK version 1.3 installed.

Note: The authorization component of JAAS is not provided in WebLogic Server.

Table 4-2 lists the JAAS classes supported in WebLogic Server.

Table 4-2 JAAS Classes

Class

Description

javax.security.auth.Subject

Represents the source of the request and can be any entity (for example, a person or a client). A Subject object is created at the completion of a successful user authentication or login.

javax.security.auth.login.LoginContext

Through the LoginContext object, an application initiates login, logout, and acquires to the authenticated Subject for the purpose of authorization checking.

javax.security.auth.login.Configuration

Provides the getConfiguration() method for the purpose of obtaining a list of LoginModules provided in a particular implementation of WebLogic Server.

javax.security.auth.spi.LoginModule

Provides the ability to implement different kinds of authentication technologies into WebLogic Server. For example, one LoginModule object may perform password authentication while another LoginModule object performs certificate authentication.

javax.security.auth.callback.Callback

Gathers input from users (such as a password or the name of a digital certificate file) and passes it to the Java client.

javax.security.auth.callback.Callback.
CallbackHandler

Provides a way for the LoginModule to communicate with a Subject to obtain authentication information. Implement the CallbackHandler interface and pass it LoginContext which forwards it directly to the underlying LoginModules. The LoginModules use the CallbackHandler both to gather input from users (such as a password) or to supply information to users (such as status information). By using CallbackHandlers, LoginModules can remain independent of the different ways WebLogic Server communicates with users.

To use JAAS in a Java client to authenticate a Subject, complete the following procedure:

  1. Implement a LoginModule class for the authentication mechanism you want to use with WebLogic Server. You need a LoginModule class for each type of authentication mechanism. You can have multiple LoginModule classes for a single WebLogic Server deployment.

    WebLogic Server provides a helper class weblogic.security.auth.Authenticate that facilitates the writing of a LoginModule class. The weblogic.security.auth.Authenticate class uses a JNDI Environment object and returns an authenticated Subject. The JNDI Environment object should include the properties listed in Table 4-3.

  2. Implement a Configuration class that specifies which LoginModule classes should be used for your WebLogic Server and in which order the LoginModule classes should be invoked.

  3. In the Java client, instantiate a LoginContext.

    The LoginContext consults the Configuration to load all of the LoginModules configured for WebLogic Server.

  4. Invoke the login() method of LoginContext.

    The login() method invokes all the loaded LoginModules. Each LoginModule attempts to authenticate the Subject.

    The LoginContext throws a LoginException if the configured login conditions are not met.

  5. Retrieve the authenticated Subject from the LoginContext.

  6. Upon successful authentication of a Subject, access controls can be placed upon that Subject by invoking the doAs() method of the javax.security.auth.Subject class. The doAs() method associates the specified Subject with the current thread's ACL and then executes the action. If the Subject has the necessary access controls the action is completed, if the Subject does not have the necessary access controls, a security exception is raised.

The examples.security.jaas example in the samples/examples/security directory provided with WebLogic Server shows how to use JAAS authentication in a Java client.

Listing 4-1 contains an implementation of the javax.security.auth.spi.LoginModule class that performs password authentication. The code in Listing 4-1 is excerpted from the SampleLoginModule in the examples.security.jaas package.

Listing 4-1 Example of LoginModule for Password Authentication


...

//Import the relevant classes.//
import java.util.Map;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.RemoteException;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.spi.LoginModule;
import weblogic.security.auth.Authenticate;
import weblogic.jndi.Environment;

public class SampleLoginModule implements LoginModule 
{
private Subject subject = null;
private CallbackHandler callbackHandler = null;
private Map sharedState = null;
private Map options = null;
private String url = null;

// Authentication status
private boolean succeeded = false;
private boolean commitSucceeded = false;

// Username and password
private String username = null;
private String password = null;

// Initialize 

  public void initialize(Subject subject,
CallbackHandler callbackHandler,
Map sharedState,
Map options)

  {

        this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;

// Retrieve WebLogic Server URL string

url = System.getProperty
("weblogic.security.jaas.ServerURL");

//Authenticate the user using the username and password passed in.
//Return true if successful.
//Raise FailedLoginException if the authentication fails.
//Raise LoginException if this LoginModule is unable to perform
//the authentication.

public boolean login() throws LoginException 
{
// Verify that the client supplied a callback handler
if(callbackHandler == null)
throw new LoginException("No CallbackHandler Specified");

  // Populate callback list//
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("username: ");
callbacks[1] = new PasswordCallback("password: ", false);

  // Prompt for username and password
callbackHandler.handle(callbacks);

  // Retrieve username
username = ((NameCallback) callbacks[0]).getName();

  // Retrieve password, converting from char[] to String
char[] charPassword = ((PasswordCallback)
callbacks[1]).getPassword();

        if(charPassword == null)
{

// Treat a NULL password as an empty password, not NULL
charPassword = new char[0];
}
password = new String(charPassword);
}

// Populate weblogic environment and authenticate
Environment env = new Environment();
env.setProviderUrl(url);
env.setSecurityPrincipal(username);
env.setSecurityCredentials(password);

// Authenticate user credentials, populating Subject
Authenticate.authenticate(env, subject);

// Successfully authenticated subject with supplied info
succeeded = true;
return succeeded;

...


WebLogic Server uses the default LoginModule (weblogic.security.internal.ServerLoginModule) to gather authentication information during server initialization. To replace the default Login module, edit the Server.policy file and replace the name of the default Login module with the name of a custom Login module.

Optionally, custom Login modules can be specified in the server.policy file ahead of the default LoginModule. The JAAS implementation in WebLogic Server uses Login modules in the order in which they are defined in the server.policy file. The default Login module checks for existing system user authentication definitions prior to execution and does nothing if they are already defined.

The default Login Module is required to define JVM properties for both the system username and password. These properties are specified as weblogic.management.username and weblogic.management.password respectively. In order to use a custom Login modules, these properties must be set accordingly.

Listing 4-2 contains an implementation of the javax.security.auth.login.Configuration class. The code in Listing 4-2 is excerpted from the SampleConfig in the examples.security.jaas package.

Listing 4-2 Example of a Configuration Implementation


...
import java.util.Hashtable;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.AppConfigurationEntry;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class SampleConfig extends Configuration

{
String configFileName = null;

//Create a new Configuration object.
public SampleConfig()

//Retrieve an entry from the Configuration using an application name 
//as an index. This code specified a single Login Module.

  public AppConfigurationEntry[] 
getAppConfigurationEntry(String applicationName)
{

AppConfigurationEntry[] list =
new AppConfigurationEntry[1];
AppConfigurationEntry entry = null;

// Get the specified configuration file
configFileName =
System.getProperty("weblogic.security.jaas.Policy");
System.out.println("Using Configuration File: " +
configFileName);

  try
{
FileReader fr = new FileReader(configFileName);
BufferedReader reader = new BufferedReader(fr);
String line;

  line = reader.readLine();
while(line != null)
{

// Skip lines until the line starting with a '{'
if(line.length() == 0 || line.charAt(0) != '{')
{
line = reader.readLine();
continue;
}
// Read following line which contains the LoginModule configured
line = reader.readLine();

  int i;
for(i = 0; i < line.length(); i++)
{
char c = line.charAt(i);
if(c != ' ')
break;
}
int sep = line.indexOf(' ', i);

String LMName = line.substring(0, sep).trim();
String LMFlag = line.substring(sep + 1)line.indexOf
(' ', sep + 1));

System.out.println("Login Module Name: " + LMName);
System.out.println("Login Module Flag: " + LMFlag);

if(LMFlag.equalsIgnoreCase("OPTIONAL"))
{
entry = new AppConfigurationEntry(LMName,
AppConfigurationEntry.LoginModuleControlFlag.
OPTIONAL,new Hashtable());
list[0] = entry;
}


else if(LMFlag.equalsIgnoreCase("REQUIRED"))
{
entry = new AppConfigurationEntry(LMName,
AppConfigurationEntry.LoginModuleControlFlag.
REQUIRED, new Hashtable());
list[0] = entry;
}


else if(LMFlag.equalsIgnoreCase("REQUISITE"))
{
entry = new AppConfigurationEntry(LMName,
AppConfigurationEntry.LoginModuleControlFlag.
REQUISITE, new Hashtable());
list[0] = entry;
}

else if(LMFlag.equalsIgnoreCase("SUFFICIENT"))

        {
entry = new AppConfigurationEntry(LMName,
AppConfigurationEntry.LoginModuleControlFlag.
SUFFICIENT,new Hashtable());
list[0] = entry;

...
//Refresh and reload all of the Login configurations.
public void refresh()

...


Listing 4-3 contains an example of a Java client that uses JAAS authentication. The code in Listing 4-3 is excerpted from the SampleClient in the examples.security.jaas package. Note that the Java client includes an implementation of the javax.security.auth.callback.Callback.CallbackHandler class.

Listing 4-3 Example of Java Client that Uses JAAS Authentication


//Import the required classes.
import java.io.*;
import java.util.*;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.TextOutputCallback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.AccountExpiredException;
import javax.security.auth.login.CredentialExpiredException;

public class SampleClient
{

//Attempt to authenticate the user.
LoginContext loginContext = null;

//Set JAAS server url system property and create a LoginContext.
{

//Set Server url for SampleLoginModule, the LoginModule for
//the JAAS code example
Properties property = new
Properties(System.getProperties());
property.put("weblogic.security.jaas.ServerURL", args[0]);
System.setProperties(property);

// Set configuration class name to load SampleConfiguration, the
//Configuration for the JAAS code example
property = new Properties(System.getProperties());
property.put("weblogic.security.jaas.Configuration",
"examples.security.jaas.SampleConfig");
System.setProperties(property);

// Set Configuration file name to load sample configuration policy //file.
property = new Properties(System.getProperties());
property.put("weblogic.security.jaas.Policy",
"Sample.policy");
System.setProperties(property);

// Create LoginContext
loginContext = new LoginContext("SampleLoginModule", new
MyCallbackHandler());
}

//Attempt authentication
loginContext.login();

//Retrieve authenticated Subject and perform SampleAction as //Subject.
Subject subject = loginContext.getSubject();
SampleAction sampleAction = new SampleAction();
Subject.doAs(subject, sampleAction);

//Implementation of the CallbackHandler Interface
class MyCallbackHandler implements CallbackHandler

{
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
{
for(int i = 0; i < callbacks.length; i++)
{
if(callbacks[i] instanceof TextOutputCallback)
{
//Display the message according to the specified type
TextOutputCallback toc = (TextOutputCallback) callbacks[i];
switch(toc.getMessageType())
{
case TextOutputCallback.INFORMATION:
System.out.println(toc.getMessage());
break;
case TextOutputCallback.ERROR:
System.out.println("ERROR: " + toc.getMessage());
break;
case TextOutputCallback.WARNING:
System.out.println("WARNING: " + toc.getMessage());
break;
default:
throw new IOException("Unsupported message type: " +
toc.getMessageType());
}
}
else if(callbacks[i] instanceof NameCallback)

      {
// Prompt the user for the username
NameCallback nc = (NameCallback) callbacks[i];
System.err.print(nc.getPrompt());
System.err.flush();
nc.setName((new BufferedReader(new
InputStreamReader(System.in))).readLine());
}else if(callbacks[i] instanceof PasswordCallback)

      {
// Prompt the user for the password
PasswordCallback pc = (PasswordCallback) callbacks[i];
System.err.print(pc.getPrompt());
System.err.flush();

//JAAS specifies that the password is a char[] rather than a String
String tmpPassword = (new BufferedReader(new
InputStreamReader(System.in))).readLine();

int passLen = tmpPassword.length();
char[] password = new char[passLen];
for(int passIdx = 0; passIdx < passLen; passIdx++)
password[passIdx] = tmpPassword.charAt(passIdx);
pc.setPassword(password);
}
else
{
throw new UnsupportedCallbackException(callbacks[i],
"Unrecognized Callback");
}
...


For more information about using JAAS, see the Java Authentication and Authorization Service Developer's Guide.

Using JNDI Authentication

Java clients can also use JNDI to pass credentials. A Java client establishes a connection with WebLogic Server by getting a JNDI InitialContext. The Java client then uses the InitialContext to look up the resources it needs in the WebLogic Server JNDI tree.

To specify a user and the user's credentials set the JNDI properties listed in the following table:

Table 4-3 JNDI Properties Used for Authentication

Property

Meaning

INITIAL_CONTEXT_FACTORY

Provides an entry point into the WebLogic Server environment. The class weblogic.jndi.WLInitialContextFactory is the JNDI SPI for WebLogic Server.

PROVIDER_URL

Specifies the host and port of the WebLogic Server. For example: t3://weblogic.7001.

SECURITY_AUTHENTICATION

Indicates the types of authentication to be used. The following values are valid:

  • None indicates that no authentication is performed.

  • Simple indicates that password authentication is performed.

  • Strong indicates that certificate authentication is performed.

SECURITY_PRINCIPAL

Specifies the identity of the User when that User us authenticate to the WebLogic Server security realm.

SECURITY_CREDENTIALS

Specifies the credentials of the User when that User is authenticate to the WebLogic Server security realm.

  • For password authentication enabled via SECURITY_AUTHENTICATION="simple", this property specifies a string that is the either User's password or a User object used by WebLogic Server to verify credentials.

  • For certificate authentication enabled via SECURITY_AUTHENTICATION="strong", this property specifies the name of the X509 object that contains the digital certificate and private key for the WebLogic Server.

These properties are stored in a hash table that is passed to the InitialContext constructor.

Listing 4-4 demonstrates how to use password authentication in a Java client. The code in Listing 4-4 is excerpted from the Client in the examples.security.acl example provided with WebLogic Server in the samples/examples/security directory.

Listing 4-4 Example of Password Authentication


...
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
env.put(WLContext.PROVIDER_URL, "t3://weblogic:7001");
env.put(WLContext.SECURITY_AUTHENTICATION "simple");
env.put(Context.SECURITY_PRINCIPAL, "javaclient");
env.put(Context.SECURITY_CREDENTIALS, "password");

ctx = new InitialContext(env);


Listing 4-5 demonstrates how to use certificate authentication in a Java client. Notice the use of the t3s protocol, which is a WebLogic Server proprietary protocol over the SSL protocol. The SSL protocol protects the connection and communication between WebLogic Server and the Java client.

Listing 4-5 Example of Certificate Authentication


...
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
env.put(WLContext.PROVIDER_URL, "t3s://weblogic:7001");
env.put(WLContext.SECURITY_AUTHENTICATION "strong");
env.put(Context.SECURITY_PRINCIPAL, "javaclient");
env.put(Context.SECURITY_CREDENTIALS, "certforclient");

ctx = new InitialContext(env);


The code in Listing 4-4 and Listing 4-5 generates a call to weblogic.security.acl.Security.getUser() which returns a User object if the username and password are correct or if the digital certificate is valid. WebLogic Server stores this authenticated User object on the Java client's thread in WebLogic Server and uses it for subsequent authorization requests when the thread attempts to use resources protected by ACLs.

Using Mutual Authentication

When using certificate authentication, WebLogic Server sends a digital certificate to the requesting client. The client examines the digital certificate to ensure that it is authentic, has not expired, and matches the WebLogic Server that presented it.

With mutual authentication, the requesting client also presents a digital certificate to WebLogic Server. By setting fields in the Administration Console, you can configure WebLogic Server to require requesting clients to present digital certificates from a specified set of certificate authorities. WebLogic Server accepts only digital certificates that are signed by root certificates from the specified certificate authorities. For more information, see the "Configuring the SSL Protocol" section in Managing Security.

When using Web browsers, users must install their digital certificates in those browsers. Then using the HTTP and SSL protocols, WebLogic Server and the Web coordinates the digital certificate exchange with each Web browser.

When using JAAS for authentication in a Java client, you write a LoginModule class that performs mutual authentication.

When using JNDI for authentication in a Java client, use the setSSLClientCertificate() method of the WebLogic JNDI Environment class. This method sets a private key and chain of X.509 digital certificates for client authentication. To supply the Java client's digital certificate and private key read the Definite Encoding Rules (DER) files that contain the digital certificate and private key into an X509 object, and then set the X509 object in a JNDI hash table. Use the JNDI properties described in Using JNDI Authentication to specify the information required for authentication.

To pass digital certificates to JNDI, create an array of InputStreams opened on files containing DER-encoded digital certificates and set the array in the JNDI hash table. The first element in the array must contain an InputStream opened on the Java client's private key file. The second element must contain an InputStream opened on the Java client's digital certificate file. (This file contains the public key for the Java client.) Additional elements may contain the digital certificates of the root certificate authority and the signer of any digital certificates in a certificate chain. A certificate chain allows WebLogic Server to authenticate the digital certificate of the Java client if that digital certificate was not directly issued by a certificate authority registered for the Java client in the fileRealm.properties file.

You can use the weblogic.security.PEMInputStream class to read digital certificates stored in Privacy Enhanced Mail (PEM) files. This class provides a filter that decodes the base 64-encoded DER certificate into a PEM file.

Listing 4-6 demonstrates how to use mutual authentication in a Java client. The code in Listing 4-6 is excerpted from the AltClient in the examples.security.acl example in the samples/examples/security directory provided with WebLogic Server.

Listing 4-6 Example of Mutual Authentication


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 the JNDI getInitialContext() method is called, the Java client and WebLogic Server execute mutual authentication in the same way that a Web browser performs mutual authentication to get a secure Web server connection. An exception is thrown if the digital certificates cannot be validated or if the Java client's digital certificate cannot be authenticated in the security realm. The authenticated User object is stored on the Java client's server thread and is used for checking the permissions governing the Java client's access to any ACL-protected WebLogic Server resources.

When you use the WebLogic JNDI Environment class, you must create a new Environment object for each call to the getInitialContext() method. Once you specify a User and security credentials, both the user and their associated credentials remain set in the Environment object. If you try to reset them and then call the JNDI getInitialContext() method, the original User and credentials are used.

When you use mutual authentication from a Java client, WebLogic Server gets a unique Java Virtual Machine (JVM) ID for each client JVM so that the connection between the Java client and WebLogic Server is constant. Unless the connection times out from lack of activity, it persists as long as the JVM for the Java client continues to execute. The only way a Java client can negotiate a new SSL connection reliably is by stopping its JVM and running another instance of the JVM.

A Java client running in a JVM with an SSL connection can change the WebLogic Server User identity by creating a new JNDI InitialContext and supplying a new username and password in the JNDI SECURITY_PRINCIPAL and SECURITY_CREDENTIALS properties. Any digital certificates passed by the Java client after the SSL connection is made are not used. The new WebLogic Server User continues to use the SSL connection negotiated with the initial User's digital certificate.

If you implement the CertAuthenticator interface, WebLogic Server passes the digital certificate for the Java client to the implementation of the CertAuthenticator class. The CertAuthenticator class maps the digital certificate to a WebLogic Server User. Because the digital certificate is processed only at the time of the first connection request from the JVM, it is not possible to set a new user identity when you use the CertAuthenticator class.

Mapping a Digital Certificate to a WebLogic Server User

When you perform mutual authentication, WebLogic Server authenticates the digital certificate of the Web browser or Java client for in order to establish an SSL connection. However, the digital certificate does not identify the Web browser or Java client as a User in the WebLogic Server security realm. If the Web browser or Java client requests a WebLogic Server resource protected by an ACL, WebLogic Server requires the Web browser or Java client to provide a username and password.

To map a Web browser or Java client to a User in the WebLogic Server security realm, implement the weblogic.security.acl.CertAuthenticator interface. The CertAuthenticator class is called after an SSL connection has been established. The class can extract data from a digital certificate to determine which User owns the digital certificate. The CertAuthenticator class then calls the weblogic.security.acl.getUser() method to retrieve the authenticated User object from the WebLogic Server security realm.

When the CertAuthenticator class is installed, it is unnecessary for Web browsers to prompt for WebLogic Server usernames and for Java applications to set a password in the JNDI SECURITY_CREDENTIALS property. For more information, see the "Configuring the SSL Protocol" section in Managing Security.

If you use the CertAuthenticator class with a Java client application, note that the Java client cannot change the User identity once the SSL connection is established. To supply a new digital certificate, you must stop the JVM for the Java client and restart the client in a new JVM instance so that a new SSL connection can be negotiated.

You can use any of the several methods to map a digital certificate to a User. One technique is to set the password of a User to the fingerprint of the User's digital certificate. Then you can extract the username from the digital certificate, calculate the fingerprint, and call the weblogic.security.acl.getUser() method in the same way WebLogic Server does when a User submits a username and a password to access a resource.

Note: The fingerprint of a digital certificate is not part of the certificate but it can be computed from the certificate. A fingerprint is the MD5 digest of the DER-encoded CertificateInfo which is an ANS.1 type included in the X.509 specification.

The CertAuthenticator class has a public no-arg constructor and invokes the authenticate() method. WebLogic Server calls the authenticate() method with a username, which may be null, a Certificate array containing the digital certificate of the Java client or a certificate chain, and a Boolean that is true if an SSL handshake succeeds. You can call methods on the Certificate array to retrieve data from the digital certificate.

Listing 4-7 shows how to implement the CertAuthenticator interface. It extracts the username from the email address in the digital certificate and calls the weblogic.security.acl.getUser() method to retrieve an authenticated User object from the WebLogic Server security realm. Because the code example examines only a portion of the email address, this example is not very secure. Digital certificates with the same email address in different domains can be mapped to the same User and no additional authentication is performed. If you want to implement this feature, you may want to add code that fully establishes the identity of the client.

Listing 4-7 also shows how to map a digital certificate to a User in a WebLogic Server security realm. The code in Listing 4-7 is excerpted from SimpleCertAuthenticator in the examples.security.cert example in the samples/examples/security directory provided with WebLogic Server.

Listing 4-7 Example of Mapping a Digital Certificate to a WebLogic Server User



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
* @a 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 in Listing 4-7 shows how to get access to the WebLogic Server security realm in a server-side class. The getRealm("weblogic") method of the weblogic.security.acl.realm class returns the realm being used by WebLogic Server, whether it is the File realm or an alternative security realm, such as the LDAP Security realm.

The weblogic.security.X500Name class includes accessor methods to retrieve fields from the weblogic.security.Certificate class. Listing 4-7 casts the Certificate object to an X500Name object, calls the getEmail() method of the X500Name object, and takes the initial substring of the email address. The getUser(String) method in the weblogic.security.acl.AbstractableRealm class retrieves the WebLogic Server user with the computed username. If the user does not exist, the authenticate() method of the weblogic.security.acl.AbstractableRealm class returns null.

Using Mutual Authentication with Other WebLogic Servers

You can use mutual authentication in server-to-server communication in which one WebLogic Server is acting as the client of another WebLogic Server. Using mutual authentication in server-to-server communication allows you to depend on high-security connections, even without the more familiar client/server environment.

Listing 4-8 establishes a secure connection to a second WebLogic Server called server2.weblogic.com from a servlet running in WebLogic Server.

Listing 4-8 Establishing a Secure Connection to Another WebLogic Server


Environment e = new Environment ();
e.setProviderURL("t3s://server2.weblogic.com:443");
e.setSSLClientCertificateFromServer();
e.setSSLServerName("server2.weblogic.com");
e.setSSLRootCAFingerprints("ac45e2d1ce492252acc27ee5c345ef26");

T3Client t3c = e.createProviderClient();
t3c.connect();

e.setInitialContextFactory
("weblogic.jndi.WLInitialContextFactory");
Context ctx = new InitialContext(e.getProperties())


In Listing 4-8, the WebLogic JNDI Environment class creates a hash table to store the following parameters that are password with the weblogic.jndi.InitialContextFactory:

Using Mutual Authentication with Applets

Mutual authentication originated by an applet is difficult because an applet cannot access the digital certificate of the Web browser in which it is running. One solution is to give an applet indirect access to the digital certificate of the Web browser via WebLogic Server. A servlet can capture the digital certificate of a Web browser and reveal it only when a specific 64-bit token is presented. The servlet can then create an HTML page with an applet tag that passes the token as a parameter.

The CertAuthenticator servlet addresses the problem of how an applet can establish an SSL connection using the same digital certificate as the Web browser that loaded the applet. If your Web browser connects to WebLogic Server using the URL path authenticated/directory, the digital certificate presented by the Web browser is captured and stored in WebLogic Server as a randomly generated 64-bit token. The CertAuthenticator servlet then creates an HTML page for the applet. The HTML page contains the token, which the applet can redeem once. The applet presents the token to WebLogic Server and WebLogic Server accepts the token and authenticates the applet just as it would have done with a digital certificate. To use the CertAuthenticator servlet, you need to specify the name of the class that implements the servlet. For more information, see the "Configuring the SSL Protocol" section in Managing Security.

Using Mutual Authentication with Servlets

To authenticate Java clients in a servlet (or any other server-side Java class), you must check whether the client presented a digital certificate and if so, whether the certificate was issued by a trusted certificate authority. The servlet writer is responsible for asking whether the Java client has a valid digital certificate. When writing servlets with the WebLogic Servlet API, you must access information about the SSL connection through the getAttribute() method of the HTTPServletRequest object.

The following attributes are supported in WebLogic Server servlets:

You have access to the user information defined in the digital certificates. A digital certificate includes information, such as the following:

You can see the available information in each digital certificate by calling the to_string()method on the X509 object that represents the digital certificate.

You can create a weblogic.security.JDK11Certificate object for a digital certificate by passing an X509 object to its constructor. The weblogic.security.JDK11Certificate class implements the java.security.Certificate interface.

Listing 4-9 converts the first X509 object in an array of X509 objects to a JDK111Certificate object.

Listing 4-9 Converting an X509 Object to a JDK111Certificate Object


weblogic.security.JDK11Certificate jdk11cert =
new weblogic.security.JDK111Certificate(X509certs [0]);

print(out, "jdk11cert.getPrincipal().getName() -",
jdk11cert.getPrincipal().getName() );
print(out, "jdk11cert.getGuarantor().getName() -",
jdk11cert.getGuarantor().getName() );


The weblogic.security.JDK11Certificate class has the following member functions that provide additional information about the digital certificate:

Using Custom ACLs

WebLogic Server defines a standard set of access control lists (ACL)s to protect resources. If you create an ACL for a resource, WebLogic Server automatically checks the permissions for that resource before allowing anyone to access it. Most resources in WebLogic Server can be fully protected with these standard ACLs.

Some resources, however, require more protection than is offered by the standard set of ACLs. WebLogic Server allows you to augment the security for such resources. You may, for example, create a servlet that checks user permissions before writing certain data to a Web page. The weblogic.security.acl.Security class provides access to realm operations, such as checking an ACL. This class is available only to server-side code.

The Security.hasPermission() and Security.checkPermission() methods in the weblogic.security.acl.Security class test whether a user has the required permission necessary to access a resource. The two methods are similar except that the Security.hasPermission() method returns a Boolean (true if the user has the relevant permission) and the Security.checkPermission()method throws java.lang.SecurityException if the user does not have the permission.

The examples.security.acl example provided with WebLogic Server (in the samples/examples/security directory) shows how to create your own ACLs and test them in a server-side class. The custom ACL protects an RMI class, FrobImpl, with a custom ACL named aclexample that has the permission of frob.

Note: Before a custom ACL can be used, the ACL must be installed in the security realm being used by WebLogic Server.

To use the custom ACL, the Java client application must:

  1. Get a JNDI InitialContext from WebLogic Server.

  2. Look up the protected resource in the WebLogic Server JNDI tree using the permission name. For example, the Java client looks up FrobImpl using the permission name, frob.

  3. Execute the frob() method on the RMI stub.

The FrobImpl class contains the server-side code that tests the ACL. Listing 4-10 shows how to use the static checkPermission() method in the weblogic.security.acl.realm class to test the custom ACL.

Listing 4-10 Testing Custom ACLs in the Default Security Realm


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


You can also test custom ACLs in alternate security realms.

  1. Use the getRealm(realm_name) method of the weblogic.security.acl.realm class to get the alternate security realm.

  2. Retrieve the custom ACL and permission using the getACL()and the getPermission()methods of the weblogic.security.acl.realm class.

  3. Test the permission by calling the acl.checkPermission()method.

Listing 4-11 illustrates this technique for testing custom ACLs.

Listing 4-11 Testing Custom ACLs in an Alternate Security Realm


    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 in Listing 4-11 tests whether the custom ACL was found and whether the user p has the frob permission. The sense of the test is reversed; if the ACL exists and the user has frob permission, the result is false.

If you audit security events and you use the technique in Listing 4-12 for testing permissions, you must explicitly call the static Audit class of the weblogic.security.audit package if you want to audit your permission tests. The call to the Audit class generates a notification of the permission-checking event to the AuditProvider class in WebLogic Server.

Listing 4-12 Testing Permission


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


For a complete code example that uses custom ACLs, see the examples.security.acl package in the samples/examples/security directory provided by WebLogic Server.

Writing a Custom Security Realm

You may need to create your own security realm to draw from an existing security store in your environment such as a directory server on the network. To write a custom security realm that supports authentication you need to write code that:

  1. Defines a User class for the custom security realm.

  2. Defines a Group class for the custom security realm.

  3. Defines an enumeration classes that return all Users and Groups in a security store and release the resources of the security store when finished.

  4. Defines a class for the custom security realm.

  5. Obtains configuration data about the security store.

  6. Authenticates a User.

  7. Returns the members of a Group and creates a hash table that contains the members of a Group.

  8. Returns a User object given a User name.

  9. Returns a Group object given a Group name.

  10. Uses an enumeration for Users to return Users objects for all the Users in the security store.

  11. Uses an enumeration for Groups to return Group objects for all the Groups in the security store.

You can also write a custom security realm that supports authorization. For more information, see Using Authorization in a Custom Security Realm.

Note: WebLogic Server also provides the capability to create a custom security realm that can be managed through the WebLogic Server Administration Console. For more information, see the javadoc for the weblogic.security.acl package or contact BEA Professional Services.

Table 4-4 lists the WebLogic classes used to create a custom security realm:

Table 4-4 WebLogic Classes Used to Create Custom Security Realms

Class

Definition

weblogic.security.acl.User

Defines a User that is retrieved from a local security store.

weblogic.security.acl.
FlatGroup

Defines a Group whose membership is updated when the local security store is updated.

weblogic.security.acl.
CloseableEnumeration

Defines an enumeration that can be closed thus releasing resources.

weblogic.security.acl.
AbstractListableRealm

Allows you to create a security realm whose Users, Groups, ACLs, and permissions can be viewed through the Administration Console. However, you need to use the facilities provided by the security store you are using to add and delete Users, Groups, and ACLs and assign permissions to Users and Group.

weblogic.security.acl.
RefreshableRealm

Synchronizes the information about Users, Groups, ACLs, and permissions displayed in the Administration Console with the information in the local security store.

weblogic.management.
configuration.
CustomRealmMbean

Obtains configuration information about the security store accessed from the custom security realm.

Figure 4-1 illustrates how these classes work together to create a custom security realm.

Figure 4-1 WebLogic Classes Used to Create Custom Security Realms

The following sections describe the programming tasks required to write and custom security realm and how the WebLogic classes are used to in a custom security realm.

Define a Class for Users

Extend the weblogic.security.acl.User class to create a User class for the custom security realm.

Listing 4-13 contains code that defines a User class.

Listing 4-13 Defining a User Class


// Import the required classes
import weblogic.security.acl.user;
...

// Create a custom User class for the custom realm
/*package */class CustomRealmUser
extends User
{
// Keep track of the User's custom realm
CustomRealm realm = null;

// Implement a constructor
/*package*/ CustomRealmUser(String name, CustomRealm realm);

{
// Call base constructor class passing in the name of the
// User
super(name);

// Keep track of this User's realm
this.realm = realm;
}
// Return the User's custom realm
public BasicRealm getRealm()
{
return realm;
}
}
...


Define a Class for Groups

Groups make it easier to manage security. Internally, a custom security realm represents a Group as a hash table containing a list of members which can be Users or Groups.

To implement a Group in a custom security realm, extend the weblogic.security.acl.Flatgroup class to create a new Group with no membership information. The constructor for the class takes as input the name of the desired Group and the realm object corresponding to the custom security realm.

The Flatgroup class is especially designed to work with custom security realms. A custom security realm needs to periodically update Group membership. The FlatGroup maintains its group membership in a cache instead of in a static set. When the cache expires, the Group implementation queries the security store to obtain the most recent membership information. The default time for the Group cache is five minutes which means any changes you make in the underlying store will be recognized in the custom security realm within five minutes. You can tune this value by setting the GroupMembershipCacheTTL field in the Administration Console to the number of seconds a cached group remains valid.

Listing 4-14 contains code that defines a Group class.

Listing 4-14 Defining a Group Class


// Import the required classes
import weblogic.security.acl.FlatGroup;
...

/*package*/ class CustomRealmGroup
extends FlatGroup
{
// Implement a constructor
/*package*/ CustomRealmGroup(String name,
CustomRealm realm);
{
// Call the base class constructor passing in the name
// of the Group and custom security realm
super(name, source);
}
// Implement a method that returns the user class for
// custom security realm
protected Class getUserClass()
{
return CustomRealmUser.class;
}
}
...


Define Enumeration Classes for Users and Groups

Write an enumeration classes for Users and Groups. If the enumeration holds resources that must be released when the enumeration is done (for example, release a database cursor), then implement the weblogic.security.acl.CloseableEnumeration class. Otherwise, implement the java.util.Enumeration interface. In the enumerator constructor pass arguments needs to access the security store.

Do not create a User or Group object for every User or Group in the custom security realm and put them in a hash table that enumerates over them. A custom security realm in a deployed WebLogic Server can have more Users and Groups than can fit into memory. Instead, use a database cursor which can be used to incrementally create User or Groups objects as they are needed.

Listing 4-15 contains code that defines enumeration classes for users and groups.

Listing 4-15 Defining Enumeration Classes for Users and Groups


// Import the required classes
import weblogic.security.acl.FlatGroup;
import weblogic.security.acl.ClosableEnumeration;

...
// Define an enumeration class for users.
/*package*/ class CustomRealmUsersEnumeration
implements CloseableEnumeration
{
// Keep data members here (for example, a database cursor)

// Keep track of the enumeration's security realm (for
// use with the User constructor)
private CustomRealm realm = null;

// Implement a constructor
/*package */ CustomRealmUsersEnumeration(...,
CustomRealm realm)
{
this.realm = realm;
}

// Implement a method to determine if there are more Users.
public boolean hasMoreElements()
{
//For example, use a database cursor to see if there are
// more users
return (there are more users ...) ? true : false;
}

// Implement a method to return the next user.
// The method must return users objects that use the
// User class for the custom security realm
public Object nextElement()
{
// For example, use the database cursor to get the name
// of the next user.
return new CustomRealmUser(next user name ..., realm);
}

// Implement a method to terminate the enumeration.
// This step is optional
public void close()

{
// If this enumeration is delegating to an iterator that
// needs to be closed (e.g., a database cursor), release
// the resources here.
}
}

// Create a Group class for the custom security realm
/*package*/class CustomRealmGroupsEnumeration
implements CloseableEnumeration
{
// Keep data members here (for example, a database cursor

// Keep track of the enumeration's security realm (for
// use with the Groups constructor)
private CustomRealm realm = null;

// Implement a constructor
/*package */ CustomRealmUsersEnumeration(...,
CustomRealm realm)
{
this.realm = realm;
}

// Implement a method to determine if there are more Groups.
public boolean hasMoreElements()
{
// For example, use a database cursor to see if there are
// more groups
return (there are more groups ...) ? true : false;
}

         // Implement a method to return the next group.
// The method must return group objects that use the
// Group class for the custom security realm
public Object nextElement()
{
// For example, use the database cursor to get the name
// of the next group.
return new CustomRealmGroup(next group name ..., realm);
}

// Implement a method to terminate the enumeration.
// This step is optional
public void close()

{
// If this enumeration is delegating to an iterator that
// needs to be closed (e.g., a database cursor), release
// the resources here.
}
}
...


Define a Class for the Custom Security Realm

Extend the weblogic.security.acl.AbstractListableRealm class to define a new class for the custom security realm and implement a constructor that creates the custom security realm. This class needs to:

  1. Obtain configuration data for the security store.

  2. Authenticate Users.

  3. Determine the members of a Group

  4. Get Users and Groups from the security store.

Weblogic Server caches User and Group information in memory. Therefore, BEA recommends having a custom security realm go to disk to whenever it needs User or Group information. The WebLogic Server system administrator can only change Users or Groups for a custom security realm by editing the information in the security store with tools provided for the security store. After the system administrator changes User or Group information in the security store, the system administrator must update the information in the Administration Console by clicking on the Reset button. This action automatically flushes the User and Group information kept in memory.

If the custom security realm caches User or Group information in memory, implement the weblogic.security.acl.RefreshableRealm class and the refresh() method of the class. When the system administrator updates resets the realm, the refresh() method is called. Use the refresh() method to discard any cached User or Group information.

Listing 4-16 contains code that defines a class for a custom security realm.

Listing 4-16 Defining a Class for a Custom Security Realm


...
// Import the necessary classes
import weblogic.security.acl.AbstractListableRealm;
import weblogic.security.acl.BasicRealm;
import weblogic.security.acl.RefreshableRealm;
import weblogic.server.Server;

// Create a class for the custom security realm
public class CustomRealm
extends AbstractListableRealm // Required
implements Refreshable Realm // Optional

// Implement a constructor that creates the custom security realm
public CustomRealm()
{
super("Custom Realm");
...

public void refresh()
{
// Discard User and Group information in-memory
}


Obtain Configuration Data for the Security Store

In order to connect to the security store, configuration properties (for example, a property that contains a URL or a property that specifies a directory path) that specify how to access the security store used by the custom security realm must be defined. Once these properties are defined, the system administrator for WebLogic Server must set the properties in the Configuration Data section of the Custom Security Realm Create window in the Administration Console. The properties for the security store must be defined in the WebLogic Server administration environment before the custom security realm can be used.

For example, define two properties userInfoFileName and groupInforFileName that specify directory paths to files that contain User and Group information. The system administrator enters those properties in the Configuration Data section of the Custom Security Realm Create window in the Administration Console.

In the code for the custom security realm, use the weblogic.management.configuration.CustomRealmMbean class to retrieve configuration properties for the custom security and use those properties to connect to the security store.

Listing 4-17 contains code that retrieves configuration properties for the security store and then connects to the security store.

Listing 4-17 Accessing the Security Store


...
// Import the necessary classes
import weblogic.management.configuration.BasicRealmMBean;
import weblogic.management.configuration.CustonRealmMBean;

...
// Get the Custom Realm MBean
BasicRealmMBean basicRealmMBean =
Server.getSecurityConfig().getRealm().getCachingRealm.
getBasicRealm();

CustomRealmMBean customRealmMBean =
(CustomRealmMBean)basicRealmMBean;

// Get configuration data from the CustomRealmMBean
Properties configData = customRealmMBean.getConfigurationData();

// Get the properties for the custom security store.
String userInfoFileName =
configData.getProperty("UserInfoFileName);
String groupInfoFileName =
configData.getProperty("GroupInfoFileName);


Authenticate Users

If the custom security realm uses passwords to authenticate Users, you must explicitly implement the authUserPassword() method to authenticate Users. Write code that checks the security store to ensure that the user specified by the authUserPassword() method exists with the supplied password.

Listing 4-18 contains code that authenticates a User.

Listing 4-18 Authenticating Users


...
//Implement a method which authenticates a user
protected User authUserPassword(String name, String password)
{
// Check the security store to see if there is a user
// named name with password password

if (...) {
return new CustomRealmUser(name, this);
} else {
return null;
}
}


Determine the Members of a Group

Use the getGroupMembersInternal() method of the weblogic.security.acl.AbstractListableRealm class to get the members of a group and build a hash table with the members of a group.

Listing 4-19 contains code that obtains the members of a Group.

Listing 4-19 Obtaining the Members of a Group


...
// Implement a method to return members of a group.
protected Hashtable getGroupMembersInternal(String name)
{
// Check the security store to see if there is a group with
// the specified name
if (!...) {

// If the group does not exist, throw an exception
throw new CustomRealmException("No such group : " + name);
}

// Create a hash table with is filled with group members
// and is then returned.
Hashtable members = new Hashtable();

// Get the group members from the security store
for (...) {// loop over the members
if (...) {
// If this member is a user, create a user object
// for this user and add it to the list of members.
// Use the User class created for the custom
// security realm.
members.put(memberName, new CustomRealmUser
(memberName, this));
} else if
// If this member is a group, create a group object
// for this group and add it to the list of members.
// Use the Group class created for the custom
// security realm.
members.put(memberName, new CustomRealmGroup
(memberName, this));
}
}
// Return the hash table contains the members of the group.
return members;
}
...


Get Users and Groups from Security Store

Implement the getUser() and getGroup() methods of the weblogic.security.acl.AbstractListableRealm class to retrieve Users and Groups from the security store into the custom security realm. Use the getUsers() and getGroups() methods of the weblogic.security.acl.AbstractListableRealm class to return enumeration objects that return User objects and Group objects for the User and Groups in the security store. The Users and Groups in the security store can now be viewed through the Administration Console.

Listing 4-20 contains code that retrieves Users and Groups from the security store.

Listing 4-20 Retrieving Users and Groups from the Security Store


...
// Implement a method to return a User object given the name of
// the user.
public User getUser(String name)
{
// Check the security store to see if there is a user with the
// the specified name.
if (...) {
// If the user exists, return a User object for the
// the user. Use the User class created for the custom
// security realm.
return new CustomRealmUser(name, this);
} else {
// Return a null if the user does not exist
return null;
}
}

// Implement a method to return a Group object given the name of 
// the Group.
public Group getGroup(String name)
{
// Check the security store to see if there is a group with the
// the specified name.
if (...) {
// If the group exists, return a Group object for the
// the Group. Use the Group class created for the
// custom security realm
return new CustomRealmGroup(name, this
} else {
// Return a null if the group does not exist
return null;
}
}

// Implement a method to return an enumeration object that can 
// can be used to iterate over all the users in the custom security
// realm.
public Enumeration getUsers()
{
// Return an enumeration object that returns User object for
// the users in the security store. Use the user enumeration
// class created for the custom security realm. Remember to
// give the enumeration access to the security store so that
// it can iterate over the users.
return new CustomRealmUsersEnumeration(..., this);
}

// Implement a method to return an enumeration object that can 
// can be used to iterate over all the groups in the custom security
// realm.
public Enumeration getGroups()
{
// Return an enumeration object that returns Group object for
// the Groups in the security store. Use the group
// enumeration class created for the custom security realm.
// Remember to give the enumeration access to the security
// store so that it can iterate over the Groups.
return new CustomRealmGroupsEnumeration(..., this);
}
...


Using Authorization in a Custom Security Realm

To construct an ACL in a custom security realm, create a new AclImpl object, set its name, and then add an AclEntryImpl objects for each User or Group. Each AclEntry object contains a set of permissions associated with a particular principal which represents a User or a Group.

The AclImpl interface imposes an ordering constraint on constructing ACLs. You must add all permissions to an AclEntryImpl object before you add the AclEntryImpl object to the AclImpl object.

In the class for the custom security realm, use the getAcl() method to retrieve ACLs from a security store. The getAclInternal() method steps through the result set creating an AclImpl object, creating an AclEntryImpl object for each User or Group, and then adding permissions to the AclEntryImpl object. When an AclEntryImpl object is finished, it is added to the AclImpl object. When the AclImpl object is finished, the getAclInternal() method returns the finished ACL.

Auditing Security Events

The weblogic.security.audit package allows you to use an audit SPI for events that occur in the WebLogic Server security realm. The package includes an interface, AuditProvider, and a static class, Audit, to which WebLogic Server sends auditable security events.

To enable auditing, you create a class that implements the AuditProvider interface and the methods that represent the security events you want to audit. WebLogic Server calls the methods on your class when a user attempts to authenticate, when a permission is tested, or when an invalid digital certificate or root digital certificate is presented. Your AuditProvider class receives the information for each event type and 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.

Before you can use an AuditProvider class, you need to install the class through the Administration Console. For more information, see "Installing an Audit Provider" section in Managing Security.

The LogAuditProvider example is available in the examples.security.audit package in the /samples/examples/security/audit directory provided by WebLogic Server. The example writes all events it receives in the WebLogic Server log file. It also defines filter methods for each event type, and calls those filters 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, you can use the LogAuditProvider example as a starting point for creating your own provider.

Filtering Network Connections

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

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

Before you can use a Connection Filter, you need to install the class through the Administration Console. For more information, see the "Installing a Connection Filter" section in Managing Security.

When a Java client or Web browser client tries to connect to WebLogic Server, WebLogic Server constructs a ConnectionEvent object and passes it to the accept() method of your ConnectionFilter class. The ConnectionEvent object includes the remote IP address (in the form of java.net.InetAddress), the remote port number, the port number of the local WebLogic Server, and a string specifying the protocol (HTTP, HTTPS, T3, T3S, or IIOP).

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

The examples.security.net.SimpleConnectionFilter example provided in the samples/examples/security/net directory provided by WebLogic Server filters connections using a rules file. The SimpleConnectionFilter example parses the rules file and sets up a rule-matching algorithm so that connection filtering adds minimal overhead to a WebLogic Server connection. The SimpleConnectionFilter example is an efficient, generalized connection filter. If necessary, you can modify this code. You may, for example, want to accommodate the local or remote port number in your filter or a more site-specific algorithm that will reduce filtering overhead.

In Listing 4-21, WebLogic Server calls the SimpleConnectionFilter.accept() method with a ConnectionEvent. The SimpleConnectionFilter.accept() method gets the remote address and protocol and converts the protocol to a bitmask to avoid string comparisons in rule-matching. Then the SimpleConnectionFilter.accept() method compares the remote address and protocol against each rule until it finds a match.

Listing 4-21 Example of Filtering Network Connections


  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;
}


 

Back to Top