JBoss naar Tomcat conversie

Bij de klant waar ik momenteel werk is JBoss de defacto standaard. Alle applicatie werken er op. Laat het alleen nou net niet zo lekker tegen ontwikkelen zijn…

Alle ontwikkelaars wilden graag overstappen naar Tomcat. Er waren alleen twee problemen:

  • Er is een instellingen bestand die buiten de applicatie staat en alle configuratie moet bevatten.
  • JBoss maakt gebruikt van JAAS voor beveiliging met behulp van JNDI.

Instellingen bestand
Het instellingen bestand staat in een speciale service van JBoss die de property service heet. Hier staat een variabele die verwijst naar een bestand met het volledige pad. Ik kwam er achter dat deze variabele simpelweg in de instelling van System gezet werden. Dus Tomcat opstarten met een extra instelling (-Dvariabel=value) is dan dus genoeg om binnen Tomcat dezelfde werking te krijgen.
Dit was nog het simpele probleem.

JAAS in JBoss
Ik vond de service in JBoss die de beveiliging regelde. De LoginModule die achter JAAS zit om de toegang te regelen bleek een JDBC koppeling te zijn met SHA1 encryptie. Technisch zou het dus mogelijk moeten zijn om in Tomcat een JDBC Realm op te zetten die exact hetzelfde deed.
Tomcat heeft een klein programmaatje mee geleverd in de bin directory genaamd digest (.sh of .bat). In een command prompt venster heb ik mijn eigen wachtwoord ingetoetst om te zien of de gecodeerde wachtwoorden op elkaar leken:

digest.bat -a SHA1 [wachtwoord]

Helaas dit bleek niet het geval te zijn. Nadat ik de code van JBoss had bekeken kwam ik er snel achter dat JBoss iets extra’s deed: Base 64 encoding over het resultaat van de wachtwoord na het encoderen.
Dat was dus simpel verholpen met het volgende stuk code:

package nl.sogyo.core.catalina.realm;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.apache.catalina.realm.JDBCRealm;
import org.apache.catalina.util.Base64;

public class Base64EncodingJDBCRealm extends JDBCRealm {
	
    @Override
    protected String digest(String aPassword) {

    byte bytes[] = null;
                
    try {
                
      bytes = MessageDigest.getInstance(getDigest()).digest(aPassword.getBytes());                    
    } 
    catch (NoSuchAlgorithmException e) {

      new RuntimeException("Failed to digest password", e);
    }
                                
    return new String(Base64.encode(bytes));
  }
}

Simpel doch doeltreffend. Gebruik maken van deze Realm is ook simpel. In Tomcat zet je in de context van je weg applicatie de volgende XML:

<Realm className="nl.sogyo.core.catalina.realm.Base64EncodingJDBCRealm" ... />

De rest van de instelling voor de Realm vind je in de documentatie van Tomcat 5.5.

De Base64 toevoeging
Men kan uiteraard nu denken dat Base64 encoding over een SHA1 voor extra beveiliging zorgt maar dat is niet de reden dat JBoss (volgens mij) deze extra handeling doet. De reden is volgens mij om database problemen te voorkomen. Als je SHA1 encryptie los laat over een stuk tekst dan krijg je een reeks bytes (kijk maar naar de code), Base64 encoding zorgt er voor dat het ASCII encoding wordt. Dit betekend dat het niet uitmaakt wat voor encoding de database heeft omdat ASCII in alle encodingen wel goed gaat.

In mijn opinie zou Base64 encoding niet hoeven gezien het best practice is dat je je database in UTF-8 of UNICODE encoding zou moeten aanmaken en dan zou je nooit encoding problemen kunnen krijgen!