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.