<s1 title="Security Configuration">

<summarylist/>

<s2 title='Overview'>

<p>Security in Resin consists of four separate functions:</p>

<ul>
<li><a href="#authentication">Authentication</a>: Who is trying to use the resource?
<ul>
<li><a href="#login-config">login-config</a>: How the client sends the user and password.
<li><a href="#authenticator">authenticator</a>: How the server checks the user and password to authenticate a user.
</ul>
<li><a href="#authorization">Authorization</a>: Is the client allowed to use the resource?
<li><a href="#encryption">Encryption</a> (SSL): Protecting data from prying eyes.
<li><a href="#security-manager">Security Manager</a> (for ISPs only) :
Protecting users from each other.
</ul>

<p>By using Resin's login support, applications can add security
without writing an entire authentication library.  If the predefined
authentication methods, XML and database user lookup, are inadequate,
Resin provides an API to write custom authentication code.</p>

<p>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.</p>

<example title="Using the XmlAuthenticator">
&lt;web-app>
&lt;login-config auth-method='basic'>
  &lt;authenticator>
    &lt;class-name>com.caucho.http.security.XmlAuthenticator&lt;/class-name>
    &lt;init-param user='Harry Potter:quidditch:user'/>
  &lt;/authenticator>
&lt;/login-config>
&lt;security-constraint url-pattern='/users-only/*' role-name='user'/>
&lt;/web-app>
</example>

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

</s2>

<s2 name='authentication' title='Authentication'>

<defun title='login-config'>

</defun>

<defun title='auth-method'>
<p>Selects the authentication method.</p>

<deftable title="auth-method values">
<tr><th>auth-method<th>Meaning
<tr><td>basic<td>HTTP Basic authentication
<tr><td>digest<td>HTTP Digest authentication
<tr><td>form<td>Form-based authentication
</deftable>

</defun>

<defun title='form-login-config'>
<p>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.</p>

<deftable>
<tr><td>form-login-page<td>The page to be used to prompt the user login<td>none
<tr><td>form-error-page<td>The error page for unsuccessful login<td>none
<tr><td>internal-forward<td>Use an internal redirect on success or a sendRedirect<td>false
<tr><td>form-uri-priority<td>If true, the form's j_uri will override a stored URI<td>false
</deftable>

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

<p><var/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.
</p>

<deftable title="j_security_check Parameters">
<tr><th>Parameter<th>Meaning)
<tr><td>j_username<td>The user name
<tr><td>j_password<td>The password
<tr><td>j_uri<td>Resin extension for the successful display
page (Optional).
<tr><td>j_use_cookie_auth<td>Resin extension to allow cookie
login (Optional).
</deftable>

<p>The following is an example of a servlet-standard login page:</p>

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

</defun>

<defun title='authenticator' version='Resin 1.1'>
<p>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.</p>

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

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

<s3 title='XmlAuthenticator' version='Resin 2.0.4'>
<p>The XmlAuthenticator (com.caucho.http.security.XmlAuthenticator),
stores the authentication in either an xml file or in the configuration
itself.</p>

<p>When configuring the XmlAuthenticator in the resin.conf
(or web.xml), each <var/init-param user/> adds a new configured
user.  The value contains the username, password, and the
roles the user plays.</p>

<example title='XmlAuthenticator in resin.conf'>
&lt;authenticator>
  &lt;class-name>com.caucho.http.security.XmlAuthenticator&lt;/class-name>
  &lt;init-param user='Harry Potter:quidditch:user,gryffindor'/>
  &lt;init-param user='Draco Malfoy:pureblood:user,slytherin'/>
&lt;/authenticator>
</example>

<p>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.</p>

<deftable>
<tr><th>attribute<th>meaning
<tr><td>user<td>specifies an allowed user.  May be repeated.
<tr><td>password-digest<td>selects the signature method to protect
the password
<tr><td>path<td>specifies a path to an XML file containing the users and passwords.
<tr><td>logout-on-session-timeout<td>If true, the user will be logged out when the session times out<td>true
</deftable>

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

<example title='password.xml'>
&lt;authenticator>
  &lt;user name='Harry Potter' password='quidditch' role='gryffindor'/>
  &lt;user name='Draco Malfoy' password='pureblood' role='slytherin'/>
&lt;/authenticator>
</example>

<p>Sites should use password-digest to protect the passwords.</p>

</s3>

<s3 title='JdbcAuthenticator' version='Resin 2.0'>
<p>The JdbcAuthenticator (com.caucho.http.security.JdbcAuthenticator),
asks a backend database for the password matching the user's name.
It uses the DataSource specified by the <var/pool-name/> option, or
the JNDI <var/java:comp/env/jdbc/db-pool/> by default.
<var/pool-name/> refers to a DataSource configured with
<a href="app-config.xtp#resource-ref">resource-ref</a>.</p>

<p>The following are the attributes for the JdbcAuthenticator:</p>

<deftable>
<tr><th>attribute<th>meaning
<tr><td>pool-name<td>The database pool.  Looks in the application
attributes first, then in the global database pools.
<tr><td>password-query<td>A SQL query to get the user's password.  The
default query is given below.
<tr><td>cookie-auth-query<td>A SQL query to authenticate the user by a
persistent cookie.
<tr><td>cookie-auth-update<td>A SQL update to match
a persistent cookie to a user.
<tr><td>role-query<td>A SQL query to determine the user's role.  By
default, all users are in role "user", but no others.
<tr><td>password-digest<td>Specifies the digest algorithm and format (Resin 2.0.4)
<tr><td>logout-on-session-timeout<td>If true, the user will be logged out when the session times out (Resin 2.0.6)<td>true
</deftable>

<example>
&lt;!-- Resin-specific JdbcAuthenticator -->
&lt;authenticator id='com.caucho.http.security.JdbcAuthenticator'>
  &lt;pool-name>test&lt;/pool-name>
  &lt;password-query>
    SELECT password FROM LOGIN WHERE username=?
  &lt;/password-query>
  &lt;cookie-auth-query>
    SELECT username FROM LOGIN WHERE cookie=?
  &lt;/cookie-auth-query>
  &lt;cookie-auth-update>
    UPDATE LOGIN SET cookie=? WHERE username=?
  &lt;/cookie-auth-update>
  &lt;role-query>
    SELECT role FROM LOGIN WHERE username=?
  &lt;/role-query>
&lt;/authenticator>
</example>

</s3>

<s3 title='PasswordDigest' version='Resin 2.0.4'>

<p>Resin 2.0.4 adds the capability to store 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.</p>

<p>Setting password-digest of any authenticator
extending 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.</p>

<p>The authenticator will create a digest of the username and password.
Since that digest is a byte array, it is then converted to a string.</p>
<def>
MD5(<var/username/>:<var/password/>)
</def>

<example title='Using password-digest with XmlAuthenticator'>
&lt;authenticator>
  &lt;class-name>com.caucho.http.security.XmlAuthenticator&lt;/class-name>
  &lt;init-param password-digest='MD5-base64'/>
  &lt;init-param user='harry:Syvian7bcPDKI261QvH9Cw:user'/>
&lt;/authenticator>
</example>

<p>Of course, storing the digest password take a bit more work.  When
the user registers, the application needs to compute the
digest to store it.  You can use the PasswordDigest class to do that.</p>

<example>
import com.caucho.http.security.PasswordDigest;

...
PasswordDigest digest = new PasswordDigest();
digest.setAlgorithm("MD5");
digest.setFormat("base64");

String password = digest.getPasswordDigest("harry", "quidditch");
</example>

</s3>

</s2>

<s2 name='authorization' title='Authorization (security-constraint)'>

<s3 title='security-constraint'>
<p>Selects protected areas of the web site.  Sites using
authentication as an optional personalization feature will typically
not use any security constraints.</p>

<p>Security constraints can also be custom classes.</p>

<example title='Protecting all pages for logged-in users'>
&lt;security-constraint>
  &lt;web-resource-collection>
    &lt;url-pattern>/*&lt;/url-pattern>
  &lt;/web-resource-collection>
  &lt;auth-constraint role-name='user'/>
&lt;/security-constraint>
</example>
</s3>

<s3 title='web-resource-collection'>
<p>Specifies a collection os areas of the web site.</p>

<deftable>
<tr><td>url-pattern<td>url patterns describing the resource
<tr><td>method<td>HTTP methods to be restricted.
</deftable>
</s3>

<s3 title='auth-constraint'>
<p>Requires that authenticated users fill the specified role.
In Resin's JdbcAuthenticator, normal users are in the "user" role.
Think of a role as a group of users.</p>

<deftable>
<tr><td>role-name<td>Roles which are allowed to access the resource.
</deftable>

<example title='Protecting webdav for webdav users'>
&lt;security-constraint>
  &lt;auth-constraint role-name='webdav'/>

  &lt;web-resource-collection>
    &lt;url-pattern>/webdav/*&lt;/url-pattern>
  &lt;/web-resource-collection>
&lt;/security-constraint>
</example>

</s3>

<s3 title='ip-constraint' version='2.0.6'>
<p>Requires that the remote address is in an IP network.
ip-constraint is very useful for protecting administration resources
to an internal network.</p>

<example title='Admin pages allowed in 192.168.17.0/24'>
&lt;security-constraint>
  &lt;ip-constraint>192.168.17.0/24&lt;/ip-constraint>

  &lt;web-resource-collection>
    &lt;url-pattern>/admin/*&lt;/url-pattern>
  &lt;/web-resource-collection>
&lt;/security-constraint>
</example>

</s3>

<s3 title='user-data-constraint'>
<p>Restricts access to secure transports, i.e. SSL.</p>

<deftable>
<tr><td>transport-guarantee<td>Required transport properties.  NONE,
INTEGRAL, and CONFIDENTIAL are allowed values.
</deftable>

<example>
&lt;security-constraint>
  &lt;user-data-constraint>
    &lt;transport-guarantee>CONFIDENTIAL&lt;/transport-guarantee>
  &lt;/user-data-constraint>

  &lt;web-resource-collection>
    &lt;url-pattern>/*&lt;/url-pattern>
  &lt;/web-resource-collection>
&lt;/security-constraint>
</example>

</s3>

<s3 title='transport-guarantee'>
<p>Restricts access to secure transports, i.e. SSL.</p>
</s3>

<s3 title='constraint' version='Resin 2.0.1'>
<p>Defines a custom constraint.  The custom constraint specifies
a <var/&lt;class-name>/> which extends
com.caucho.http.security.AbstractConstraint.  Any <var/init-param/>
elements use Bean introspection to initialize the constraint.</p>

<example>
...
&lt;security-constraint>
  &lt;constraint>
    &lt;class-name>qa.CustomSecurity&lt;/class-name>
    &lt;init-param foo='ok'/>
  &lt;/constraint>
  &lt;web-resource-collection url-pattern='/*'/>
&lt;/security-constraint>
...
</example>

</s3>

<s3 title='Custom Security Constraints'>

<p>Any custom security constraint is checked after any authentication (login)
but before any filters or servlets are applied.  The security constraint will
return true if the request is allowed and false if it's forbidden.  If the
request is forbidden, it's the constraint's responsibility to return an
error page.</p>

<example>
package qa;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.caucho.http.security.*;

public class CustomSecurity extends AbstractConstraint {
  private String foo = "false";

  public void setFoo(String foo)
  {
    this.foo = foo;
  }

  public boolean isAuthorized(HttpServletRequest request,
                              HttpServletResponse response,
                              ServletContext application)
    throws ServletException, IOException
  {
    if (foo.equals(request.getParameter("test")))
      return true;

    response.sendError(response.SC_FORBIDDEN);

    return false;
  }
}
</example>

</s3>

</s2>

<s2 name="encryption" title="Encryption (SSL)">

<s3 title="OpenSSL">

<p>The easiest way to add SSL support is to compile the JNI
libraries and use OpenSSL
(not available on Windows.)  OpenSSL is the same SSL implementation
that Apache's mod_ssl uses.</p>

<p>The OpenSSL configuration has two tags &lt;certificate-file> and
&lt;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.
</p>

<p>The full set of parameters is in the <a href="port-config.xtp#ssl">port configuration.</a>

<ol>
<li>Create a private key for the server:
<example>
unix> openssl genrsa -des3 -out gryffindor.key 1024
</example>
<li>Create a request for the the certificate to be signed:
<example>
unix> openssl req -new -key gryffindor.key -out gryffindor.csr
</example>
<li>Send the CSR to a certificate signer (CA).  You'll use the
instructions for Apache because the certificates are identical.
Some commercial signers include:
<ul>
<li><a href="http://digitalid.verisign.com/server/apacheNotice.htm">Verisign</a>
<li><a href="http://www.thawte.com/certs/server/request.html">Thawte
Consulting</a>
</ul>
<li>You'll receive a <em>gryffindor.crt</em> file.
<li>Configure Resin to use the files:
<example>
...
&lt;http port='443'>
  &lt;ssl/>
  &lt;certificate-file>/opt/ssl/keys/gryffindor.crt&lt;/certificate-file>
  &lt;certificate-key-file>/opt/ssl/keys/gryffindor.key&lt;/certificate-key-file>
  &lt;key-store-password>password&lt;/key-store-password>
&lt;/http>
</example>
</ol>

</s3>

</s2>

<s2 name="security-manager" title="Security Manager">

<p>In ISP environments, it's important that each user have 
restricted permissions to use the server.  Normally, the
web server will be run as a non-root user so the users can't
read system files, but that user will still have read access.</p>

<p>Don't use a security manager if you're not in an ISP environment.
There's no need for it and the security manager does slow the server
down somewhat.</p>

<p>Adding a Java security manager puts each web-app into a
"sandbox" where Java limits their abilities.</p>

<p>The security manager is enabled by adding a <a
href="resin-config.xtp">security-manager</a> tag in the resin.conf.</p>

<p>Sun's documentation is available at
<a href="http://java.sun.com/j2se/1.4/docs/guide/security/index.html">
http://java.sun.com/j2se/1.4/docs/guide/security/index.html</a>.
In particular, the <a href="http://java.sun.com/j2se/1.4/docs/guide/security/permissions.html">policy
permissions</a> and <a
href="http://java.sun.com/j2se/1.4/docs/guide/security/PolicyFiles.html">policy
file syntax</a> files are useful.</p>

<p>Each web-app automatically has permissions to read, write and
delete any file under the web-app's directory, including WEB-INF.  It
also has read permission for the classpath, including &lt;classpath>
from the &lt;host> and &lt;http-server> contexts.</p>

<example title="sample java.policy">
#
# Permissions allowed for everyone.
#
grant {
  permission java.util.PropertyPermission "*", "read";
  permission java.lang.RuntimePermission "accessClassInPackage.*";
  permission java.net.SocketPermission "mysql.myhost.com:3306" "connect";
  permission java.io.FilePermission "/opt/resin/xsl/*", "read";
};

#
# Give the system and Resin classes all permissions
#
grant codeBase "file:${resin.home}/lib/-" {
	permission java.security.AllPermission;
};

grant codeBase "file:${java.home}/lib/-" {
	permission java.security.AllPermission;
};

grant codeBase "file:${java.home}/jre/lib/-" {
	permission java.security.AllPermission;
};

#
# Give a specific web-app additional permissions.
#
grant codeBase "file:/opt/web/webapps/ejb/WEB-INF/-" {
	permission java.io.FilePermission "/opt/web/doc/*", "read";
};
</example>

</s2>

</s1>
