Temps de lecture : 3 min.

Cet article est destiné à ceux qui ont la ‘chance’ d’avoir Tomcat 6 comme serveur pour leurs applications et qui doivent paramétrer le pool de connexions par JNDI.

Voici un petit article issu d’une demande d’un client.

Le client : C’est bien la configuration par JNDI, ça serait mieux si on ne voyait pas le mot de passe en clair 🙁 …

Moi: No problem, everything is possible (enfin je crois) …

Effectivement c’est possible. D’après la documentation, il suffit d’implémenter une classe de type ‘factory’ pour instancier les connexions avec la base de données.

Dans cet article, vous verrez comment crypter facilement un mot de passe ou autre mais aussi comment remplacer le pool de connexion DBCP  par le pool de connexion de Tomcat 7 (plus performant à  mon goût).

Tout ceci se fait en 3 étapes :

  • Codage d’une classe ‘Factory’
  • Configuration de la ressource JNDI
  • Copier les jar dans le répertoire lib de Tomcat

Le processus de cryptage ne sera pas détaillé ici.
Pour plus d’information, vous avez une classe “EncryptHelper” dans les sources (voir à la fin).

    1° La classe Factory

    Ici j’utilise le pool de connexion de Tomcat 7 :

    public class Tomcat7EncryptedFactory extends org.apache.tomcat.jdbc.pool.DataSourceFactory implements SecuredFactory{
    
    	@SuppressWarnings("rawtypes")
    	@Override
    	public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
    		Object o = super.getObjectInstance(obj, name, nameCtx, environment);
    		if (o != null && o instanceof org.apache.tomcat.jdbc.pool.DataSource) {
    			org.apache.tomcat.jdbc.pool.DataSource ds = (org.apache.tomcat.jdbc.pool.DataSource) o;
    			// recuperation du login et mot de passe cryptes
    			String cryptedUsername = ds.getUsername();
    			String cryptedPassword = ds.getDbProperties().getProperty("password");
    			// on decrypte le password
    			if (cryptedPassword != null && cryptedPassword.length() > 0) {
    				String pwd = EncryptHelper.decryptData(secretKeyPassword, cryptedPassword);
    				ds.setPassword(pwd);
    			}
    			// on decrypte le login
    			if (cryptedUsername != null && cryptedUsername.length() > 0) {
    				String username = EncryptHelper.decryptData(secretKeyUser, cryptedUsername);
    				ds.setUsername(username);
    			}
    			// on set la taille initiale avec le minimum idle
    			// on doit laisser le initialSize a 0 car il ne faut pas cree de connexion tout de suite car on a les identifiants cryptes.
    			int minIdleSize = ds.getMinIdle();
    			ds.setInitialSize(minIdleSize);
    			ds.setConnectionProperties(ds.getConnectionProperties());
    
    			// on ferme le pool deja parametre
    			ds.close();
    			// on recree le pool avec les nouveaux parametres
    			ds.createPool();
    			System.out.println("Initialisation de la datasource JNDI : OK");
    			return ds;
    		} else {
    			System.out.println("Initialisation de la datasource JNDI : KO");
    			return null;
    		}
    	}
    }
    

    Juste que la rien de difficile ^_^

    2° Configuration JNDI

    Extrait du fichier de configuration des ressources de Tomcat 6 (conf/context.xml)

    <Resource name=”jdbc/mydatabase”
        auth="Container" type="javax.sql.DataSource"
        factory="fr.cnvt.tomcat.Tomcat7EncryptedFactory"
        username="sD20tsCeFQPP3HuQV17yXw=="
        password="LoPCUiDWD47S6wIOTZWvBX7X9XTLt2vS9Sv52csoEGo="
        driverClassName="my.driver.class"
        url="my.jdbc.url"
        initialSize="0" maxActive="20" minIdle="5" maxIdle="10"
        validationQuery="SELECT 1 FROM Dual" validationQueryTimeout="300"
        maxWait="30000"
        removeAbandoned="true" removeAbandonedTimeout="600" logAbandoned="true"
        timeBetweenEvictionRunsMillis="20000"
        testWhileIdle="true"
        connectionProperties="CHARSET=utf8;" />

    Comme vous pouvez le voir, le login (username) et le mot de passe (password) sont cryptés.

    Vous pouvez avoir le même login et mot de passe (c’est bizarre comme c’est fréquent…) , les 2 chaines cryptés seront différentes (normal j’utilise 2 clés de cryptage différentes ^_^)

    3° Librairies dans Tomcat

    Dernières étapes, il suffit de copier les fichiers tomcat-datasource-factory-1.0.0.jar et tomcat-jdbc-7.0.22.jar(dans le répertoire lib du zip) dans le répertoire “lib” de Tomcat 6.

    Voila en 3 copié-collé, vous avez un pool de connexion sans mot de passe en clair ^_^

    Pour générer vos propres login et password cryptés, il suffit d’utiliser la classe EncryptHelper comme ceci:

    	@Test
    	public void generateEncryptedValues(){
    		String login = "monsupertest";
    		String password = "monsupertestaussi";
    		String cryptedLogin = EncryptHelper.encryptData(SecuredFactory.secretKeyUser, login);
    		String cryptedPassword = EncryptHelper.encryptData(SecuredFactory.secretKeyPassword, password);
    		String decryptedLogin = EncryptHelper.decryptData(SecuredFactory.secretKeyUser, cryptedLogin);
    		String decryptedPassword = EncryptHelper.decryptData(SecuredFactory.secretKeyPassword, cryptedPassword);
    		assertEquals(login, decryptedLogin);
    		assertEquals(password, decryptedPassword);
    		System.out.println("Login crypte : " + cryptedLogin);
    		System.out.println("Mot de passe crypte : " + cryptedPassword);
    	}
    

    Pour les curieux, le fichier zip contient également un pool DBCP et C3P0 qui gèrent aussi le login et mot de passe cryptés. Les clés de cryptages sont dans l’interface SecuredFactory.

    Enjoy 🙂

    Les sources sont disponibles ici