JBoss naar Tomcat conversie

 
18 december 2007

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!


Werken met ?
Kijk dan bij onze mogelijkheden voor starters en/of ervaren IT'ers.


Categorieën: Development

Tags: ,


Reacties (4)

  • Ivo Limmen schreef:

    Jaap:

    Om mijzelf terug te quoten: “De meeste ontwikkelaars maken alleen gebruik van VARCHAR en andere primitieven.”; dit is de realiteit die ik over het algemeen aantref. Ik ben het er niet mee eens maar dit is wat ik tegenkom.

    Geplaatst op 19 december 2007 om 15:41 Permalink

  • Jaap Taal schreef:

    Toch ben ik het niet met je eens dat een VARCHAR veld gebruikt kan worden om bytes op te slaan.
    Karakters zijn fundamenteel andere dingen dan bytes. Je moet dus geen byte string rechtsreeks in een karakter string willen opslaan. Het is gewoon niet hetzelfde.
    Ik verwijs hier naar de manual pages van MySQL 6.0 (niet dat MySQL perse de waardheid verteld, maar ik heb er behoorlijk veel vertrouwen in).

    Quote:
    The BINARY and VARBINARY types are similar to CHAR and VARCHAR, except that they contain binary strings rather than non-binary strings. That is, they contain byte strings rather than character strings. This means that they have no character set, and sorting and comparison are based on the numeric values of the bytes in the values.

    http://dev.mysql.com/doc/refman/6.0/en/binary-varbinary.html

    Voor databases waar er geen VARBINARY (of BLOB) bestaat, zul je dus inderdaad terug moeten vallen op base 64.

    Geplaatst op 19 december 2007 om 14:54 Permalink

  • Ivo Limmen schreef:

    Jaap: Mijn stelling is juist dat een hoop mensen denken dat Base64 een extra beveiliging is maar dat het alleen maar voor byte naar char conversie is. De meeste ontwikkelaars maken alleen gebruik van VARCHAR en andere primitieven. Als je VARCHAR gebruikt in een UNICODE or UTF-8 encoding database met een SHA-1 byte regel is dat geen probleem.

    Geplaatst op 19 december 2007 om 9:08 Permalink

  • Jaap Taal schreef:

    Volgens mij kan een base 64 encoding nooit voor veiligheid zorgen, zoals je aangeeft doen ze dit alleen maar om problemen te vermijden.
    Ik ben het echter niet met je eens dat je een de output van een SHA1 als een string ziet. Het is namelijk een collectie bytes, zoals is te zien in je voorbeeld. Je gedachtesprong naar unicode en utf-8 vind ik niet terecht aangezien we het niet over karakters maar over bytes hebben. Ik zou eerder roepen dat het gebruik van een BLOB veld kiezen.
    Volgens mij (maar hier zou ik geen harde uitspraken over durven doen) heeft zo’n beetje iedere database wel een type om binaire data op te slaan.

    Geplaatst op 19 december 2007 om 1:42 Permalink