Se Connecter à Oracle en JDBC Thin via Kerberos

L’authentification à une base de données Oracle via Kerberos offre deux avantages principaux :

  • Il s’agit d’un vrai Single Sign-On. une fois le ticket Kerberos récupéré, vous n’avez plus besoin de mot de passe pour vous connecter aux bases de données. En fait, si vous utilisez un domaine Windows, le ticket est automatiquement récupéré avec l’ouverture de votre session Windows et vous partagez « votre sessions » entre Windows et Oracle et cela même si vous bases de données Oracle sont sur Unix/Linux
  • L’autre avantage tient dans l’intégration à Active Directory. Si vous décidez d’utiliser des utilisateurs d’entreprise stockés dans MSAD via Enterprise User Security (EUS) et Oracle Virtual Directory, vous n’avez malgré tout pas besoin de valider le mot de passe dans celui-ci et donc vous ne modifiez rien à votre active directory (pas de .dll, pas d’extension de schéma…).

Autrement dit pour les utilisateurs d’Active Directory, cette configuration est de loin la plus confortable puisqu’elle permet, par exemple aux DBA, de s’affranchir des mots de passe Oracle sans modifier l’infrastructure Microsoft, en dehors de l’ajout d’un attribut standard krbName pour faire le lien entre les utilisateurs d’entreprise et les utilisateurs vus du distributeur de clé Kerberos. L’ensemble de la configuration est décrite dans ce précédent article intitulé « S’authentifier à Oracle à l’aide de Kerberos« .

Cet article, revient sur l’utilisation de Kerberos avec JDBC Thin, ce qui est une nouveauté d’Oracle 11g et nécessite une configuration légèrement différente…

Programme Java, JDBC Thin et Kerberos

Oracle propose un exemple assez poussé d’utilisation de Kerberos en JDBC Thin.
Il illustre notamment la configuration du client Kerberos sur Windows. Vous y découvrirez qu’il est possible, au choix, d’utiliser un ticket existant et stocké dans le cache du client ou d’entrer les noms d’utilisateurs et mots de passe pour vous reconnecter. Vous découvrirez également qu’il est possible de modifier les emplacement de krb5.conf ou du cache client. Quoiqu’il en soit, voici ci-dessous un exemple vraiment minimal :

$ cat KerberosOracleDb.java
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import java.util.Properties;

import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleDriver;
import oracle.net.ano.AnoServices;

public class KerberosOracleDb
{
String url ="jdbc:oracle:thin:@tmpdb.easyteam.fr:1521/ORCL";

public static void main(String[] arv)
{

KerberosOracleDb krbDb = new KerberosOracleDb();
try
{
System.out.println("Attempt to connect with the default user:");
krbDb.testDB();
}
catch (Exception e)
{
e.printStackTrace();
}
}

void testDB() throws Exception
{
OracleDriver driver = new OracleDriver();
Properties prop = new Properties();

prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_SERVICES,
"("+AnoServices.AUTHENTICATION_KERBEROS5+")");
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5_MUTUAL,
"true");

Connection conn = driver.connect(url,prop);
String auth = ((OracleConnection)conn).getAuthenticationAdaptorName();
System.out.println("Authentication adaptor is:"+auth);
displayCurrentSchema(conn);
conn.close();
}

void displayCurrentSchema(Connection conn) throws SQLException
{
Statement stmt = null;
try
{
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select user from dual");
while(rs.next())
System.out.println("Current Schema is: "+rs.getString(1));
rs.close();
}
finally
{
if(stmt != null)
stmt.close();
}
}
}

Vous voyez qu’il est fait référence à la classe oracle.net.ano.AnoServices uniquement pour définir le type de connexion Kerberos. En fait, il s’agit de la valeur KERBEROS5 pour l’instant ; oracle propose cette variable pour les évolutions. En dehors de cette classe, seules changent ensuite les propriétés de la connexion pour utiliser Kerberos.

Par ailleurs, il est possible de changer l’emplacement du fichier de configuration de Kerberos. L’emplacement par défaut pour le JDK est dans le répertoire $JAVA_HOME/jre/lib/security. Vous copierez donc simplement le fichier à cet endroit pour ne pas avoir à le mettre dans votre configuration. Par ailleurs, vous devrez également avoir un client Kerberos installé et charger un TGT (ticket to get tickets) à l’aide des commandes associées. Voilà ce que ça donne sur un client Linux :

kinit scott
Password for scott@ARKZOYD.COM:

klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: scott@ARKZOYD.COM

Valid starting
Expires           Service principal
30/11/2012 17:12  01/12/2012 17:12  krbtgt/ARKZOYD.COM@ARKZOYD.COM

Vous compilerez la classe Java comme ceci :

export CLASSPATH=$ORACLE_HOME/jdbc/lib/ojdbc6.jar:.
javac KerberosOracleDb.java

Vous pourrez ensuite vous connecter à la base de données en lançant votre programme Java qui s’appuie sur le contenu de votre cache Kerberos :

java KerberosOracleDb
Attempt to connect with the default user:
Authentication adaptor is:KERBEROS5
Current Schema is: SCOTT

Si vous n’avez pas de ticket, votre client ne se connecte pas :

kdestroy -A

klist
klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_1000)

java KerberosOracleDb
Attempt to connect with the default user:
java.sql.SQLRecoverableException: IO Error: The service in process is not supported. Unable to obtain Princpal Name for authentication
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:475)
at oracle.jdbc.driver.PhysicalConnection.(PhysicalConnection.java:552)
at oracle.jdbc.driver.T4CConnection.(T4CConnection.java:253)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:526)
at KerberosOracleDb.testDB(KerberosOracleDb.java:41)
at KerberosOracleDb.main(KerberosOracleDb.java:23)
Caused by: oracle.net.ns.NetException: The service in process is not supported. Unable to obtain Princpal Name for authentication
at oracle.net.ano.AuthenticationService.i(Unknown Source)
at oracle.net.ano.AuthenticationService.h(Unknown Source)
at oracle.net.ano.Ano.negotiation(Unknown Source)
at oracle.net.ns.NSProtocol.connect(NSProtocol.java:439)
at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1126)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:337)
... 6 more
Caused by: javax.security.auth.login.LoginException: Unable to obtain Princpal Name for authentication
at com.sun.secur ity.auth.module.Krb5LoginModule.promptForName(Krb5LoginModule.java:733)
at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:629)
at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:542)
... 12 more

Note:
Il est important que les horloges de l’ensemble des systèmes connectés soient bien synchronisés ou à défaut, vous risquez de rencontrer plusieurs erreurs de type ORA-12631, ORA-12638 ou ORA-12641. Pour plus d’informations, regardez le paramètre SQLNET.KERBEROS5_CLOCKSKEW.

Kerberos et SQL*Developer

SQL*Developer supporte Kerberos nativement, au moins dans les dernières versions. Pour configurer la plateforme, vérifiez avec la commande klist de votre client l’emplacement du fichier de cache et modifiez l’écran de paramètre « Tools | Preferences > Database | Advanced » pour préciser l’emplacement du fichier de configuration ainsi que celui du fichier de cache comme ci-dessous :

Une fois la configuration réalisée, vous pouvez utiliser le ticket kerberos chargé dans le cache pour vous connecter à une base de données et ainsi utiliser la connexion existance à condition de sélectionner la case à cocher « Kerberos Authentication ». Comme vous le voyez le test de connexion s’effectue avec succès.

Note:
Si vous n’avez pas chargé de ticket sur votre client Kerberos, vous pouvez malgré tout vous connecter en Kerberos depuis SQL*Developer en saisissant les nom d’utilisateur et mot de passe de la connexion au serveur Kerberos. Evidemment, cela suppose malgré tout que la configuration au serveur soit correcte, soit dans le menu « Tools | Preferences > Database | Advanced », soit dans le répertoire $JAVA_HOME/jre/lib/security.

Vous voilà capable de vous appuyer sur votre référentiel de sécurité Windows, que vous ayez des bases de données Unix/Linux ou des clients Linux ou Mac. Enjoy…