Resin Security

From Resin 3.0

Jump to: navigation, search

<document> <header>

 <product>resin</product>
 <title>Resin 4.0 Security</title>
 <description>
 </description>

</header>

<body>

<localtoc/>

<s1 title="Samples">

<s2 title="Local Access Authorization">

If you want an administration page to be accessible only from a local network, you can use the <resin:Allow> and <resin:IfNetwork> tags together to ensure only local requests are authorized.

<example title="WEB-INF/resin-web.xml - local network only"> <web-app xmlns="http://caucho.com/ns/resin"

         xmlns:resin="urn:java:com.caucho.resin">
 <resin:Allow url-pattern="/admin/*">
   <resin:IfNetwork>
     <resin:value>127.0.0.1</resin:value>
     <resin:value>192.168.0.0/16</resin:value>
   </resin:IfNetwork>
 </resin:Allow>

</web-app> </example>

  • <resin:Allow> creates an allow authorization rule. If all the contents match, the pattern is allowed.
  • <resin:IfNetwork> matches a set of IP addresses using standard network notation. If any address matches, <resin:IfNetwork> is true.

Because the local access protection only involves authorization, it's a shorter example than cases requiring a login.

</s2>

<s2 title="Hide URLs from browsing">

In cases like WEB-INF, when you want to protect files from any browsing, local or not, you can use a single <resin:Deny> authorization to prevent access.

<example title="hiding /hidden/*"> <web-app xmlns="http://caucho.com/ns/resin"

         xmlns:resin="urn:java:com.caucho.resin">
 <resin:Deny>
    <resin:url-pattern>/hidden/*</resin:url-pattern>
    <resin:url-pattern>*.hidden</resin:url-pattern>
 </resin:Deny>

</web-app> </example>

</s2>

<s2 title="XML Authentication">

If a section of a web-site needs basic password protection, you can use HTTP Basic authentication, an <resin:IfRule> authorization and an XML authenticator as follows.

<example title="WEB-INF/resin-web.xml - Simple Password Protection"> <web-app xmlns="http://caucho.com/ns/resin"

           xmlns:resin="urn:java:com.caucho.resin">
 <resin:Allow url-pattern="/secure/*">
   <resin:IfUserInRole role="*"/>
 </resin:Allow>
 <resin:FormLogin login-page="/login.jsp"/>
 <resin:XmlAuthenticator>
    <resin:user name="harry" password="uTOZTGaB6pooMDvqvl2Lbg==" group="user"/>
 </resin:XmlAuthenticator>

</web-app> </example>

For security, the password is secured with an MD5 hash, because plaintext passwords aren't very secure at all. The easiest way to generate the hash is with a short PHP script:

<example title="PHP generation of MD5 hash"> <?php

echo base64_encode(md5("harry:resin:quidditch", true)) . "\n";

</example>

  • <resin:Allow> protects a section of the web-app, i.e. providing an authorization context.
  • <url-pattern> matches the URLs to be protected
  • <resin:IfUserInRole> protects the web-app through login (as opposed to by IP address or by SSL)
  • <resin:FormLogin> specifies the form login method
  • <resin:XmlAuthenticator> defines the login users and passwords. The XML authenticator specifies a simple XML file for user definition.

</s2>

</s1>

<s1 title="Overview">

<deftable title="Authenticators"> <tr>

 <th>name</th>
 <th>description</th>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/AdminAuthenticator.html"><resin:AdminAuthenticator></a></td>
 <td>Resin administration authentication (same syntax as XmlAuthenticator).</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/DatabaseAuthenticator.html"><resin:DatabaseAuthenticator></a></td>
 <td>Authentication using a JDBC database schema.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/JaasAuthenticator.html"><resin:JaasAuthenticator></a></td>
 <td>Java authentication service authenticator.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/LdapAuthenticator.html"><resin:LdapAuthenticator></a></td>
 <td>LDAP authentication using JNDI.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/PropertiesAuthenticator.html"><resin:PropertiesAuthenticator></a></td>
 <td>.properties file authentication.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/XmlAuthenticator.html"><resin:XmlAuthenticator></a></td>
 <td>.xml file authentication.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/AbstractAuthenticator.html">AbstractAuthenticator</a></td>
 <td>Abstract class for custom authentication.</td>

</tr> </deftable>

<deftable title="Single Signon"> <tr>

 <th>name</th>
 <th>description</th>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/ClusterSingleSignon.html"><resin:ClusterSingleSignon></a></td>
 <td>Cluster-based single signon.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/MemorySingleSignon.html"><resin:MemorySingleSignon></a></td>
 <td>Memory-based single signon.</td>

</tr> </deftable>

<deftable title="Login managers"> <tr>

 <th>name</th>
 <th>description</th>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/BasicLogin.html"><resin:BasicLogin></a></td>
 <td>HTTP basic authentication.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/DigestLogin.html"><resin:DigestLogin></a></td>
 <td>HTTP digest authentication.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/FormLogin.html"><resin:FormLogin></a></td>
 <td>Servlet form authentication.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/AbstractLogin.html">AbstractLogin</a></td>
 <td>Abstract class for custom login.</td>

</tr> </deftable>


<deftable title="Authorization rules"> <tr>

 <th>name</th>
 <th>description</th>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/Allow.html"><resin:Allow></a></td>
 <td>Allows access to a URL pattern.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/Deny.html"><resin:Deny></a></td>
 <td>Denies access to a URL pattern.</td>

</tr> </deftable>

<deftable title="Basic conditions"> <tr>

 <th>name</th>
 <th>description</th>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfAuthType.html"><resin:IfAuthType></a></td>
 <td>Checks for the authentication type, request.getAuthType().</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfCookie.html"><resin:IfCookie></a></td>
 <td>Checks for the presence of a named HTTP cookie from request.getCookies().</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfCron.html"><resin:IfCron></a></td>
 <td>Matches if the current time is in an active range configured by cron-style times.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfFileExists.html"><resin:IfFileExists></a></td>
 <td>Matches if the URL corresponds to an actual file.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfHeader.html"><resin:IfHeader></a></td>
 <td>Tests for a HTTP header and value match.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfLocale.html"><resin:IfLocale></a></td>
 <td>Tests for a Locale match from the HTTP request.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfLocalPort.html"><resin:IfLocalPort></a></td>
 <td>Compares the local port of the request, request.getLocalPort().</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfMethod.html"><resin:IfMethod></a></td>
 <td>Compares the HTTP method, request.getMethod().</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfNetwork.html"><resin:IfNetwork></a></td>
 <td>Compares the remote IP address to a network pattern like 192.168/16.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfQueryParam.html"><resin:IfQueryParam></a></td>
 <td>Tests for a HTTP query parameger, request.getParameter().</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfRemoteAddr.html"><resin:IfRemoteAddr></a></td>
 <td>Tests against the remote IP address, request.getRemoteAddr().</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfRemoteUser.html"><resin:IfRemoteUser></a></td>
 <td>Tests against the remote user, request.getRemoteUser().</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfSecure.html"><resin:IfSecure></a></td>
 <td>True for SSL requests, i.e. if request.isSecure() is true.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/IfUserInRole.html"><resin:IfUserInRole></a></td>
 <td>Tests is the user is in the servlet security role.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/RequestPredicate.html">RequestPredicate</a></td>
 <td>Interface for custom request predicates.</td>

</tr> </deftable>

<deftable title="Combining conditions"> <tr>

 <th>name</th>
 <th>description</th>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/And.html"><resin:And></a></td>
 <td>Matches if all children match.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/Or.html"><resin:Or></a></td>
 <td>Matches if any children match.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/Not.html"><resin:Not></a></td>
 <td>Matches if the child does not match.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/NotAnd.html"><resin:NotAnd></a></td>
 <td>Matches if any child does not match.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/rewrite/NotOr.html"><resin:NotOr></a></td>
 <td>Matches if all the children do not match.</td>

</tr> </deftable>

<deftable title="Permission Mapping"> <tr>

 <th>name</th>
 <th>description</th>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/XmlRoleMap.html"><resin:XmlRoleMap></a></td>
 <td>Role to group permission mapping.</td>

</tr> <tr>

 <td><a href="http://caucho.com/resin-javadoc/com/caucho/security/AbstractRoleMap.html">AbstractRoleMap</a></td>
 <td>Abstract class for custom role to group permission mapping.</td>

</tr> </deftable>

</s1>

<s1 title="Management">

Since all Resin users will want to protect the /resin-admin pages with an administration password, and protect any clustered management and deployment, Resin's top-level <resin:AdminAuthenticator> tag includes a static, XML-based authentication context. The authenticator is automatically shared for all hosts and web-apps, so simple sites can even use this authenticator configuration for their site-wide authentication.

<example title="resin.xml"> <resin xmlns="http://caucho.com/ns/resin"

   xmlns:resin="urn:java:com.caucho.resin">
 <resin:AdminAuthenticator>
    <user name="admin" password="MD5HASH=="/>
    ...
 </resin:AdminAuthenticator>
 ...

</resin> </example>

The password is a hash of the user name, password, and the "resin" realm. The /resin-admin page includes a form to easily generate the MD5 hash. You can also use the <a href="http://caucho.com/resin-javadoc/com/caucho/server/security/PasswordDigest.html">PasswordDigest</a> class to generate the digest programmatically.

</s1>

<s1 title="Authentication">

Resin provides a basic set of authenticators covering the most common cases. Applications which need custom authenticators can easily write their own extensions, described below.

<s2 title="DatabaseAuthenticator" version="Resin 4.0.0">

The DatabaseAuthenticator (<a href="javadoc|com.caucho.security.DatabaseAuthenticator|"/>) asks a backend database for the password matching the user's name. It uses the DataSource specified by the data-source option. data-source refers to a DataSource configured with <a href="../reference/env-tags.xtp#database">database</a>.

The following are the attributes for the DatabaseAuthenticator:

<deftable> <tr>

 <th>attribute</th>
 <th>meaning</th>
 <th>default</th>

</tr> <tr>

 <td>data-source</td>
 <td>The database pool.  Looks in the application attributes first, then
 in the global database pools.</td>
 <td>none</td>

</tr> <tr>

 <td>password-query</td>
 <td>A SQL query to get the user's password.  The default query is given
 below.</td>
 <td>see below</td>

</tr> <tr>

 <td>cookie-auth-query</td>
 <td>A SQL query to authenticate the user by a persistent cookie.</td>
 <td>none</td>

</tr> <tr>

 <td>cookie-auth-update</td>
 <td>A SQL update to match a persistent cookie to a user.</td>
 <td>none</td>

</tr> <tr>

 <td>role-query</td>
 <td>A SQL query to determine the user's role.  By

default, all users are in role "user", but no others.</td>

 <td>none</td>

</tr> <tr>

 <td><a href="#password-digest">password-digest</a></td>
 <td>Specifies the digest algorithm and format (Resin 2.0.4)</td>
 <td>md5-base64</td>

</tr> <tr>

 <td>logout-on-session-timeout</td>
 <td>If true, the user will be logged out when the session times out (Resin 2.0.6)</td>
 <td>true</td>

</tr> </deftable>

<example title="WEB-INF/resin-web.xml for DatabaseAuthenticator"> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin">
 ...
 <!-- DatabaseAuthenticator -->
 <resin:DatabaseAuthenticator'>
   <resin:data-source>test</resin:data-source>
   
   <resin:password-query>
     SELECT password FROM LOGIN WHERE username=?
   </resin:password-query>
   
   <resin:cookie-auth-query>
     SELECT username FROM LOGIN WHERE cookie=?
   </resin:cookie-auth-query>
   
   <resin:cookie-auth-update>
     UPDATE LOGIN SET cookie=? WHERE username=?
   </resin:cookie-auth-update>
   
   <resin:role-query>
     SELECT role FROM LOGIN WHERE username=?
   </resin:role-query>
 </resin:DatabaseAuthenticator>
 <resin:BasicLogin/>
 <resin:Allow url-pattern="/users-only/*">
    <resin:IfUserInRole role="user"/>
 </resin:Allow>
 ...

</web-app> </example>

</s2>

<s2 title="JaasAuthenticator" version="Resin 4.0.0">

The JaasAuthenticator (<a href="javadoc|com.caucho.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.

<deftable title="JaasAuthenticator attributes"> <tr>

 <th>attribute</th>
 <th>meaning</th>
 <th>default</th>

</tr> <tr>

 <td><a href="#jaas-init-param">init-param</a></td>
 <td>Add a property to the LoginModule</td>
 <td>none</td>

</tr> <tr>

 <td>login-module</td>
 <td>The fully qualified class name of the LoginModule implementation</td>
 <td>required</td>

</tr> <tr>

 <td>logout-on-session-timeout</td>
 <td>If true, the user will be logged out when the session times out</td>
 <td>true</td>

</tr> <tr>

 <td><a href="#password-digest">password-digest</a></td>
 <td>selects the signature method to protect the password</td>
 <td>md5-base64</td>

</tr> </deftable>

<example title="WEB-INF/resin-web.xml JaasAuthenticator"> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin">
 <resin:JaasAuthenticator>
   <resin:login-module>com.sun.security.auth.module.Krb5LoginModule</resin:login-module>
   <resin:init-param>
     <debug>true</debug>
   </resin:init-param>
 </resin:JaasAuthenticator>

</web-app> </example>

<s3 name="jaas-is-user-in-role" title="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).

</s3>

<s3 name="jaas-init-param" title="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.

</s3>

<s3 name="jaas-custom" title="Custom LoginModule">

<example title="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;
  }

} </example>

<example title="Custom LoginModule - resin-web.xml configuration"> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin">
 <resin:JaasAuthenticator>
   <resin:login-module>example.TestModule</resin:login-module>
   
   <resin:init-param>
     <user>Harry</user>
     <password>quidditch</password>
   </resin:init-param>
 </resin:JaasAuthenticator>

</web-app> </example> </s3>

</s2>

<s2 title="LdapAuthenticator" version="Resin 4.0.0">

The LdapAuthenticator (<a href="javadoc|com.caucho.security.LdapAuthenticator|"/>) uses jndi to contact an LDAP (or Active Directory) server for authentication purposes.

<deftable> <tr>

 <th>attribute</th>
 <th>meaning</th>
 <th>default</th>

</tr> <tr>

 <td>dn-prefix</td>
 <td>string to prepend to query before portion selecting user by name</td>
 <td>none</td>

</tr> <tr>

 <td>dn-suffix</td>
 <td>string to append to query after portion selecting user by name</td>
 <td>none</td>

</tr> <tr>

 <td><a href="#jndi-env">jndi-env</a></td>
 <td>Add a property to the jndi provider used for connecting to the ldap server</td>
 <td>see below</td></tr>

<tr>

 <td>logout-on-session-timeout</td>
 <td>If true, the user will be logged out when the session times out</td>
 <td>true</td>

</tr> <tr>

 <td>security-authentication</td>
 <td>Sets the Context.SECURITY_AUTHENTICATION for the ldap environment</td>
 <td></td>

</tr> <tr>

 <td>security-principal</td>
 <td>Sets the Context.SECURITY_PRINCIPAL for the ldap environment</td>
 <td></td>

</tr> <tr>

 <td>security-credentials</td>
 <td>Sets the Context.SECURITY_CREDENTIALS for the ldap environment</td>
 <td></td>

</tr> <tr>

 <td><a href="#password-digest">password-digest</a></td>
 <td>selects the signature method to protect the password</td>
 <td>md5-base64</td>

</tr> <tr>

 <td>user-attribute</td>
 <td>the attribute name to use in the query for matching the user</td>
 <td>uid</td>

</tr> <tr>

 <td>password-attribute</td>
 <td>the attribute name to use for obtaining the password</td>
 <td>userPassword</td>

</tr> <tr>

 <td>url</td>
 <td>the url for the server</td>
 <td>ldap://localhost:389</td>

</tr> </deftable>

<example title="WEB-INF/resin-web.xml for LdapAuthenticator"> <web-app xmlns="http://caucho.com/ns/resin"

         xmlns:resin="urn:java:com.caucho.resin">
 ...
 <resin:LdapAuthenticator password-digest="none">
   <resin:url>ldap://localhost:389</resin:url>
   <resin:dn-suffix>dc=hogwarts,dc=com</resin:dn-suffix>
 </resin:LdapAuthenticator>
 ...

</web-app> </example>

<s3 title="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.

<example title="WEB-INF/resin-web.xml LdapAuthenticator jndi-env"> <web-app xmlns="http://caucho.com/ns/resin"

         xmlns:resin="urn:java:com.caucho.resin">
 <resin:LdapAuthenticator password-digest="none">
   <resin:jndi-env java.naming.factory.initial="com.sun.jndi.ldap.LdapCtxFactory"/>
   <resin:jndi-env java.naming.provider.url="ldap://localhost:389"/>
   <resin:dn-suffix>dc=hogwarts,dc=com</dn-suffix>
 </resin:LdapAuthenticator>

<web-app> </example> </s3> </s2>

<s2 title="PropertiesAuthenticator">

<example title="WEB-INF/resin-web.xml - inline properties"> <web-app xmlns="http://caucho.com/ns/resin"

         xmlns:resin="urn:java:com.caucho.resin">
 <resin:PropertiesAuthenticator password-digest="none">
    harry=quidditch,user,admin
    draco=mudblood,disabled,user
 </resin:PropertiesAuthenticator>

</web-app> </example>

<example title="WEB-INF/resin-web.xml - file property"> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin"
 <resin:PropertiesAuthenticator path="WEB-INF/users.properties"/>

</web-app> </example>

<example title="WEB-INF/users.properties"> harry=/Tj/54ylCloUeMi2YQIVCQ===,user,admin </example>

</s2>

<s2 title="XmlAuthenticator">

<example title="WEB-INF/resin-web.xml - inline xml"> <web-app xmlns="http://caucho.com/ns/resin"

       xmlns:resin="urn:java:com.caucho.resin">
 <resin:XmlAuthenticator password-digest="none">
    <resin:user name="harry" password="quidditch"/>
 </resin:XmlAuthenticator>

</web-app> </example>

<example title="WEB-INF/resin-web.xml - file xml"> <web-app xmlns="http://caucho.com/ns/resin">

 <resin:XmlAuthenticator path="WEB-INF/users.xml"/>

</web-app> </example>

<example title="WEB-INF/users.xml"> <users>

 <user name="harry password="/Tj/54ylCloUeMi2YQIVCQ===" roles="user,admin"/>

<users> </example>

</s2>

<s2 title="XmlAuthenticator" version="Resin 4.0.0">

The XmlAuthenticator (<a href="http://caucho.com/resin-javadoc/com.caucho.security.XmlAuthenticator">com.caucho.security.XmlAuthenticator</a>), stores the authentication in either an xml file or in the configuration itself.

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

<example title="XmlAuthenticator in resin-web.xml"> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin">
 <resin:XmlAuthenticator password-digest="none">
   <resin:user name="Harry Potter" password="quidditch" group="user,gryffindor"/>
   <resin:user name="Draco Malfoy" password="pureblood" group=":user,slytherin"/>
 </resin:XmlAuthenticator>

</web-app> </example>

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.

<deftable> <tr>

 <th>attribute</th>
 <th>meaning</th>
 <th>default</th>

</tr> <tr>

 <td>user</td>
 <td>specifies an allowed user.  May be repeated.</td>
 <td>none</td>

</tr> <tr>

 <td><a href="#password-digest">password-digest</a></td>
 <td>selects the signature method to protect the password</td>
 <td>md5-base64</td>

</tr> <tr>

 <td>path</td>
 <td>specifies a path to an XML file containing the users and passwords.</td>
 <td>none</td>

</tr> <tr>

 <td>logout-on-session-timeout</td>
 <td>If true, the user will be logged out when the session times out</td>
 <td>true</td>

</tr> </deftable>

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

<example title="password.xml"> <authenticator>

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

</authenticator> </example>

Sites should use <a href="#password-digest">password-digest</a> to protect the passwords.

</s2>


<s2 title="custom Authenticator">

<example title="WEB-INF/resin-web.xml - custom"> <web-app xmlns="http://caucho.com/ns/resin"

       xmlns:foo="urn:java:com.caucho.foo">
 <foo:MyAuthenticator>
   <foo:foo>bar</foo:foo>
 </foo:MyAuthenticator>

</web-app> </example>

<example title="MyAuthenticator.java"> package com.foo;

import com.caucho.security.AbstractAuthenticator; import com.caucho.security.PasswordUser;

public class MyAuthenticator extends AbstractAuthenticator {

 private PasswordUser _user;
 public MyAuthenticator()
 {
   _user = new PasswordUser("harry", "quidditch",
                            new String[] { "user" });
 }
 public PasswordUser getUser(String userName)
 {
   if (userName.equals(_user.getName()))
     return _user;
   else
     return null;
 }

} </example>

</s2>

</s1>

<s1 title="Digest passwords">

<s2 title="Digest protects passwords">

Digest passwords enable an application to avoid storing and even transmitting the password in a form that someone can read.

A digest of a cleartext password is calculated when it is passed through a one-way function that consistently produces another series of characters, digestPassword = digester(username + ":" + realm + ":" cleartextPassword). The function is "one-way" because the digestPassword cannot be used to reverse-engineer the original password.

For example, Resin uses md5 and base64 as the default. You can create the hash with a simple PHP script like:

<example title="digest.php"> <?php

echo base64_encode(md5("harry:resin:quidditch")) . "\n";

</example>

Digest passwords can be used in two places: storage and transmission. Digest passwords in storage means that the password is stored in a digested form, for example in a database or in a file. Digest passwords in transmission means that the client (usually a web browser) creates the digest and submits the digest password to the web server.

Storing digest passwords is so important for security purposes that the Resin authenticators default to assuming that the passwords are stored in digest form.

The important advantage is that a user's cleartext password is not as easily compromised. Since the password they use (the "cleartext" password) is not stored a malicious user cannot determine the password by gaining access to the database or other backend storage for the passwords.

</s2>

<s2 title="MD5 digest">

Resin's authenticators use "MD5-base64" and a realm "resin" to digest passwords by default. MD5 indicates that the MD5 algorithm is used. base64 is an encoding format to apply to the binary result of MD5.


Some examples are:

<deftable> <tr><th>Username</th><th>Realm</th><th>Password</th><th>digest </th></tr><tr><td>root</td><td>resin</td><td>changeme</td><td>j/qGVP4C0T7UixSpKJpTdw== </td></tr><tr><td>harry</td><td>resin</td><td>quidditch</td><td>uTOZTGaB6pooMDvqvl2Lbg== </td></tr><tr><td>hpotter</td><td>resin</td><td>quidditch</td><td>x8i6aM+zOwDqqKPRO/vkxg== </td></tr><tr><td>filch</td><td>resin</td><td>mrsnorris</td><td>KmZIq2RKXAHV4BaoNHfupQ== </td></tr><tr><td>pince</td><td>resin</td><td>quietplease</td><td>Txpd1jQc/xwhISIqodEjfw== </td></tr><tr><td>snape</td><td>resin</td><td>potion</td><td>I7HdZr7CTM6hZLlSd2o+CA== </td></tr><tr><td>mcgonagall</td><td>resin</td><td>quidditch</td><td>4slsTREVeTo0sv5hGkZWag== </td></tr><tr><td>dmalfoy</td><td>resin</td><td>pureblood</td><td>yI2uN1l97Rv5E6mdRnDFwQ== </td></tr><tr><td>lmalfoy</td><td>resin</td><td>myself</td><td>sj/yhtU1h4LZPw7/Uy9IVA== </td></tr></deftable>

In the above example the digest of "harry/quidditch" is different than the digest of "hpotter/quidditch" because even though the password is the same, the username has changed. The digest is calculated with digest(username + ":" + realm + ":" + password), so if the username changes the resulting digest is different.

</s2>

<s2 title="Calculating a digest">

Of course, storing the digest password is a bit more work. When the user registers, the application needs to compute the digest to store it.


<example title="Calculating a digest using PHP"> <?php

 $username = "harry";
 $password = "quidditch";
 $realm = "resin";
 $digest = base64_encode(md5("$username:$realm:$password", true));

?> </example>

Unix users can quickly calculate a digest:

<example> echo -n "user:resin:password" | openssl dgst -md5 -binary | uuencode -m - </example>

The class <a href="javadoc|com.caucho.security.PasswordDigest|"/> can be used to calculate a digest.

<example title="Calculating a digest - Java example">

 import com.caucho.security.PasswordDigest;
 ...
 String username = ...;
 String password = ...;
 String realm = "resin";
 PasswordDigest passwordDigest = PasswordDigest();
 String digest = passwordDigest.getPasswordDigest(username, password, realm);

</example>

The realm for DatabaseAuthenticator and XmlAuthenticator defaults to "resin"; the realm can be specified during configuration:

<example title="Specifying a realm"> <web-app xmlns="http://caucho.com/ns/resin"

         xmlns:resin="urn:java:com.caucho.resin">
 <resin:DatabaseAuthenticator>
   <resin:password-digest-realm>hogwarts</resin:password-digest-realm>
   ...
 </resin:DatabaseAuthenticator>
 

</web-app> </example>

</s2>

<s2 title="Using Digest with basic authentication or a form login">

When using the form login method or the HTTP basic authentication login method, the password submitted is in cleartext. The Resin authenticator will digest the password before comparing it to the value retrieved from storage. The message is transmitted in cleartext but is stored as a digest. This method provides only half of the protection - the password is not protected in transmission (although if the form submit is being done over an <a href="ssl.xtp">SSL</a> connection it will be secure).

</s2>


<s2 title="Using HTTP digest authentication">

The HTTP protocol includes a method to indicate to the client that it should make a digest using the password. The client submits a digest to Resin instead of submitting a cleartext password. HTTP digest authentication protects the password in transmission.

When using HTTP digest, Resin will respond to the browser and ask it to calculcate a digest. The steps involved are:

  • Resin provides the client a realm and some other information
  • The client obtains a username and password (usually a dialog box with a web browser)
  • The client calculates a digest using the username, realm, pasword, and other information supplied by Resin
  • The client submits the digest to Resin
  • Resin does the same digest calculation as the client did
  • Resin compares the submitted digest and the digest it calculated. If they match, the user has been authenticated

The advantage of this method is that the cleartext password is protected in transmission, it cannot be determined from the digest that is submitted by the client to the server.

HTTP digest authentication is enabled with the <a config-tag="auth-method"/> child of the <a config-tag="login-config"/> configuration tag.

<example title="Using HTTP digest authentication"> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin">
 <resin:DigestLogin/>

</web-app> </example>

</s2>

<s2 title="Disabling the use of password-digest">

Although it is not advised, Resin's authenticators can be configured to use passwords that are not in digest form.

<example title="Disabling the use of password-digest"> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin">
 <resin:XmlAuthenticator</type>
   <resin:password-digest>none</resin:password-digest>
   
   <resin:user name="harry" password="quidditch" group="user"/>
 </resin:XmlAuthenticator>
 

</web-app>

</example>

</s2>

<s2 title="Compatibility">

Authenticators are not defined by the <a href="http://www.jcp.org/en/jsr/detail?id=154">Servlet Specification</a>, so the ability to use passwords stored as a digest depends upon the implementation of the Authenticator that the application server provides. MD5-base64 is the most common form of digest, because it is the default in <a href="#Using-HTTP-digest-authentication">HTTP digest authentication</a>.

The use of <auth-method>DIGEST<auth-method> is defined in the Servlet Specification and implemented in most application servers.

</s2> </s1>

<s1 title="Single Signon" version="Resin 3.0.0">

"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 <a href="env-tags.xtp">environment</a>. For example, to configure the XML authenticator for all web-apps in foo.com, you might configure as follows:

<example title="Single Signon for foo.com"> <resin xmlns="http://caucho.com/ns/resin"

     xmlns:resin="urn:java:com.caucho.resin">
     
 <cluster id="app-tier>
   <http port="8080"/>
   <host id="foo.com">
     <root-directory>/opt/foo.com</root-directory>
     <resin:XmlAuthenticator">
       <!-- password: quidditch -->
       <resin:user name="harry" password="uTOZTGaB6pooMDvqvl2LBu" group="user,gryffindor"/>
       <!-- password: pureblood -->
       <resin:user name="dmalfoy" password="yI2uN1l97Rv5E6mdRnDFDB" group="user,slytherin"/>
     </resin:XmlAuthenticator>
     <web-app-deploy path="webapps"/>
   </host>
 </cluster>

</resin> </example>

Any .war in the webapps directory will share the same signon for the host. You will still need to implement a <a href="webapp-tags.xtp#login-config">login-config</a> for each web-app.

The value of <a config-tag="reuse-session-id">reuse-session-id</a> must be true for single signon.


<s2 title="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 <a href="#authenticator">authenticator</a> is placed at the cluster level so that it is common to all virtual hosts. The <a href="webapp-tags.xtp#session-config">cookie-domain</a> is placed in a <a href="webapp-tags.xtp#web-app-default">web-app-default</a> at the cluster level so that it is applied as the default for all webapps in all virtual hosts.

<example title="Single Signon for gryffindor.hogwarts.com and slytherin.hogwarts.com"> <resin xmlns="http://caucho.com/ns/resin"

       xmlns:resin="urn:java:com.caucho.resin">
 <cluster id="app-tier>
   <http port="8080"/>
   <resin:XmlAuthenticator">
     <user name="Harry" password="..."/>
   </resin:XmlAuthenticator>
   <web-app-default>
     <session-config>
       <cookie-domain>.hogwarts.com</cookie-domain>
     </session-config>
   </web-app-default>


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

</resin> </example>

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.

</s2>

</s1>

<s1 title="Login">

<s2 title="BasicLogin" type="defun">

Configures HTTP basic login, which can be convenient for a quick protection of internal pages or administration when writing a form isn't necessary.

<example title="WEB-INF/resin-web.xml resin:BasicLogin"> <web-app xmlns="http://caucho.com/ns/resin"

         xmlns:resin="urn:java:com.caucho.resin">
 <resin:BasicLogin/>
 <resin:Allow url-pattern="/foo/*">
    <resin:IfUserInRole role="user"/>
 </resin:Allow>
 <resin:XmlAuthenticator>
    ...
 </resin:XmlAuthenticator>
 

</web-app> </example>

</s2>

<s2 title="FormLogin" type="defun">

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.

<deftable title="FormLogin attribute"> <tr>

 <th>attribute</th>
 <th>description</th>
 <th>default</th>

</tr> <tr>

 <td>form-login-page</td>
 <td>The page to be used to prompt the user login</td>
 <td>none</td>

</tr> <tr>

 <td>form-error-page</td>
 <td>The error page for unsuccessful login</td>
 <td>none</td>

</tr> <tr>

 <td>internal-forward</td>
 <td>Use an internal redirect on success or a sendRedirect</td>
 <td>false</td>

</tr> <tr>

 <td>form-uri-priority</td>
 <td>If true, the form's j_uri will override a stored URI</td>
 <td>false</td>

</tr> </deftable>

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.

<deftable title="j_security_check Parameters"> <tr>

 <th>Parameter</th>
 <th>Meaning</th>

</tr> <tr>

 <td>j_username</td>
 <td>The user name</td>

</tr> <tr>

 <td>j_password</td>
 <td>The password</td>

</tr> <tr>

 <td>j_uri</td>
 <td>Resin extension for the successful display page (Optional).</td>

</tr> <tr>

 <td>j_use_cookie_auth</td>
 <td>Resin extension to allow cookie login (Optional).</td>

</tr> </deftable>

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

<example title="j_security_check form"> <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> </example>

</s2>

<s2 title="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:

<example title="WEB-INF/resin-web.xml CustomLogin"> <web-app xmlns="http://caucho.com/ns/resin"

         xmlns:resin="urn:java:com.caucho.resin">
         xmlns:foo="urn:java:com.foo">
    
 <foo:CustomLogin>
   <foo:foo>bar</foo:foo>
 </foo:CustomLogin>
 <resin:XmlAuthenticator>
   ...
 </resin:XmlAuthenticator>

</web-app> </example>

</s2> </s1>

<s1 title="Authorization">

<s2 title="resin:Allow" type="defun"> <parents>web-app</parents>

Selects protected areas of the web site. Sites using authentication as an optional personalization feature will typically not use any security constraints. Sites using authentication to limit access to certain sections of the website to certain users will use security constraints.

Security constraints can also be custom classes.

<example title="Protecting all pages for logged-in users"> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin">
 <resin:IfAllow url-pattern="/*">
   <resin:IfUserInRole role="*"/>
 </resin:IfAllow>

</web-app> </example>

<deftable title="resin:Allow attributes"> <tr>

 <td>url-pattern</td>
 <td>url patterns describing the resource</td>

</tr> <tr>

 <td>http-method</td>
 <td>HTTP methods to be restricted.</td>

</tr> </deftable>

</s2>

<s2 title="resin:IfNetwork" version="Resin 4.0.0" type="defun"> <parents>security-constraint</parents>

Allow or deny requests based on the ip address of the client. ip-constraint is very useful for protecting administration resources to an internal network. It can also be useful for denying service to known problem ip's.

<example title="Admin pages allowed from 192.168.17.0/24"> <web-app xmlns="http://caucho.com/ns/resin"

       xmlns:resin="urn:java:com.caucho.resin">
 <resin:Allow url-pattern="/admin/*">
   <resin:IfAddress name="192.168.17.0/24"/>
 </resin:Allow>
 

</web-app> </example>

The /24 in the ip 192.168.17.0/24 means that the first 24 bits of the ip are matched - any ip address that begins with 192.168.17. will match. The usage of /bits is optional.

<example title="Block out known trouble makers"> <web-app xmlns="http://caucho.com/ns/resin"

         xmlns:resin="urn:java:com.caucho.resin">
 <resin:Deny>
   <resin:IfNetwork>
      <resin:value>205.11.12.3</resin:value>
      <resin:value>213.43.62.45</resin:value>
      <resin:value>123.4.45.6</resin:value>
      <resin:value>233.15.25.35</resin:value>
      <resin:value>233.14.87.12</resin:value>
   </resin:IfNetwork>
 </resin:Deny>
 

</web-app> </example>

Be careful with deny - some ISP's (like AOL) use proxies and the ip of many different users may appear to be the same ip to your server.

If only deny is used, then all ip's are allowed if they do not match a deny. If only allow is used, then an ip is denied unless it matches an allow. If both are used, then the ip must match both an allow and a deny

</s2>

<s2 title="resin:IfUserInRole" type="defun"> <parents>resin:Allow, resin:Deny</parents>

Requires that authenticated users fill the specified role. In Resin's DatabaseAuthenticator, normal users are in the "user" role. Think of a role as a group of users.

<deftable title="IfUserInRole attributes"> <tr>

 <th>attribute</th>
 <th>description</th>

</tr> <tr>

 <td>role</td>
 <td>Roles which are allowed to access the resource.</td>

</tr> </deftable>

<example title="WEB-INF/resin-web.xml Protecting webdav for webdav users"> <web-app xmlns="http://caucho.com/ns/resin"

       xmlns:resin="urn:java:com.caucho.resin">
 <resin:Allow url-pattern="/webdav/*">
   <resin:IfUserInRole role='webdav'/>
 </resin:Allow>
 

</web-app> </example>

</s2>

<s2 title="resin:IfSecure" type="defun"> <parents>resin:Allow, resin:Deny</parents>

Restricts access to secure transports, i.e. SSL.

<example title="WEB-INF/resin-web.xml"> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin"
 <resin:Allow>
   <resin:IfSecure/>
 </resin:Allow>
 

</web-app> </example>

The default behaviour is for Resin to rewrite any url that starts with "http:" by replacing the "http:" part with "https:", and then send redirect to the browser.

If the default rewriting of the host is not appropriate, you can set the <a config-tag="secure-host-name"/> for the host:

<example title="WEB-INF/resin-web.xml"> <resin xmlns="http://caucho.com/ns/resin"> <cluster id="app-tier">

 ...
 
 <host id="...">
   <secure-host-name>https://hogwarts.com</secure-host-name>
   ...

</resin> </example>

</s2>

<s2 title="constraint" version="Resin 4.0" type="defun">

Any custom class that extends <a href="javadoc:com.caucho.security.RequestPredicate">com.caucho.security.RequestPredicate</a> can be used as an <IfXXX> rule. Just create the class and instantiate it directly:

<example title="WEB-INF/resin-web.xml - custom rule "> <web-app xmlns="http://caucho.com/ns/resin"

        xmlns:resin="urn:java:com.caucho.resin"
        xmlns:foo="urn:java:com.foo"
<resin:Allow url-pattern="/safe/*"
   <foo:IfMyTest value="value"/>
</resin:Allow url-pattern="/safe/*"

</web-app> </example>

<example> package com.foo;

import javax.servlet.http.HttpServletRequest; import com.caucho.security.ServletRequestPredicate;

public class IfMyTest extends ServletRequestPredicate {

 private String _value;
 public void setValue(String value)
 {
   _value = value;
 }
 public boolean isMatch(HttpServletRequest request)
 {
   return _value.equals(request.getHeader("Foo"));
 }

} </example>

</s2>

</s1>

<s1 name="protectall" title="Protecting static files from viewing by anyone">

Sometimes it is necessary to protect files from being viewed by anyone, such as configuration files used in your code but not meant to be served to a browser.

<s2 title="Place files in WEB-INF">

Place files in WEB-INF or a subdirectory of WEB-INF. Any files in WEB-INF or it's subdirectories will automatically be protected from viewing.

</s2>

<s2 title="resin:Deny">

Use a security constraint that requires a role that nobody will ever have.

<example title="security-constraint to protect static files"> <web-app xmlns="http://caucho.com/ns/resin"

       xmlns:resin="urn:java:com.caucho.resin">
 ...
 <!-- protect all .properties files -->
 <resin:Deny url-pattern="*.properties"/>
 <!-- protect the config/ subdirectory -->
 <resin:Deny url-pattern="/config/*"/>
 ...

</web-app> </example>

</s2> </s1>

<s1 name="aboutssl" title="What SSL provides">

SSL provides two kinds of protection, encryption and server authentication.

<s2 title="Encryption">

<glossary title="public key"> A set of bytes used to encrypt data and verify signatures. The key is public because it can be made available without a loss of security. The public key can only be used for encryption; it cannot decrypt anything. A public key always has a corresponding private key. </glossary>


SSL provides encryption of the data traffic betweeen a client and a server. When the traffic is encrypted, an interception of that traffic will not reveal the contents because they have been encrypted - it will be unusable nonsense.

<glossary title="private key" type="sidebar-left"> A set of bytes used to decrypt data and generate signatures. The key is private because it must be kept secret or there will be a loss of security. The private key is used for decryption of data that has been encrypted with the corresponding public key. </glossary>

SSL uses public key cryptography. Public key cryptography is based upon a pair of keys, the public key and the private key. The public key is used to encrypt the data. Only the corresponding private key can successfully decrypt the data.

For example, when a browser connects to Resin, Resin provides the browser a public key. The browser uses the public key to encrypt the data, and Resin uses the private key to decrypt the data. For this reason, it is important that you never allow anyone access to the private key, if the private key is obtained by someone then they can use it to decrypt the data traffic.

Encryption is arguably the more important of the security meausures that SSL provides.

</s2>

<s2 title="Server Authentication">

<glossary title="certificate"> A combination of a private key, identity information (such as company name), and a signature generated by a signing authority. private key. </glossary>

SSL also provides the ability for a client to verify the identity of a server. This is used to protect against identity theft, where for example a malicious person imitates your server or redirects client traffic to a different server while pretending to be you.

<glossary title="signing authority" type="sidebar-left"> A company that is trusted to sign certificates. Browsers include certificates of signing authorities that they trust. </glossary>

Server authentication uses the signature aspect of public key cryptography. The private key is used to sign messages, and the public key is used to verify the signature. With SSL, the validity of signatures depends upon signing authorities. Signing authorites (also called certificate authorities) are companies who have generated public keys that are included with browser software. The browser knows it can trust the signing authority, and the signing authority signs your SSL certificate, putting its stamp of approval on the information in your certificate.

<glossary title="certificate authority"> Another name for signing authority. A company that is trusted to sign certificates. Browsers include certificates of signing authorities that they trust. </glossary>

For example, after you generate your public and private key, you then generate a signing request and send it to a signing authority. This signing request contains information about your identity, this identity information is confirmed by the signing authority and ultimately displayed to the user of the browser. The signing authority validates the identity information you have provided and uses their private key to sign, and then returns a certificate to you. This certificate contains the identity information and your public key, verified by the signing authority, and is provided to the browser. Since the browser has the public key of the signing authority, it can recognize the signature and know that the identity information has been provided by someone that can be trusted.


</s2>

</s1>

<s1 name="openssl" title="OpenSSL">

OpenSSL is the same SSL implementation that Apache's mod_ssl uses. Since OpenSSL uses the same certificate as Apache, you can get signed certificates using the same method as for Apache's mod_ssl or following the OpenSSL instructions.

<s2 title="Linking to the OpenSSL Libraries on Unix">

On Unix systems, Resin's libexec/libresinssl.so JNI library supports SSL using the <a href="http://www.openssl.org">OpenSSL</a> libraries. Although the ./configure script will detect many configurations, you can specify the openssl location directly:

<example> resin> ./configure --with-openssl=/usr/local/ssl </example> </s2>

<s2 title="Obtaining the OpenSSL Libraries on Windows">

On Windows systems, the resinssl.dll includes JNI code to use OpenSSL libraries (it was in resin.dll in versions before 3.0). All you need to do is to obtain an OpenSSL binary distribution and install it.

Resin on Windows 32 is compiled against the Win32 binary, you can obtain an installation package <a href="http://www.slproweb.com">http://www.slproweb.com (Shining Light Productions)</a>.

Resin on Windows 64 is compiled against a Win64 binary, you can obtain an installation package <a href="http://www.deanlee.cn?p=60&cp=1">Dean Lee: /dev/blog</a>.

Once you have run the installation package, you can copy the necessary dll libraries into $RESIN_HOME:

<example title="Copying the Windows SSL libraries into $RESIN_HOME"> C:\> cd %RESIN_HOME% C:\resin-3.0> copy "C:\Program Files\GnuWin32\bin\libssl32.dll" .\libssl32.dll C:\resin-3.0> copy "C:\Program Files\GnuWin32\bin\libeay32.dll" .\libeay32.dll </example>


</s2>

<s2 title="Preparing to use OpenSSL for making keys">

You can make a keys/ subdirectory of $RESIN_HOME to do your work from and as a place to store your generated keys.

<example title="$RESIN_HOME/keys"> unix> cd $RESIN_HOME unix> mkdir keys unix> cd keys

win> cd %RESIN_HOME% win> mkdir keys win> cd keys </example>

Using OpenSSL requires a configuration file. Unix users might find the default configuration file in /usr/ssl/openssl.cnf or /usr/share/ssl/openssl.cnf. Windows users may not have received one with their package.

Either way, it can be valuable to make your own openssl.cnf that is used just for generating the keys to use with Resin. You can use the following as a template for a file $RESIN_HOME/keys/openssl.cnf. You may want to fill in the _default values so you don't have to type them in every time.

<example title="$RESIN_HOME/keys/openssl.cnf"> [ req ]

default_bits            = 1024
distinguished_name      = req_distinguished_name

[ req_distinguished_name ]

C                      = 2 letter Country Code, for example US
C_default              =
ST                     = State or Province
ST_default             =
L                      = City
L_default              =
O                      = Organization Name
O_default              =
OU                     = Organizational Unit Name, for example 'Marketing'
OU_default             =
CN                     = your domain name, for example www.hogwarts.com
CN_default             =
emailAddress           = an email address
emailAddress_default   =

</example> </s2>

<s2 title="Creating a private key">

Create a private key for the server. You will be asked for a password - don't forget it! You will need this password anytime you want to do anything with this private key. But don't pick something you need to keep secret, you will need to put this password in the Resin configuration file.

<example title="creating the private key gryffindor.key"> unix> openssl genrsa -des3 -out gryffindor.key 1024 win> "C:\Program Files\GnuWin32\bin\openssl.exe" \

        genrsa -des3 -out gryffindor.key 1024

</example>

</s2>

<s2 title="Creating a certificate">

OpenSSL works by having a signed public key that corresponds to your private key. This signed public key is called a certificate. A certificate is what is sent to the browser.

You can create a self-signed certificate, or get a certificate that is signed by a certificate signer (CA).

<s3 title="Creating a self-signed certificate">

You can create a certificate that is self-signed, which is good for testing or for saving you money. Since it is self-signed, browsers will not recognize the signature and will pop up a warning to browser users. Other than this warning, self-signed certificates work well. The browser cannot confirm that the server is who it says it is, but the data between the browser and the client is still encrypted.

<example title="creating a self-signed certificate gryffindor.crt"> unix> openssl req -config ./openssl.cnf -new -key gryffindor.key \

       -x509 -out gryffindor.crt

win> "C:\Program Files\GnuWin32\bin\openssl.exe" req -config ./openssl.cnf \

        -new -key gryffindor.key -x509 -out gryffindor.crt

</example>

You will be asked to provide some information about the identity of your server, such as the name of your Organization etc. Common Name (CN) is your domain name, like: "www.gryffindor.com".

</s3>

<s3 title="Creating a certificate request">

To get a certificate that is signed by a CA, first you generate a certificate signing request (CSR).

<example title="creating a certificate request gryffindor.csr"> unix> openssl req -new -config ./openssl.cnf -key gryffindor.key \

     -out gryffindor.csr

win> "C:\Program Files\GnuWin32\bin\openssl.exe" req -new \

     -config ./openssl.cnf  -key gryffindor.key -out gryffindor.csr

</example>

You will be asked to provide some information about the identity of your server, such as the name of your Organization etc. Common Name (CN) is your domain name, like: "www.gryffindor.com".

Send the CSR to a certificate signer (CA). You'll use the CA's instructions for Apache because the certificates are identical. Some commercial signers include:

You'll receive a gryffindor.crt file.

Most browsers are configured to recognize the signature of signing authorities. Since they recognize the signature, they will not pop up a warning message the way they will with self-signed certificates. The browser can confirm that the server is who it says it is, and the data between the browser and the client is encrypted.

</s3> </s2>

<s2 title="resin.xml - Configuring Resin to use your private key and certificate">

The OpenSSL configuration has two tags <a config-tag="certificate-file"/> and <a config-tag="certificate-key-file"/>. These correspond exactly to mod_ssl's SSLCertificateFile and SSLCertificateKeyFile. So you can use the same certificates (and documentation) from mod_ssl for Resin.

The full set of parameters is in the port configuration.

<example title="resin.xml"> <resin xmlns="http://caucho.com/ns/resin">

 <cluster id="http-tier">
 <server id="a" address="192.168.1.12">
   <http port="443">
     <openssl>
       <certificate-file>keys/gryffindor.crt</certificate-file>
       <certificate-key-file>keys/gryffindor.key</certificate-key-file>
       <password>my-password</password>
     </openssl>
  </http>
 </server>
 ...

</resin> </example>

</s2>

<s2 title="Testing">

<s3 title="Testing with the browser">

A quick test is the following JSP.

<example> Secure? <%= request.isSecure() %> </example> </s3>

<s3 title="Using openssl to test the server">

The openssl tool can be used as a client, showing some interesting information about the conversation between the client and the server:

<example> unix$ openssl s_client -connect www.some.host:443 -prexit </example> </s3> </s2>

<s2 title="Certificate Chains">

A certificate chain is used when the signing authority is not an authority trusted by the browser. In this case, the signing authority uses a certificate which is in turn signed by a trusted authority, giving a chain of [your certificate] <--- signed by ---- [untrusted signer] <---- signed by ---- [trusted signer].

The Resin config parameter <a config-tag="certificate-chain-file"/> is used to specify a certificate chain. It is used to reference a file that is a concatenation of:

  1. your certificate file
  2. the intermediate (untrusted) certificate
  3. the root (trusted) certificate.

The certificates must be in that order, and must be in PEM format.

<s3 title="Example certificate chain for Instant SSL">

<a href="http://instantssl.com">Comodo (http://instantssl.com)</a> is a signing authority that is untrusted by most browsers. Comodo has their certificate signed by GTECyberTrust.

Comodo gives you three certificates:

  1. your_domain.crt (signed by Comodo)
  2. ComodoSecurityServicesCA.crt (signed by GTE CyberTrust)
  3. GTECyberTrustRoot.crt (universally known root)

In addition to this, you have your key, your_domain.key. The contents of the file referred to by <a config-tag="certificate-chain-file"/> is a concatenation of the three certificates, in the correct order.

<example title="Creating a certificate chain file"> $ cat your_domain.crt ComodoSecurityServicesCA.crt GTECyberTrustRoot.crt > chain.txt </example>

<example title="resin.xml using a certificate chain file"> <http port="443">

 <openssl>
   <certificate-key-file>keys/your_domain.key</certificate-key-file>
   <certificate-file>keys/your_domain.crt</certificate-file>        
   <certificate-chain-file>keys/chain.txt</certificate-chain-file>
   <password>test123</password>
 </openssl>

</http> </example>

</s3>

</s2>

</s1>


<s1 name="jsse" title="JSSE">

We recommend avoiding JSSE if possible. It is slower than using Resin's OpenSSL support and does not appear to be as stable as Apache or IIS (or Netscape/Zeus) for SSL support. In addition, JSSE is far more complicated to configure. While we've never received any problems with Resin using OpenSSL, or SSL from Apache or IIS, JSSE issues are fairly frequent.

<s2 title="Install JSSE from Sun">

This section gives a quick guide to installing a test SSL configuration using Sun's JSSE. It avoids as many complications as possible and uses Sun's keytool to create a server certificate.

Resin's SSL support is provided by Sun's <a href="http://java.sun.com/products/jsse">JSSE</a>. Because of export restrictions, patents, etc, you'll need to download the JSSE distribution from Sun or get a commercial JSSE implementation.

More complete JSSE installation instructions for JSSE are at <a href="http://java.sun.com/products/jsse/install.html">http://java.sun.com/products/jsse/install.html</a>.

  1. First download Sun's <a href="http://java.sun.com/products/jsse">JSSE</a>.
  2. Uncompress and extract the downloaded file.
  3. Install the JSSE jar files: jsse.jar, jnet.jar, and jcert.jar. You can

    either put them into the CLASSPATH or you can put them into $JAVA_HOME/jre/lib/ext. Since you will use "keytool" with the new jars, you need to make them visible to keytool. Just adding them to resin/lib is not enough.

  4. Register the JSSE provider (com.sun.net.ssl.internal.ssl.Provider).

    Modify $JAVA_HOME/jre/lib/security/java.security so it contains something like: <example> security.provider.1=sun.security.provider.Sun security.provider.2=com.sun.net.ssl.internal.ssl.Provider </example> Adding the JSSE provider allows "keytool" to create a key using the RSA algorithm.

</s2>

<s2 title="Create a test server certificate">

The server certificate is the core of SSL. It will identify your server and contain the secret key to make encryption work.

  • Sun's keytool
  • A self-signed certificate using open_ssl
  • A test certificate from Thawte
  • A production certificate from one of the certificate authorities (Verisign, Thawte, etc)

In this case, we're using Sun's keytool to generate the server certificate. Here's how:

<example> resin1.2.b2> mkdir keys resin1.2.b2> keytool -genkey -keyalg RSA -keystore keys/server.keystore Enter keystore password: changeit What is your first and last name?

 [Unknown]:  www.caucho.com

What is the name of your organizational unit?

 [Unknown]:  Resin Engineering

What is the name of your organization?

 [Unknown]:  Caucho Technology, Inc.

What is the name of your City or Locality?

 [Unknown]:  San Francisco

What is the name of your State or Province?

 [Unknown]:  California

What is the two-letter country code for this unit?

 [Unknown]:  US

Is <CN=www.caucho.com, OU=Resin Engineering,

 O="Caucho Technology, Inc.", L=San Francisco, ST=California, C=US> correct?
 [no]:  yes

Enter key password for <mykey>

       (RETURN if same as keystore password):  changeit

</example>

Currently, the key password and the keystore password must be the same.

</s2>

<s2 title="resin.xml">

The Resin SSL configuration extends the http configuration with a few new elements.

<example> <resin xmlns="http://caucho.com/ns/resin">

 <cluster id="">
   <server-default>
   
   <http port="8443">
    <jsse-ssl>
      <key-store-type>jks</key-store-type>
      <key-store-file>keys/server.keystore</key-store-file>
      <password>changeit</password>
    </jsse-ssl>
   </http>
   </server-default>
   ...
 </cluster>

</resin> </example>

</s2>

<s2 title="Testing JSSE">

With the above configuration, you can test SSL with https://localhost:8443. A quick test is the following JSP.

<example> Secure? <%= request.isSecure() %> </example>

</s2>

</s1>

</body> </document>

Personal tools