In last couple of months, I received many e-mails seeking information on how exactly a converged application can be configured for authentication in SailFin. Most of them had the same set of requirements also.
  1. Require JDBC Realm
  2. Should not save password in clear text in the DB
  3. Use MD5 hashing
The simplest way to solve this problem is to use MD5 digest authentication. Then why there are many questions? Here are the obvious two.
  1. If you configure digest authentication for a web app, the browser shows the native login window, which almost all web developers doesnt like. Most of them like Form based authentication.
  2. For SIP application, how to save the MD5 hash in the DB is not that obvious to beginners. For SIP applications, the SIP clients are supposed to send the MD5 hash in the following form. A1 = unq(username-value) ":" unq(realm-value) ":" passwd.
The solution is to save the MD5 hash of the password in DB for web authentication and save the MD5 hash of A1 in the DB for SIP applications. So, make sure that your DB has two columns for saving these values. Here is the SQL I used in derby.
CREATE TABLE usertable1 (userid VARCHAR(15) NOT NULL, password varchar(32) NOT NULL, digestpwd varchar(32) NOT NULL, PRIMARY KEY(userid));
CREATE TABLE grouptable1(userid VARCHAR(15)NOT NULL, groupid VARCHAR(20) NOT NULL, PRIMARY KEY(userid));
ALTER TABLE grouptable1 ADD CONSTRAINT fk_userid FOREIGN KEY(userid) REFERENCES usertable1(userid) ON DELETE CASCADE;
If there is a web page that allow user to register, then from that page (JSP/Servlet), save the data to the DB in the correct form. Please see the example code that creates appropriate hashes.
   private String hashDigestPassword(String user, String password) throws Exception {
        String key = user + ":" + REALMNAME + ":" + password;
        return hashPassword(key);

    private String hashPassword(String password) throws Exception {
        MessageDigest md = (MessageDigest) MessageDigest.getInstance("MD5").clone();

        byte[] bytes = md.digest(password.getBytes());
        StringBuilder sb = new StringBuilder(2 * bytes.length);
        for (int i = 0; i < bytes.length; i++) {
            int low = (int) (bytes[i] & 0x0f);
            int high = (int) ((bytes[i] & 0xf0) >> 4);
        return sb.toString();
And now, create two auth-realms in SailFin. One a normal JDBC realm and the other JDBC digest realm. The first one will be used for the web applications and the second one for SIP. Here is my example asadmin commands.
$ASADMIN create-jdbc-resource --connectionpoolid DerbyPool jdbc/TestAuth
$ASADMIN create-auth-realm --classname --property digest-algorithm=MD5:encoding=\HEX:jaas-context=jdbcRealm:datasource-jndi=jdbc/TestAuth:user-table=usertable1:user-name-column=userid:password-column=password:group-table=grouptable1:group-name-column=groupid TestNormalAuthRealm
$ASADMIN create-auth-realm --classname --property digest-algorithm=MD5:encoding=HASHED:jaas-context=jdbcDigestRealm:datasource-jndi=jdbc/TestAuth:user-table=usertable1:user-name-column=userid:password-column=digestpwd:group-table=grouptable1:group-name-column=groupid TestAuthRealm
Now, we need to make sure that web deployment descriptor and sip deployment descriptors are configured with appropriate realm names. Web application can be configured to use form based authentication and SIP application can be configured to use digest authentication. Thats all. Note that HTTPS and SIPS provide additional security cover for the converged applications. SailFin implements both HTTPS and SIPS. For more information, please readVenu's blogs.
Download this zip file for the example code I have used in this blog.