![]() | ![]() | ![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
documentation examples changes overview quick start installation command-line configuration admin amber clustering caching database deployment ejb 3.0 embedding filters hessian hmtp ioc jsp logging messaging performance quercus/php remoting scheduled tasks security server push servlets third-party troubleshooting virtual hosting watchdog webapp xml and xslt | resin security
The following sample shows how to protect a section of a web-site with a password, using a login form. WEB-INF/resin-web.xml - Simple Password Protection <web-app xmlns="http://caucho.com/ns/resin"> <security-constraint url-pattern="/secure/*"> <auth-constraint role-name="*"/> <login uri="form:login-page=/login.jsp"/> </security-constraint> <authenticator uri="properties:password-digest=none"> <init> harry=quidditch,user </init> </authenticator> </web-app>
Since all Resin users will want to protect
the resin.conf <resin xmlns="http://caucho.com/ns/resin"> <management"> <user name="admin" password="MD5HASH=="/> ... </management> ... </resin> The password is a hash of the user name, password, and the "resin"
realm. The 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. properties: - properties authenticationWEB-INF/resin-web.xml - inline properties <web-app xmlns="http://caucho.com/ns/resin"> <authenticator uri="properties:password-digest=none"> <init> harry=quidditch,user,admin draco=mudblood,disabled,user </init> </authenticator> </web-app> WEB-INF/resin-web.xml - file property <web-app xmlns="http://caucho.com/ns/resin"> <authenticator uri="properties:path=WEB-INF/users.properties"/> </web-app> WEB-INF/users.properties harry=MD5HASH==,user,admin xml: - xml authenticationWEB-INF/resin-web.xml - inline xml <web-app xmlns="http://caucho.com/ns/resin"> <authenticator uri="properties:password-digest=none"> <init> <user name="harry" password="quidditch"/> </init> </authenticator> </web-app> WEB-INF/resin-web.xml - file xml <web-app xmlns="http://caucho.com/ns/resin"> <authenticator uri="properties:path=WEB-INF/users.xml"/> </web-app> WEB-INF/users.xml <users> <user name="harry password="MD5HASH==" roles="user,admin"/> <users> custom authenticationWEB-INF/resin-web.xml - custom <web-app xmlns="http://caucho.com/ns/resin"> <authenticator class="com.foo.MyAuthenticator"> <init> <foo>bar</foo> </init> </authenticator> </web-app> MyAuthenticator.java package com.foo; import com.caucho.server.security; public class MyAuthenticator extends AbstractPasswordAuthenticator { private PasswordUser _user; public MyAuthenticator() { _user = new PasswordUser("harry", "quidditch", new String[] { "user" }); } 192 public PasswordUser getUser(String userName) { if (userName.equals(_user.getName())) return _user; else return null; } } It's also possible to register your custom authenticatr with Resin's
uri-based configuration. You'll add a file in the
com.caucho.server.security.ServletAuthenticator foo.my=com.foo.MyAuthenticator Quick StartThe 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> login-configConfigures the login class. The web.xml configuration describes the configuration in more detail. The login can be customized by selecting the Typically a custom login would only be necessary if the application needed a custom way of extracting credentials from the request. auth-methodSelects the authentication method.
form-login-configConfigures 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.
The form itself must have the action . It must also have the parameters and . Optionally, it can also have and . gives the next page to display when login succeeds. allows Resin to send a persistent cookie to the user to make following login easier.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.
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> authenticatorSpecifies 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. XmlAuthenticatorThe 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 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.
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. JdbcAuthenticatorThe 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 option, or the JNDI by default. refers to a DataSource configured with database. The following are the attributes for the JdbcAuthenticator:
<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> LdapAuthenticatorThe LdapAuthenticator (com.caucho.server.security.LdapAuthenticator) uses jndi to contact an LDAP (or Active Directory) server for authentication purposes.
<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-envjndi-env configures properties of the ldap provider implementation.
Prior to 3.1.1, the url of the server is specified with
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> JaasAuthenticatorThe 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.
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> isUserInRoleThe 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 LoginModuleCustom 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> AuthenticationListAuthenticatorList (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'/> Digest protects passwordsDigest 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,
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. MD5 digestResin's authenticators use "MD5-base64" and a realm "resin" to digest passwords by default. indicates that the MD5 algorithm is used. is an encoding format to apply to the binary result of MD5.Some examples are:
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
Calculating a digestOf course, storing the digest password is a bit more work. When the user registers, the application needs to compute the digest to store it. Unix users can quickly calculate a digest: echo -n "user:resin:password" | openssl dgst -md5 -binary | uuencode -m - The class com.caucho.http.security.PasswordDigest can be used to calculate a digest. Calculating a digest - Java example import com.caucho.server.security.PasswordDigest; ... String username = ...; String password = ...; String realm = "resin"; PasswordDigest passwordDigest = PasswordDigest(); String digest = passwordDigest.getPasswordDigest(username, password, realm); Calculating a digest - PHP example $username = ...; $password = ...; $realm = "resin"; $passwordDigest = new Java("com.caucho.server.security.PasswordDigest"); $digest = $passwordDigest->getPasswordDigest($username, $password, $realm); The realm for JdbcAuthenticator and XmlAuthenticator defaults to "resin"; the realm can be specified during configuration: Specifying a realm <authenticator type='com.caucho.server.security.JdbcAuthenticator'> <init> <password-digest-realm>hogwarts</password-digest-realm> ... Using Digest with basic authentication or a form loginWhen 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 SSL connection it will be secure). Using HTTP digest authenticationThe 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:
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 auth-method child of the login-config configuration tag. Using HTTP digest authentication <login-config> <auth-method>DIGEST</auth-method> </login-config> Disabling the use of password-digestAlthough it is not advised, Resin's authenticators can be configured to use passwords that are not in digest form. Disabling the use of password-digest <authenticator> <type>com.caucho.server.security.XmlAuthenticator</type> <init> <password-digest>none</password-digest> <user>harry:quidditch:user</user> </init> </authenticator> CompatibilityAuthenticators are not defined by the Servlet Specification, 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 HTTP digest authentication. The use of "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 Single signon for virtual hostsThe 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. 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
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 <login-config type="test.CustomLogin"> <init> <foo>bar</bar> </init> </login-config> security-constraintchild of web-appSelects 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. Protecting all pages for logged-in users <web-app> ... <security-constraint> <web-resource-collection> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint role-name='user'/> </security-constraint> ... </web-app> web-resource-collectionchild of security-constraintSpecifies a collection of areas of the web site.
auth-constraintchild of security-constraintRequires 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.
Protecting webdav for webdav users <security-constraint> <auth-constraint role-name='webdav'/> <web-resource-collection> <url-pattern>/webdav/*</url-pattern> </web-resource-collection> </security-constraint> ip-constraintchild of security-constraintAllow 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. Admin pages allowed from 192.168.17.0/24 <security-constraint> <web-resource-collection> <url-pattern>/admin/*</url-pattern> </web-resource-collection> <ip-constraint> <allow>192.168.17.0/24</allow> </ip-constraint> </security-constraint> The Block out known trouble makers <security-constraint> <ip-constraint> <deny>205.11.12.3</deny> <deny>213.43.62.45</deny> <deny>123.4.45.6</deny> <deny>233.15.25.35</deny> <deny>233.14.87.12</deny> </ip-constraint> <web-resource-collection> <url-pattern>/*</url-pattern> </web-resource-collection> </security-constraint> 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 user-data-constraintchild of security-constraintRestricts access to secure transports, i.e. SSL.
<security-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> <web-resource-collection> <url-pattern>/*</url-pattern> </web-resource-collection> </security-constraint> 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 secure-host-name for the host: <host id='...'> <secure-host-name>https://hogwarts.com</secure-host-name> ... <host id='...'> <secure-host-name>https://hogwarts.com:8443</secure-host-name> ... constraintchild of security-constraintDefines a custom constraint. The custom constraint specifies a com.caucho.server.security.AbstractConstraint. Bean-style initialization is used to initialize the constraint. which extends... <security-constraint> <constraint resin:type="example.CustomConstraint> <init> <policy>strict</policy> </init> </constraint> <web-resource-collection url-pattern='/*'/> </security-constraint> ... 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 use response.sendError() or to return an error page. package example; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import com.caucho.server.security.*; public class CustomSecurity extends AbstractConstraint { private String foo = "false"; public void setFoo(String foo) { this.foo = foo; } public boolean needsAuthentication() return false; } 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; } } The <constraint resin:type="example.CustomSecurity"> <foo>test-value</foo> </constraint> 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. Place files in WEB-INFPlace files in or a subdirectory of . Any files in or it's subdirectories will automatically be protected from viewing.Security constraint requiring role nobodyUse a security constraint that requires a that nobody will ever have.security-constraint to protect static files <web-app> ... <!-- protect all .properties files --> <security-constraint> <web-resource-collection> <url-pattern>*.properties</url-pattern> </web-resource-collection> <auth-constraint role-name='nobody'/> </security-constraint> <!-- protect the config/ subdirectory --> <security-constraint> <web-resource-collection> <url-pattern>/config/*</url-pattern> </web-resource-collection> <auth-constraint role-name='nobody'/> </security-constraint> ... </web-app> A servlet that returns a 403 errorUse a simple servlet that returns a 403 error, which means "Forbidden". Resin provides the servlet com.caucho.servlets.ErrorStatusServlet which is useful for this: Using ErrorStatusServlet to protect static files <web-app> ... <servlet> <servlet-name>forbidden</servlet-name> <servlet-class>com.caucho.servlets.ErrorStatusServlet</servlet-class> <init> <status-code>403</status-code> </init> </servlet> <servlet-mapping url-pattern="*.properties" servlet-name="forbidden"/> <servlet-mapping url-pattern="/config/*" servlet-name="forbidden"/> ... </web-app> Or you could implement your own servlet: servlet to protect static files - WEB-INF/classes/example/servlets/Forbidden.java package example.servlets; import javax.servlet.*; import javax.servlet.http.*; import java.io.IOException; /** * Respond with a 403 error */ public class Forbidden extends GenericServlet { public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { HttpServletResponse res = (HttpServletResponse) response; res.sendError(403); } } SSL provides two kinds of protection, and .Encryption
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.
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. Server Authentication
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.
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.
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 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.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. Linking to the OpenSSL Libraries on UnixOn Unix systems, Resin's libexec/libresinssl.so JNI library supports SSL using the OpenSSL libraries. Although the ./configure script will detect many configurations, you can specify the openssl location directly: resin> ./configure --with-openssl=/usr/local/ssl Obtaining the OpenSSL Libraries on WindowsOn 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 is compiled against the GnuWin32 binary, you can obtain an installation package here. Once you have run the installation package, you can copy the necessary
dll libraries into 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 Preparing to use OpenSSL for making keysYou can make a $RESIN_HOME/keys unix> cd $RESIN_HOME unix> mkdir keys unix> cd keys win> cd %RESIN_HOME% win> mkdir keys win> cd keys Using OpenSSL requires a configuration file. Unix users might find
the default configuration file in Either way, it can be valuable to make your own
$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 = Creating a private keyCreate 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. 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 Creating a certificateOpenSSL works by having a signed public key that corresponds to your private key. This signed public key is called a . 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). Creating a self-signed certificateYou 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. 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 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". Creating a certificate requestTo get a certificate that is signed by a CA, first you generate a (CSR).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 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. resin.conf - Configuring Resin to use your private key and certificateThe OpenSSL configuration has two tags certificate-file and 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. ... <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> Certificate ChainsA The Resin config parameter certificate-chain-file is used to specify a certificate chain. It is used to reference a file that is a concatenation of:
The certificates must be in that order, and must be in PEM format. Example certificate chain for Instant SSLComodo (http://instantssl.com) is a signing authority that is untrusted by most browsers. Comodo has their certificate signed by GTECyberTrust. Comodo gives you three certificates:
In addition to this, you have your key, Creating a certificate chain file $ cat your_domain.crt ComodoSecurityServicesCA.crt GTECyberTrustRoot.crt > chain.txt resin.conf 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> 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. Install JSSE from SunThis 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 JSSE. 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 http://java.sun.com/products/jsse/install.html.
Create a test server certificateThe server certificate is the core of SSL. It will identify your server and contain the secret key to make encryption work.
In this case, we're using Sun's to generate the server certificate. Here's how:resin1.2.b2>resin1.2.b2> Enter keystore password: What is your first and last name? [Unknown]: What is the name of your organizational unit? [Unknown]: What is the name of your organization? [Unknown]: What is the name of your City or Locality? [Unknown]: What is the name of your State or Province? [Unknown]: What is the two-letter country code for this unit? [Unknown]: Is <CN=www.caucho.com, OU=Resin Engineering, O="Caucho Technology, Inc.", L=San Francisco, ST=California, C=US> correct? [no]: Enter key password for <mykey> (RETURN if same as keystore password): Currently, the key password and the keystore password must be the same. resin.confThe Resin SSL configuration extends the http configuration with a few new elements. <resin xmlns="http://caucho.com/ns/resin"> <server> <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> ... </http-server> </caucho.com> Testing JSSEWith the above configuration, you can test SSL with https://localhost:8443. A quick test is the following JSP. Secure? <%= request.isSecure() %> User Experiences with JSSEHow do I configure Resin with SSL using JSSE?Nicholas Lehuen writes: Here is a short step-by-step installation guide for SSL on Resin. The purpose : to install SSL support on Resin Requirements
JSSE setup
Keystore initialization
Keystore protectionYour private.keystore file is for the moment a copy of the cacerts keystore, which contains the CA public key certificates (very important for client HTTPS connections). We will insert your own private key in this file, thus it'll have to be password-protected, so that anyone stealing it will have difficulties in forging certificates on your behalf.
(the default password for the cacerts keystore is 'changeit') Private key generationWe'll now generate your key pair, which is composed of a private (the one which MUST remain secret !) and a public key. The point here is to use the RSA key pair generator, and NOT the default one, which is DSA. This is were the JSSE security provider is used. type the following command : M:\keys>keytool -genkey -keyalg RSA -alias myserverkeypair \ -storepass YourPasswordHere -keystore private.keystore What is your first and last name? [Unknown]: www.myserver.com What is the name of your organizational unit? [Unknown]: Foo Dept What is the name of your organization? [Unknown]: Bar What is the name of your City or Locality? [Unknown]: Paris What is the name of your State or Province? [Unknown]: France What is the two-letter country code for this unit? [Unknown]: FR Is <CN=www.myserver.com, OU=Foo Dept, O=Bar, L=Paris, ST=France, C=FR> correct? [no]: yes Enter key password for <myserverkeypair> (RETURN if same as keystore password): You MUST mention your HTTP server name as the CN of the certificate (thus the reply to 'first and last name'). Browsers would emit warnings to your users if you didn't. Any other informations are at your choice, however the process of key pair generation and attributes definitions is very strict for "real-life" cryptography, i.e. Verisign will double-check your identity, address and so on. Another important point : DON'T AFFECT A PASSWORD to your key pair. It must remain the same as the keystore, at least until Resin provides a means of configuring the key pair password. Public Key Certificate (optional)Request a public key certificate and insert the public key certificate into your keystore. For users to trust your server, you'll have to have your public key certificate (PKC) signed by a Certificate Authority (CA) (Verisign, Thawte, Certplus...). This is done by sending a certificate signature request (CSR) to the CA, coping with all the legal stuff and getting a signed PKC in return. This step is mandatory for production server, unless you have some means to convince your users that your PKC is valid without a CA signature, which is possible in intranet environment for example. However, for testing purpose, you can start by using your self-signed PKC without any CA signature. An intermediary solution is to use a test CA so that you can check that your CSR is correctly emitted, that the Certificate Chain is correctly checked, and so on. Thawte provides a test CA at the address mentioned above.
Key pair verificationIssue the following command : M:\keys>keytool -list -v -alias myserverkeypair -storepass YourPasswordHere \ -keystore private.keystore Alias name: myserverkeypair Creation date: Fri Aug 11 23:07:53 CEST 2000 Entry type: keyEntry Certificate chain length: 2 Certificate[1]: Owner: CN=www.myserver.com, OU=Foo Dept, O=Bar, L=Paris, ST=France, C=FR Issuer: CN=Thawte Test CA Root, OU=TEST, O=Thawte, ST=FOR TESTING, C=ZA Serial number: 69f12 Valid from: Fri Aug 11 23:00:07 CEST 2000 until: Mon Sep 11 23:00:07 CEST 2000 Certificate fingerprints: MD5: 41:84:55:8C:A1:85:28:DA:B0:5A:47:D6:5B:D2:ED:41 SHA1: 61:DE:DB:E6:7C:3C:AD:90:63:9B:20:E0:FF:3B:02:3A:60:EB:B4:82 Certificate[2]: Owner: CN=Thawte Test CA Root, OU=TEST, O=Thawte, ST=FOR TESTING, C=ZA Issuer: CN=Thawte Test CA Root, OU=TEST, O=Thawte, ST=FOR TESTING, C=ZA Serial number: 0 Valid from: Thu Aug 01 02:00:00 CEST 1996 until: Thu Dec 31 22:59:59 CET 2020 Certificate fingerprints: MD5: 5E:E0:0E:1D:17:B7:CA:A5:7D:36:D6:02:DF:4D:26:A4 SHA1: 39:C6:9D:27:AF:DC:EB:47:D6:33:36:6A:B2:05:F1:47:A9:B4:DA:EA As you can see the alias myserverkeypair points to a keyEntry type entry, its certificate chain has 2 certificate, the first being your own certificate, signed by the Thawte Test CA Root, and the other being the Thawte Test CA Root own. Resin configuration (resin.conf)add the support for the SunJSSE security provider : <resin xmlns="http://caucho.com/ns/resin"> <security-provider id='com.sun.net.ssl.internal.ssl.Provider'/> <!-- declare a new HTTP server on port 443 (standard port for HTTPS), - with SSL enabled --> <server> <!-- the http port --> <http port="80"/> <!-- the srun port, read by both JVM and plugin --> <cluster> <srun host='localhost' port='6802'/> </cluster> <http port=443> <jsse-ssl> <key-store-type>jks</key-store-type> <key-store-file>file://m:/keys/private.keystore</key-store-file> <password>YourPasswordHere</password> </jsse-ssl> </http> 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. The use of RMI also requires a security manager. Don't use a security manager if you're not in an ISP environment or using RMI. There's no need for it and the security manager does slow the server down somewhat. Adding a Java security manager puts each web-app into a "sandbox" where Java limits the things that can be done from code within th web-app. The security manager is enabled by adding a security-manager tag in the resin.conf. enabling security-manager in resin.conf <resin xmlns="http://caucho.com/ns/resin" xmlns:resin="http://caucho.com/ns/resin/core"> <security-manager/> ... java.policyThe security manager determines a that applies to the current virtual machine. The security manager is controlled by policy file's.The simplest way to change the policy is to change one of the default policy file's. There are two default policy files that are used by the JDK: ${java.home}/lib/security/java.policy ${user.home}/.java.policy
An additional policy file can be set using the unix$ bin/httpd.sh -Djava.security.policy=file:/path/to/java.policy win$ bin/httpd.exe -Djava.security.policy=file:/path/to/java.policy The resulting policy for the virtual machine is the union of all granted permissions in all policy files. java.policy syntaxA useful resource is Sun's documentation about security, in particular the policy permissions and policy file syntax files are useful. 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 <classpath> from the <host> and <server> contexts. 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"; };
|