Authentification Kerberos avec Apache dans un environnement Active Directory multi-domaine

Le contexte

Parfois les gens sont fous ! Ils installent des architectures informatiques avec du Microsoft partout : des postes de travail sous Windows, pleins de contrôleurs de domaine et pleins d’annuaires Active Directory. Et puis régulièrement MS vient les voir en leurs présentant la facture et ils perdent un bras. Comme ils veulent quand même continuer à manger du chocolat, ils décident (ce qui est déjà pas mal) d’ouvrir leur SI à d’autres technologies. Comme ça la prochaine fois qu’un soldat de Bill viendra les voir, ils pourront le menacer (un peu) de ne plus utiliser ses produits et ainsi faire baisser la douloureuse.

La prochaine application sera donc totalement faite avec des briques logicielles libres, et de plus au format Web tant qu’à faire. L’utilisateur devra se connecter à l’application via son navigateur en utilisant l’authentification intégrée de Windows.

Nous, on arrive et on est content car on propose d’utiliser les logiciels suivants :

  • Linux CentOS 5.6
  • Samba 3.5.4
  • Apache 2.2.3
  • Mod_auth_kerb : 5.1
  • Kerberos 1.6.1
  • Php 5.1

Et tout ça dans l’environnement qui suit :

  • OS des postes de travail : Windows XP et 7
  • Navigateur web : IE9 et Firefox 4
  • KDC : Windows 2003/2008 R2

Un petit schéma pour illustrer l’architecture Active Directory à considérer :

Schéma architecture Active Directory

1er Schéma d'architecture

Et un petit 2ème :

Schéma architecture 2

2ème schéma architecture

Règles de nommage utilisées dans ce tutoriel

  • Serveur Linux Apache : serveurA
  • Serveur KDC 2003 dom1.maboite.fr : serveurKDC1
  • Serveur KDC 2008 dom1.maboite.fr : serveurKDC2
  • Serveur KDC 2003 dom2.maboite.fr : serveurKDC3

Installation

Une fois la distribution CentOS préparée dans une version de base, il faut installer les packages nécessaires :

# yum update
# yum install krb5-workstation
# yum install samba3x samba3x-client
# yum install httpd
# yum install mod_auth_kerb
# yum install ntp
# yum install php php-ldap

Configuration

Date et heure

Notre serveur ne doit pas être trop décalé (< 10 mn) avec le DC du domaine DOM1.

Modifiez le fichier /etc/ntp.conf pour que le serveur se synchronise avec un serveur de temps, puis taper les commandes suivantes :

# service ntpd stop
# ntpdate @SERVEUR_de_TEMPS
# service ntpd start

Fichier HOSTS

Le fichier /etc/hosts doit être correctement renseigner pour pouvoir joindre un domaine Active Directory :

127.0.0.1           serveurA.maboite.fr           serveurA

KERBEROS

Éditez le fichier /etc/krb5.conf et adaptez ce qui suit :

[libdefaults]
  default_realm = DOM1.MABOITE.FR
  default_keytab_name = FILE:/etc/krb5.keytab
  kdc_timesync = 1
  ccache_type = 4
  forwardable = true
  proxiable = true
  fcc-mit-ticketflags = true

[realms]
  DOM1.MABOITE.FR = {
    kdc = @IP serveurKDC1
    kdc = @IP serveur KDC2
    admin_server = @IP serveurKDC1
    admin_server = @IP serveurKDC2
 }

[domain_realm]
  MONWORKGROUP = DOM1.MABOITE.FR
  .dom1.maboite.fr = DOM1.MABOITE.FR

[appdefaults]
  kinit = {
  renewable = true
  fowardable = true
  }

Créer ensuite un fichier /etc/krb5.keytab :

# touch /etc/krb5.keytab
# chmod 640 /etc/krb5.keytab
# chgrp apache /etc/krb5.keytab

SAMBA

Voici un extrait du fichier de configuration /etc/samba/smb.conf présentant les paramètres nécessaires :

[global]
 dedicated keytab file = /etc/krb5.keytab
 kerberos method = secrets and keytab
 security = ADS
 server string = SERVEURA
 realm = DOM1.MABOITE.FR
 workgroup = MONWORKGROUP
 password server = *

 winbind offline logon = true
 winbind refresh tickets = true
 winbind cache time = 3600
 winbind use default domain = no
 preferred master = no
 domain master = No

Puis nous allons joindre le serveur Linux au domaine 1 :

# /etc/init.d/smb stop
# /etc/init.d/nmb stop
# /etc/init.d/winbind stop
# net cache flush
# kinit compte_admin_dom1
# net ads join -U compte_admin_dom1
Enter compte_admin_dom1's password:

La réponse de la dernière commande indiquant que l’opération s’est bien déroulée doit être :

Using short domain name -- MONWORKGROUP
Joined 'SERVEURA' to realm 'dom1.maboite.fr'

Pour vérifier :

# net ads testjoin
Join is OK

Puis on redémarre SAMBA :

# /etc/init.d/smb start
# /etc/init.d/nmb start
# /etc/init.d/winbind start

KEYTAB

Le serveur Web a correctement joint le domaine AD, nous allons maintenant renseigner le fichier /etc/krb5.keytab pour qu’il soit utilisé par Apache.

# net ads keytab add HTTP -U compte_admin_dom1
Processing principals to add...
Enter compte_admin_dom1's password:

Vérifions que le fichier /etc/krb5.keytab est bien renseigné :

# ktutil
ktutil:  rkt /etc/krb5.keytab
ktutil:  l
slot KVNO Principal
---- ---- ---------------------------------------------------------------------
1   28 HTTP/serveurA.maboite.fr@DOM1.MABOITE.FR
2   28 HTTP/serveurA.maboite.fr@DOM1.MABOITE.FR
3   28 HTTP/serveurA.maboite.fr@DOM1.MABOITE.FR
4   28         HTTP/serveurA@DOM1.MABOITE.FR
5   28         HTTP/serveurA@DOM1.MABOITE.FR
6   28         HTTP/serveurA@DOM1.MABOITE.FR

APACHE

Éditons maintenant le fichier /etc/httpd/conf.d/auth_kerb.conf :

#
# Sample configuration: Kerberos authentication must only be
# used over SSL to prevent replay attacks.  The keytab file
# configured must be readable only by the "apache" user, and
# must contain service keys for "HTTP/www.example.com", where
# "www.example.com" is the FQDN of this server.
#

<Location /logon>
  AuthType Kerberos
  AuthName "Kerberos Login"
  KrbMethodNegotiate On
  KrbMethodK5Passwd On
  KrbAuthRealms DOM1.MABOITE.FR DOM2.MABOITE.FR
  Krb5KeyTab /etc/krb5.keytab
  KrbSaveCredentials On
  KrbServiceName HTTP
  require valid-user
</Location>

Et on redémarre Apache :

# /etc/init.d/httpd restart

PHP et LDAP

Le fichier PHP suivant est donné à titre d’exemple. Nous afficherons les variables PHP pour vérifier que l’authentification se passe bien, puis nous tenterons de récupérer sur l’utilisateur quelques informations contenues dans l’AD (prénom, nom, mail, …).

Créons maintenant un fichier php /var/www/html/logon/index.php dans lequel nous allons mettre le code suivant :

SUPER ça marche !!<br>

<?php
    foreach($_SERVER as $key_name => $key_value){
      print $key_name . " = " . $key_value . "<br>";
    }
    echo "<br />";

// Info AD DOM1
    $ldaphostDOM1 = "serveurKDC1";  // notre serveur AD du DOM1
    $ldapportDOM1 = 389;            // port
// Info AD DOM2
    $ldaphostDOM1 = "serveurKDC3";  // notre serveur AD du DOM2
    $ldapportDOM1 = 389;            // port
// [...] pareil pour les autres domaines

// User DN DOM1
    $ldaprdnDOM1  = 'CN=LDAP, OU=Comptes techniques, OU=Dom1, DC=dom1, DC=maboite, DC=fr';
    $ldappassDOM1 = 'motdepasse';           // Mot de passe associé
// User DN DOM2
    $ldaprdnDOM2  = 'CN=LDAP, OU=Comptes techniques, OU=Dom2, DC=dom2, DC=maboite, DC=fr';
    $ldappassDOM2 = 'motdepasse';           // Mot de passe associé
// [...] pareil pour les autres domaines

// DN utilisateurs DOM1
   $dnDOM1 = "OU=Comptes Utilisateurs,OU=dom1, DC=Dom1, DC=maboite, DC=fr"
// DN utilisateurs DOM2
   $dnDOM2 = "OU=Comptes Utilisateurs,OU=dom2, DC=Dom2, DC=maboite, DC=fr"
// [...] pareil pour les autres domaines

// $person est le nom de l'utilisateur et $domain est le REALM
   $tab = explode('@',$_SERVER['REMOTE_USER']);
   $person = $tab[0];
   $domain = $tab[1];

   switch ($domain){
         case "DOM1.MABOITE.FR":
           $ldaphost = $ldaphostDOM1;
           $ldapport = $ldapportDOM1;
           $ldaprdn = $ldaprdnDOM1;
           $ldappass = $ldappassDOM1;
           $dn = $dnDOM1;
           break;

         case "DOM2.MABOITE.FR":
           $ldaphost = $ldaphostDOM2;
           $ldapport = $ldapportDOM2;
           $ldaprdn = $ldaprdnDOM2;
           $ldappass = $ldappassDOM2;
           $dn = $dnDOM2,
           break;

         // case [...] pareil pour les autres domaines
         default:
             die( "Domaine utilisateur inconnu : $domain" );
     }

// Connecting to LDAP
    $ldapconn = ldap_connect( $ldaphost, $ldapport )
     or die( "Impossible de se connecter au serveur LDAP " );

    if ($ldapconn) {
//Connexion au serveur LDAP
     $ldapbind = ldap_bind($ldapconn, $ldaprdn, $ldappass);
// Identification
     if ($ldapbind) {
       echo "Connexion LDAP reussie<br>";
       $filter = "(sAMAccountName=$person)";
       $justthese = array( "cn", "ou", "sn", "givenname", "mail", "memberOf");
       $sr=ldap_search($ldapconn, $dn, $filter, $justthese);
       $info = ldap_get_entries($ldapconn, $sr);
       echo $info["count"]." entrees trouvees.\\n";

       for ($i=0; $i<$info["count"]; $i++) {
         echo 'dn est : ' . $info[$i]["dn"] . '<br />';
         echo 'premiere entree cn : ' . $info[$i]["cn"][0] . '<br />';
         echo 'prenom : ' . $info[$i]["givenname"][0] . '<br />';
         echo 'nom : ' . $info[$i]["sn"][0] . '<br />';
         echo 'premier email : ' . $info[$i]["mail"][0] . '<br />';
         $taillememberof = sizeof($info[$i]["memberof"]) -1;
         for ($j=0; $j<$taillememberof; $j++){
           echo 'memberOf ['.$j.'] : ' . $info[$i]["memberof"][$j] . '<br />';
         }
       }
     }else{
       echo "Connexion LDAP échouée";
     }
    }
?>

INTERNET EXPLORER

Si le navigateur utilisé est IE, vérifiez la configuration dans les options Internet :

configuration IE

FIREFOX

Dans la barre d’adresse tapez about:config puis filtrez avec le mot « auth.trusted » :

configuration Firefox

RESULTAT

SUPER ça marche !!

HTTP_ACCEPT = image/jpeg, application/x-ms-application, image/gif, application/xaml+xml,
image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash; [..] */*
HTTP_ACCEPT_LANGUAGE = fr-FR
HTTP_USER_AGENT = Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2;
.NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0;
Tablet PC 2.0; .NET CLR 1.1.4322; .NET4.0C; InfoPath.3)
HTTP_ACCEPT_ENCODING = gzip, deflate
HTTP_HOST = serveurA
HTTP_CONNECTION = Keep-Alive
PATH = /sbin:/usr/sbin:/bin:/usr/bin
SERVER_SIGNATURE =
Apache/2.2.3 (CentOS) Server at serveurA.maboite.fr Port 80

SERVER_SOFTWARE = Apache/2.2.3 (CentOS)
SERVER_NAME = serveurA.maboite.fr
SERVER_ADDR = 10.80.133.196
SERVER_PORT = 80
REMOTE_ADDR = 10.80.128.36
DOCUMENT_ROOT = /var/www/html
SERVER_ADMIN = root@localhost
SCRIPT_FILENAME = /var/www/html/logon/index.php
REMOTE_PORT = 52398
REMOTE_USER = MUSER@DOM2.MABOITE.FR
AUTH_TYPE = Negotiate
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.1
REQUEST_METHOD = GET
QUERY_STRING =
REQUEST_URI = /logon/index.php
SCRIPT_NAME = /logon/index.php
PHP_SELF = /logon/index.php
REQUEST_TIME = 1308664098

Connexion LDAP reussie

1 entrees trouvees.
dn est : CN=USER\\, MON,OU=Comptes Collaborateurs,OU=Dom2,DC=dom2,DC=maboite,DC=fr
premiere entree cn : USER, Mon
prenom : Mon
nom : USER
premier email : MUSER@maboite.fr
memberOf [0] : CN=LinuxEXPLOIT,OU=Groupes d'equipes,OU=Dom2,DC=dom2,DC=maboite,DC=fr
memberOf [1] : CN=Utilisateurs Internet,OU=Groupes Applicatifs,OU=Dom2,DC=dom2,DC=maboite,DC=fr
memberOf [2] : CN=Equipe Systeme,OU=Groupes d'equipes,OU=Dom2,DC=dom2,DC=maboite,DC=fr

 

Conclusion

Et voilà c’est terminé pour aujourd’hui. Comme nous l’avons vu, il est possible de permettre à des utilisateurs Windows de s’authentifier en toute transparence à un site Web qui fonctionne sous Linux.

Si vous avez des commentaires n’hésitez pas !

 

Liens

Vus : 7658
Publié par Vince : 7