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.