Catch Exception from Tomcat DataSourceRealm Authenticator

15 Apr, 2013 | techniek

One a recent project we used Tomcat to run a JSON WebService Layer on that transferred data to several client applications. We kept authentication simple by reverting to the Tomcat DataSourceRealm implementation. This implementation derives user account information from a simple set of tables in an underlying database. It worked fine just when we started testing the behaviour in a database down situation, it seemed that this authenticator started giving Authentication Failed on the moment that it could not reach the database. Semantically this is a correct error but we needed our clients to be able to discern between incorrect username/password and a system situation. For this, I wrote a simple override of the standard DataSourceRealm that I want to share:

package nl.plance.tomcat.plugins;

import java.security.Principal;
import java.sql.Connection;
import org.apache.catalina.realm.DataSourceRealm;

/**
 * Class that overrides the default Tomcat DataSourceRealm
 * and throws a runtime exception when no connection could be
 * fetched.
 *
 * This results in an HTTP-500 error returned to client instead
 * of an authentication failed error which is undesired in this situation.
 *
 * Use the class by setting the className attribute in the Realm definition in
 * the context.xml.
 *
 */
public class MyDataSourceRealm extends DataSourceRealm {

    @Override
    public Principal authenticate(String username, String credentials) {

        // No user or no credentials
        // Can't possibly authenticate, don't bother the database then
        if (username == null || credentials == null) {
            return null;
        }

        Connection dbConnection = null;

        // Ensure that we have an open database connection
        dbConnection = open();
        if (dbConnection == null) {
           System.out.println("Database could not be reached");
           throw new RuntimeException("Database could not be reached");
        }

        // Acquire a Principal object for this user
        Principal principal = authenticate(dbConnection, username, credentials);

        close(dbConnection);

        return principal;
    }
}

Activate it by putting it in the className attribute of the Real configuration in context.xml.

Tags:

@2021 Plance. All rights reserved.