The context
Sometimes people are crazy ! They install Microsoft architectures everywhere : Windows on workstations, a lot of domain controllers and Active Directory. And then MS is regularly see them with their bill and they lose an arm. Since they are still eager to eat chocolate, they decide (which is not bad) to open their information to other technologies. That way the next time a Bill ‘s soldier will see them, they can threaten him (a little) to stop using its products and thus lower the bill.
The next application will be completely done with free software components, and as more Web format than done. The user must connect to the application via a browser using the Windows Integrated authentication.
We arrive and we are happy because it proposes to use the following software :
- Linux CentOS 5.6
- Samba 3.5.4
- Apache 2.2.3
- Mod_auth_kerb : 5.1
- Kerberos 1.6.1
- Php 5.1
And all this in the following environment :
- OS Workstation : Windows XP et 7
- Web browser : IE9 et Firefox 4
- KDC : Windows 2003/2008 R2
A small diagram to illustrate the Active Directory architecture used in this post :
And a small second :
Naming rules used in this tutorial
- Server Linux Apache : serverA
- Server KDC 2003 dom1.maboite.fr : serverKDC1
- Server KDC 2008 dom1.maboite.fr : serverKDC2
- Server KDC 2003 dom2.maboite.fr : serverKDC3
Installation
Once the CentOS prepared in a basic version, install the necessary packages :
# 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 and time
Our server should not be too delayed (<10 min) with the DC domain DOM1.
Customize the file /etc/ntp.conf to synchronize with a time server, then type the following commands :
# service ntpd stop # ntpdate @TIME_SERVER # service ntpd start
HOSTS file
The file /etc/hosts must be properly informed in order to join an Active Directory domain :
127.0.0.1 serverA.maboite.fr serverA
KERBEROS
Customize the file /etc/krb5.conf and adapt the following :
[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 serverKDC1
kdc = @IP serverKDC2
admin_server = @IP serverKDC1
admin_server = @IP serverKDC2
}
[domain_realm]
MONWORKGROUP = DOM1.MABOITE.FR
.dom1.maboite.fr = DOM1.MABOITE.FR
[appdefaults]
kinit = {
renewable = true
fowardable = true
}
Then create file /etc/krb5.keytab :
# touch /etc/krb5.keytab # chmod 640 /etc/krb5.keytab # chgrp apache /etc/krb5.keytab
SAMBA
Here is a sample of the configuration file /etc/samba/smb.conf with the necessary parameters:
[global] dedicated keytab file = /etc/krb5.keytab kerberos method = secrets and keytab security = ADS server string = SERVERA 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
Then we will join the Linux server to the Domain 1 :
# /etc/init.d/smb stop # /etc/init.d/nmb stop # /etc/init.d/winbind stop # net cache flush # kinit admin_account_dom1 # net ads join -U admin_account_dom1 Enter admin_account_dom1's password:
The answer of the last command indicating that the operation went well must be :
Using short domain name -- MONWORKGROUP Joined 'SERVERA' to realm 'dom1.maboite.fr'
To check :
# net ads testjoin Join is OK
Then restart SAMBA :
# /etc/init.d/smb start # /etc/init.d/nmb start # /etc/init.d/winbind start
KEYTAB
The Web server has successfully joined the AD domain, we now learn the file /etc/krb5.keytab for it to be used by Apache.
# net ads keytab add HTTP -U admin_account_dom1 Processing principals to add... Enter admin_account_dom1's password:
Verify if the file /etc/krb5.keytab is right :
# ktutil ktutil: rkt /etc/krb5.keytab ktutil: l slot KVNO Principal ---- ---- --------------------------------------------------------------------- 1 28 HTTP/serverA.maboite.fr@DOM1.MABOITE.FR 2 28 HTTP/serverA.maboite.fr@DOM1.MABOITE.FR 3 28 HTTP/serverA.maboite.fr@DOM1.MABOITE.FR 4 28 HTTP/serverA@DOM1.MABOITE.FR 5 28 HTTP/serverA@DOM1.MABOITE.FR 6 28 HTTP/serverA@DOM1.MABOITE.FR
APACHE
Customize the file /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>
The restart Apache :
# /etc/init.d/httpd restart
PHP and LDAP
The following PHP file is given as an example. We will post the PHP variables to verify that the authentication is successful, then we will try to get some information about the user contained in the AD (name, surname, email, …).
Create the php file /var/www/html/logon/index.php and write the following code:
SUPER it works !!<br>
<?php
foreach($_SERVER as $key_name => $key_value){
print $key_name . " = " . $key_value . "<br>";
}
echo "<br />";
// Info AD DOM1
$ldaphostDOM1 = "serverKDC1"; // DOM1 server AD
$ldapportDOM1 = 389; // port
// Info AD DOM2
$ldaphostDOM1 = "serverKDC3"; // DOM2 server AD
$ldapportDOM1 = 389; // port
// [...] same for other doamins
// User DN DOM1
$ldaprdnDOM1 = 'CN=LDAP, OU=Comptes techniques, OU=Dom1, DC=dom1, DC=maboite, DC=fr';
$ldappassDOM1 = 'password'; // User Password
// User DN DOM2
$ldaprdnDOM2 = 'CN=LDAP, OU=Comptes techniques, OU=Dom2, DC=dom2, DC=maboite, DC=fr';
$ldappassDOM2 = 'password'; // User password
// [...] same for other domains
// USER DN 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"
// [...] same for other domains
// $person is the username et $domain is 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 [...] same for other domains
default:
die( "Unknow user domain : $domain" );
}
// Connecting to LDAP
$ldapconn = ldap_connect( $ldaphost, $ldapport )
or die( "Unable to connect to the LDAP server {$ldaphost}" );
if ($ldapconn) {
//Connect to LDAP server
$ldapbind = ldap_bind($ldapconn, $ldaprdn, $ldappass);
// Identification
if ($ldapbind) {
echo "LDAP connection successfull<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"]." register.\n";
for ($i=0; $i<$info["count"]; $i++) {
echo 'dn is : ' . $info[$i]["dn"] . '<br />';
echo 'first register cn : ' . $info[$i]["cn"][0] . '<br />';
echo 'name : ' . $info[$i]["givenname"][0] . '<br />';
echo 'surname : ' . $info[$i]["sn"][0] . '<br />';
echo 'first 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 "LDAP connction failed";
}
}
?>
INTERNET EXPLORER
If the browser is IE, check the configuration options in the Internet :
FIREFOX
In the address bar type about: config then filter with the word « auth.trusted » :
RESULTAT
SUPER it works !! 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 = serverA.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 LDAP connection successfull 1 register. dn is : CN=USER\, MON,OU=Comptes Collaborateurs,OU=Dom2,DC=dom2,DC=maboite,DC=fr first register cn : USER, Mon name : Mon surname : USER first 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
And now it’s over for today. As we have seen, it is possible to allow Windows users to authenticate seamlessly with a website that runs on Linux.
If you have any comments please!












CC - Paternité - Certains droits réservés
Hey!
If I need to do authentication with Apache + Samba + Kerberos against Active Directory on website which has for example MediaWiki or another CMS engine. You method is suitable for this.
User goes to website (MediaWiki page) and has Active Directory username.
It is possible?
Thanks!
Sorry.
Your method is suitable for this?*
Can you do screenshot to show how it works?
Thanks , I’ve recently been searching for info about this topic for a long time and yours is the best I have discovered till now. But, what about the conclusion? Are you sure about the supply?
By default the system keytab, /etc/krb5.keytab, should only be readable by root.
For security purposes it would be better to create a separate keytab for the webserver process (EG: /etc/apache2/krb5.keytab ), put the HTTP credentials in that file, and make it readable by apache. That way, if your website gets compromised (EG: bad user PHP code, SQL injection, etc) the only thing the attacker can get is the webserver credentials, the creds for other processes (EG: sshd or smbd) are still safe.