Authentication with Resin
Resin 3.1

Documentation
Examples
Changes

Overview
Installation
Configuration
Quercus
SOA/IoC
JSP
Servlets and Filters
Admin (JMX)
EJB
Amber
Security
Performance
Hessian
XML and XSLT
Third-party
Troubleshooting/FAQ

Authentication
Digest Passwords
Authorization
SSL
Security Manager
Malicious Attacks
FAQ
Scrapbook
Security
Security
Digest Passwords

Authentication provides a method for a username and password combination to be provided by a user and then verified by the web server. By using Resin's Authenticator API for login support, applications can add security without writing an entire authentication library.

Resin provides a predefined XML authenticator for user and password lookup in an XML file, a database authenticator for lookup in a database using JDBC, an LDAP authenticator for LDAP and Active Directory servers, and a JAAS authenticator. If the predefined authentication methods are inadequate, Resin provides an API to write custom authentication code.

Quick Start

The easiest authenticator to understand is the XmlAuthenticator. It lets you put users and passwords directly in the configuration file. The following example uses "Basic" authentication for login. Basic authentication asks the browser to pop open a window prompting for a username and password. (Basic authentication is discouraged because it is not secure unless you use it with SSL, but it's the easiest example.) The only user defined here is "Harry Potter" and he has the password "quidditch". He also plays the "user" role.

Using the XmlAuthenticator
<web-app xmlns="http://caucho.com/ns/resin">

  ...

  <authenticator type="com.caucho.server.security.XmlAuthenticator">
    <init>
      <user>Harry Potter:quidditch:user</user>
      <password-digest>none</password-digest>
    </init>
  </authenticator>

  <login-config auth-method='basic'/>

  <security-constraint url-pattern='/users-only/*' role-name='user'/>

  ...

</web-app>

In the above example, the <security-constraint> checks for authorization. Only users playing the "user" role can access the /users-only directory.

Another often used authenticator is the JdbcAuthenticator, which uses usernames, passwords, and roles stored in a database.

<web-app xmlns="http://caucho.com/ns/resin">

  ...

  <!-- Resin-specific JdbcAuthenticator -->
  <authenticator type='com.caucho.server.security.JdbcAuthenticator'>
    <init>
      <data-source>test</data-source>
      <password-query>
        SELECT password FROM LOGIN WHERE username=?
      </password-query>
      <cookie-auth-query>
        SELECT username FROM LOGIN WHERE cookie=?
      </cookie-auth-query>
      <cookie-auth-update>
        UPDATE LOGIN SET cookie=? WHERE username=?
      </cookie-auth-update>
      <role-query>
        SELECT role FROM LOGIN WHERE username=?
      </role-query>
    </init>
  </authenticator>

  <login-config auth-method='basic'/>

  <security-constraint url-pattern='/users-only/*' role-name='user'/>

  ...

</web-app>

Configuration

login-config

Configures the login class. The web.xml configuration describes the configuration in more detail.

The login can be customized by selecting the com.caucho.server.security.AbstractLogin. The type attribute will select that class. More sophisticated applications may want to add their own custom AbstractLogin class to replace the predefined values.

Typically a custom login would only be necessary if the application needed a custom way of extracting credentials from the request.

auth-method

Selects the authentication method.

auth-method values
auth-methodMeaning
basicHTTP Basic authentication
digestHTTP Digest authentication
formForm-based authentication

form-login-config

Configures authentication for forms. The login form has specific parameters that the servlet engine's login form processing understands. If the login succeeds, the user will see the original page. If it fails, she will see the error page.

form-login-pageThe page to be used to prompt the user loginnone
form-error-pageThe error page for unsuccessful loginnone
internal-forwardUse an internal redirect on success or a sendRedirectfalse
form-uri-priorityIf true, the form's j_uri will override a stored URIfalse

The form itself must have the action j_security_check. It must also have the parameters j_username and j_password. Optionally, it can also have j_uri and j_use_cookie_auth. j_uri gives the next page to display when login succeeds. j_use_cookie_auth allows Resin to send a persistent cookie to the user to make following login easier.

j_use_cookie_auth gives control to the user whether to generate a persistent cookie. It lets you implement the "remember me" button. By default, the authentication only lasts for a single session.

j_security_check Parameters
ParameterMeaning)
j_usernameThe user name
j_passwordThe password
j_uriResin extension for the successful display page (Optional).
j_use_cookie_authResin extension to allow cookie login (Optional).

The following is an example of a servlet-standard login page:

<form action='j_security_check' method='POST'>
<table>
<tr><td>User:<td><input name='j_username'>
<tr><td>Password:<td><input name='j_password'>
<tr><td colspan=2>hint: the password is 'quidditch'
<tr><td><input type=submit>
</table>
</form>

authenticator

Specifies a class to authenticate users. This Resin-specific option lets you control your authentication. You can either create your own custom authenticator, or use Resin's JdbcAuthenticator.

The authenticator is responsible for taking the username and password and returning a UserPrincipal if the username and password match.

Users wanting to implement an authenticator should look at the JavaDoc for com.caucho.server.security.ServletAuthenticator and com.caucho.server.security.AbstractAuthenticator. To protect your application from API changes, you should extend AbstractAuthenticator rather than implementing Authenticator directly.

XmlAuthenticator

The XmlAuthenticator (com.caucho.serer.security.XmlAuthenticator), stores the authentication in either an xml file or in the configuration itself.

When configuring the XmlAuthenticator in the resin.conf (or web.xml), each user adds a new configured user. The value contains the username, password, and the roles the user plays.

XmlAuthenticator in resin.conf
<authenticator type="com.caucho.server.security.XmlAuthenticator">
  <init>
    <user>Harry Potter:quidditch:user,gryffindor</user>
    <user>Draco Malfoy:pureblood:user,slytherin</user>
    <password-digest>none</password-digest>
  </init>
</authenticator>

Because the plain text passwords in the example above are a serious security issue, most sites will use the password-digest attribute described below to protect the passwords.

attributemeaningdefault
userspecifies an allowed user. May be repeated.none
password-digestselects the signature method to protect the passwordmd5-base64
pathspecifies a path to an XML file containing the users and passwords.none
logout-on-session-timeoutIf true, the user will be logged out when the session times outtrue

The passwords can be specified in a separate *.xml file. The password file looks like:

password.xml
<authenticator>
  <user name='Harry Potter' password='quidditch' roles='gryffindor'/>
  <user name='Draco Malfoy' password='pureblood' roles='slytherin'/>
</authenticator>

Sites should use password-digest to protect the passwords.

JdbcAuthenticator

The JdbcAuthenticator (com.caucho.server.security.JdbcAuthenticator) asks a backend database for the password matching the user's name. It uses the DataSource specified by the pool-name option, or the JNDI java:comp/env/jdbc/db-pool by default. pool-name refers to a DataSource configured with database.

The following are the attributes for the JdbcAuthenticator:

attributemeaningdefault
data-sourceThe database pool. Looks in the application attributes first, then in the global database pools.none
password-queryA SQL query to get the user's password. The default query is given below.see below
cookie-auth-queryA SQL query to authenticate the user by a persistent cookie.none
cookie-auth-updateA SQL update to match a persistent cookie to a user.none
role-queryA SQL query to determine the user's role. By default, all users are in role "user", but no others.none
password-digestSpecifies the digest algorithm and format (Resin 2.0.4)md5-base64
logout-on-session-timeoutIf true, the user will be logged out when the session times out (Resin 2.0.6)true
<web-app xmlns="http://caucho.com/ns/resin">

  ...

  <!-- Resin-specific JdbcAuthenticator -->
  <authenticator type='com.caucho.server.security.JdbcAuthenticator'>
    <init>
      <data-source>test</data-source>
      <password-query>
        SELECT password FROM LOGIN WHERE username=?
      </password-query>
      <cookie-auth-query>
        SELECT username FROM LOGIN WHERE cookie=?
      </cookie-auth-query>
      <cookie-auth-update>
        UPDATE LOGIN SET cookie=? WHERE username=?
      </cookie-auth-update>
      <role-query>
        SELECT role FROM LOGIN WHERE username=?
      </role-query>
    </init>
  </authenticator>

  <login-config auth-method='basic'/>

  <security-constraint url-pattern='/users-only/*' role-name='user'/>

  ...

</web-app>

LdapAuthenticator

The LdapAuthenticator (com.caucho.server.security.LdapAuthenticator) uses jndi to contact an LDAP (or Active Directory) server for authentication purposes.

attributemeaningdefault
dn-prefixstring to prepend to query before portion selecting user by namenone
dn-suffixstring to append to query after portion selecting user by namenone
jndi-envAdd a property to the jndi provider used for connecting to the ldap serversee below
logout-on-session-timeoutIf true, the user will be logged out when the session times outtrue
password-digestselects the signature method to protect the passwordmd5-base64
user-attributethe attribute name to use in the query for matching the useruid
password-attributethe attribute name to use for obtaining the passworduserPassword
urlthe url for the server (since Resin 3.1.1)ldap://localhost:389
<web-app xmlns="http://caucho.com/ns/resin">

  ...

  <authenticator>
    <type>com.caucho.server.security.LdapAuthenticator</type>
    <init>
      <url>ldap://localhost:389</url>
      <dn-suffix>dc=hogwarts,dc=com</dn-suffix>
      <password-digest>none</password-digest>
    </init>
  </authenticator>

  ...

</web-app>

jndi-env

jndi-env configures properties of the ldap provider implementation. Prior to 3.1.1, the url of the server is specified with jndi-env and the java.naming.provider.url property.

LdapAuthenticator jndi-env
  <authenticator>
    <type>com.caucho.server.security.LdapAuthenticator</type>
    <init>
      <jndi-env java.naming.factory.initial="com.sun.jndi.ldap.LdapCtxFactory"/>
      <jndi-env java.naming.provider.url="ldap://localhost:389"/>

      <dn-suffix>dc=hogwarts,dc=com</dn-suffix>
      <password-digest>none</password-digest>
    </init>
  </authenticator>

JaasAuthenticator

The JaasAuthenticator (com.caucho.server.security.JaasAuthenticator) uses a JAAS LoginModule for authentication. The JaasAuthenticator is an adapter that provides the ability to use the large number of JAAS LoginModule's included in the JDK for authentication purposes.

attributemeaningdefault
init-paramAdd a property to the LoginModulenone
login-moduleThe fully qualified class name of the LoginModule implementationrequired
logout-on-session-timeoutIf true, the user will be logged out when the session times outtrue
password-digestselects the signature method to protect the passwordmd5-base64
JaasAuthenticator configuration
<web-app xmlns="http://caucho.com/ns/resin">

  <authenticator type="com.caucho.server.security.JaasAuthenticator">
    <init>
      <login-module>com.sun.security.auth.module.Krb5LoginModule</login-module>
      <init-param>
        <debug>true</debug>
      </init-param>
    </init>
  </authenticator>

</web-app>

isUserInRole

The isUserInRole method is supported if the LoginModule provides either an isUserInRole method in the Principal returned by the LoginModule, or a getRoles() method returning a java.util.Set. (Since 3.0.19).

init-param

<init-param> directives are used to configure the properties of the LoginModule. Existing LoginModules provide documentation of the init-param that are accepted. Custom LoginModule implementations retrieve the init-param values in the initialize method.

Custom LoginModule

Custom LoginModule - java code
import java.util.*;

import javax.security.auth.*;
import javax.security.auth.spi.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;

public class TestLoginModule implements javax.security.auth.spi.LoginModule {
  private Subject _subject;
  private CallbackHandler _handler;
  private Map _state;
 
  private String _userName;
  private String _password;

  public void initialize(Subject subject,
                         CallbackHandler handler,
                         Map sharedState,
                         Map options)
   {
     _subject = subject;
     _handler = handler;
     _state = sharedState;

     _userName = (String) _options.get("user");
     _password = (String) _options.get("password");
   }

   public boolean login()
     throws LoginException
   {
     NameCallback name = new NameCallback("");
     PasswordCallback password = new PasswordCallback("", false);
 
     _handler.handle(new Callback[] { name, password });

     if (_userName.equals(name.getName()) && 
         _password.equals(password.getPassword()) {
         _subject.getPrincipals().add(new TestPrincipal(_userName));
       return true;
     }
     else
       return false;
   }

   public boolean abort()
   {
     return true;
   }

   public boolean commit()
   {
     return _subject.getPrincipals().size() > 0;
   }

   public boolean logout()
   {
      return true;
   }
}
Custom LoginModule - resin-web.xml configuration
<web-app xmlns="http://caucho.com/ns/resin">

  <authenticator type="com.caucho.server.security.JaasAuthenticator">
    <init>
      <login-module>example.TestModule</login-module>
      <init-param>
        <user>Harry</user>
        <password>quidditch</password>
      </init-param>
    </init>
  </authenticator>
</web-app>

AuthenticationList

AuthenticatorList (com.caucho.server.security.AuthenticatorList) is used to configure more than one authenticator in a list, each authenticator is tried in turn and if the authentication fails the next authenticator in the list is attempted.

  <authenticator type="com.caucho.server.security.AuthenticatorList">
    <init>
      <authenticator resin:type="com.caucho.server.security.XmlAuthenticator">
        <user>admin:NIHlOSafJN2H7emQCkOQ2w==:user,admin</user>
      </authenticator>

      <authenticator resin:type='com.caucho.server.security.JdbcAuthenticator'>
        <data-source>jdbc/users</data-source>
        <password-query>
          SELECT password FROM LOGIN WHERE username=?
        </password-query>
        <cookie-auth-query>
          SELECT username FROM LOGIN WHERE cookie=?
        </cookie-auth-query>
        <cookie-auth-update>
          UPDATE LOGIN SET cookie=? WHERE username=?
        </cookie-auth-update>
        <role-query>
          SELECT role FROM LOGIN WHERE username=?
        </role-query>
      </authenticator>
    </init>
  </authenticator>

  <login-config auth-method='basic'/>

  <security-constraint url-pattern='/users/*' role-name='user'/>
  <security-constraint url-pattern='/admin/*' role-name='admin'/>

password-digest

Resin has the capability of storing the digest of a password instead of the password itself. By using the password digest, the application can avoid storing the password in a form that someone can read.

Setting password-digest of any authenticator extending com.caucho.server.security.AbstractAuthenticator will create a digest of the password. The password-digest has two parts: the digest algorithm and the encoding format. "MD5-base64" is a typical digest format, and is the default for the Resin authenticators..

The use of a password digest is more completely described in Digest Passwords.

Single Signon

"Single signon" refers to allowing for a single login for more than one context, for example, logging in to all web-apps in a server at once. You can implement single signon by configuring the authenticator in the proper environment: web-app, host, or server. The login will last for all the web-apps in that environment.

The authenticator is a resource which is shared across its environment. For example, to configure the XML authenticator for all web-apps in foo.com, you might configure as follows:

Single Signon for foo.com
<resin xmlns="http://caucho.com/ns/resin">
  <cluster id="app-tier>
    <http port="8080"/>

    <host id="foo.com">
      <root-directory>/opt/foo.com</root-directory>

      <authenticator type="com.caucho.server.security.XmlAuthenticator">
        <init>
          <!-- password: quidditch -->
          <user>harry:uTOZTGaB6pooMDvqvl2LBu:user,gryffindor</user>
          <!-- password: pureblood -->
          <user>dmalfoy:yI2uN1l97Rv5E6mdRnDFDB:user,slytherin</user>
        </init>
      </authenticator>

      <web-app-deploy path="webapps"/>
    </host>
  </cluster>
</resin>

Any .war in the webapps directory will share the same signon for the host. You will still need to implement a login-config for each web-app.

The value of reuse-session-id must be true for single signon.

Single signon for virtual hosts

The basis for establishing client identity is the JSESSIONID cookie. If single signon is desired for virtual hosts, Resin must be configured to notify the browser of the proper domain name for the cookie so that the same JSESSIONID cookie is submitted by the browser to each virtual host.

The authenticator is placed at the cluster level so that it is common to all virtual hosts. The cookie-domain is placed in a web-app-default at the cluster level so that it is applied as the default for all webapps in all virtual hosts.

Single Signon for gryffindor.hogwarts.com and slytherin.hogwarts.com
<resin xmlns="http://caucho.com/ns/resin">
  <cluster id="app-tier>
    <http port="8080"/>

    <authenticator type="com.caucho.server.security.XmlAuthenticator">
      ...
    </authenticator>

    <web-app-default>
      <session-config>
        <enable-url-rewriting>false</enable-url-rewriting>
        <cookie-domain>.hogwarts.com</cookie-domain>
      </session-config>
    </web-app-default>


    <host id="gryffindor.hogwarts.com">
      ...
    </host>

    <host id="slytherin.hogwarts.com">
      ...
    </host>
  </server>
</resin>

Because of the way that browsers are restricted by the HTTP specification from submitting cookies to servers, it is not possible to have a single signon for virtual hosts that do not share some portion of their domain name. For example, "gryffindor.com" and "slytherin.com" cannot share a common authentication.

Custom Login

The Login is primarily responsible for extracting the credentials from the request (typically username and password) and passing those to the ServletAuthenticator.

The Servlet API calls the Login in two contexts: directly from ServletRequest.getUserPrincipal(), and during security checking. When called from the Servlet API, the login class can't change the response. In other words, if an application calls getUserPrincipal(), the Login class can't return a forbidden error page. When the servlet engine calls authenticate(), the login class can return an error page (or forward internally.)

Normally, Login implementations will defer the actual authentication to a ServletAuthenticator class. That way, both "basic" and "form" login can use the same JdbcAuthenticator. Some applications, like SSL client certificate login, may want to combine the Login and authentication into one class.

Login instances are configured through bean introspection. Adding a public setFoo(String foo) method will be configured with the following login-config:

<login-config type="test.CustomLogin">
  <init>
    <foo>bar</bar>
  </init>
</login-config>

Security
Security
Digest Passwords
Copyright © 1998-2006 Caucho Technology, Inc. All rights reserved.
Resin ® is a registered trademark, and Quercustm, Ambertm, and Hessiantm are trademarks of Caucho Technology.