EN 
30.11.2025 Ondřej WELCOME IN MY WORLD

This website is originally written in the Czech language. Most content is machine (AI) translated into English. The translation may not be exact and may contain errors.

Tento článek si můžete zobrazit v originální české verzi. You can view this article in the original Czech version.
Kerberos SSO v PHP aplikaci s Apachem na Linuxu

Kerberos SSO in a PHP application with Apache on Linux

Edited 08.04.2013 16:29 | created | Petr Bouška - Samuraj |
In previous articles, we have described the Kerberos protocol and its use in Single sign-on. Also, using SSO from a Windows client perspective, primarily when authenticating to a web application. Today we'll look at the other side, the web server and the use of SSO in our web application. The basic description is general, but in the details we have to work from precise conditions. Again, we will take advantage of the fact that we have user management in an Active Directory domain, and thus authentication to AD using Kerberos. The clients will be on Windows as we described in the last article. On the server we will be using the Apache application server and a small mention of the code will be related to the PHP language.
displayed: 39 853x (38 185 CZ, 1 668 EN) | Comments [12]

I have recently explored the topics described in this article in more detail and have prepared an extensive series Kerberos protocol with focus on SSO in AD DS. The last few parts, especially Kerberos part 11 - Apache configuration and use in PHP, are most relevant to this article.

My colleague Ondra worked on setting up Kerberos in Apache and using it in PHP, and he also came up with a solution for transitioning to standard authentication when SSO doesn't work for the client. Unfortunately, there is one crucial condition: Apache must run on Linux. We were unable to find a single Kerberos library (or any other for using SSO) for Apache on Windows. However, on Windows, we can use a different application server, such as IIS or Tomcat, where we have SSO libraries available.

Related articles are Kerberos protocol and Single sign-on and Kerberos SSO - Internet Explorer and Firefox settings.

Creating an Account for the Apache Service in AD

From the principles of Kerberos, we know that each service we want to authenticate to must have a record (account) in Active Directory. And that the application server needs a secret key to be able to decrypt the communication that will come to it. Because our application server is Linux, we cannot normally join it to the domain, but we must manually create an account and export the encryption key.

The procedure described below can be used on Windows Server 2000, 2003, 2008, and 2008 R2. The only differences are some details, such as the supported encryption algorithms. The examples given are tested on Windows Server 2008 R2. The ktpass command used is available in the Windows 2000 Resource Kit, Windows 2003 Support Tools, and is included in the tools installed on the domain controller on Server 2008. Always use the version corresponding to the domain level.

Creating a DNS Record

If we don't have one yet, we must first create a DNS record for the server/service (the web server address, e.g., mywebsite.domain.local).

Creating a User Account in AD

We need to sort of join our Linux server to the domain, so it would seem we should create a computer account. In reality, we only want a service account, which we cannot create separately, but we can link it to a user account. So we create a user account for our server/service.

  • for example, using Active Directory Users and Computers, we create a user account in AD
  • this account must be placed in the default Users container
  • we can choose the same name (not required) as the server name (e.g., mywebsite)
  • of course, such an account must not already exist, and we must not set a password change requirement

Setting SPN and Exporting the Keytab File

Service Principal Name (SPN) is the name of the service that the client (web browser) will call when we want to perform Kerberos authentication to the web. The SPN is tied to the account (user, computer, group). We could create it using the setspn command, but we'll use the ktpass command instead, which will also create the keytab file for us. For a web application, the SPN has the form HTTP/<hostname> (i.e., HTTP/mywebsite.domain.local), where the hostname must match the server's DNS address. This also applies if we use the HTTPS protocol (it's still HTTP/hostname). We will associate this SPN with our created user (mywebsite@domain.local).

Note: The hostname in the SPN must match the A record in DNS and not an Alias (CNAME). For example, if we have a server web.domain.local with the same name in DNS and an alias www.domain.local, we must put web.domain.local in the SPN, even though users use the alias to access it.

Using the ktpass command, we will map the SPN and at the same time export the Kerberos keytab file. The syntax and an example for our situation:

ktpass -out <filename> -princ HTTP/<hostname>@<AD DOMAIN NAME IN UPPERCASE> -mapUser <username>@<domain name> -mapOp set -pass * -ptype KRB5_NT_PRINCIPAL -kvno 0

ktpass -out mywebsite.keytab -princ HTTP/mywebsite.domain.local@DOMAIN.LOCAL -mapUser mywebsite@domain.local -mapOp set -pass * -ptype KRB5_NT_PRINCIPAL -kvno 0

The output keytab file (mywebsite.keytab) contains the SPN and the service's secret key. The Principal name (princ parameter) consists of the SPN and the specification of the domain against which we will authenticate the user (must be in uppercase). MapOp specifies that the SPN will be set on the account (not added). If we want to save the keytab file, we must enter a password. This password will be set on the user account (the original password will be changed). When we enter an asterisk, we are then prompted for the password.

At the moment when we create the keytab file, the user account must be in the Users container, otherwise we will get the following error message (perhaps a bug in Windows Server 2008 R2). After creating the file, we can move the account to any organizational unit.

Password set failed!  0x00000020
Aborted.

It is important to ensure the security of the keytab file, as it contains login credentials for AD on behalf of the given service. You can find some information in MS articles on Service Principal Names and the Ktpass tool.

Added on 8.4.2013 - Firefox 20.0 was released and SSO set up according to this description no longer worked. Instead of logging in, the HTTP authentication dialog was displayed. After a whole day of investigation, I found that the new Firefox has a problem with the server being named mywebsite.domain.local and using this name in the SPN, but accessing the web using www.domain.local. When I created a new Keytab file and used www.domain.local, SSO started working in Firefox, but then stopped working in Internet Explorer. So I also had to change the DNS records so that the A record was www.domain.local and the CNAME was mywebsite.domain.local. After a few minutes, everything started working.

Kerberos Module for Apache - mod_auth_kerb

We tested on Oracle Enterprise Linux 5.5 (OEL). We chose the most widespread library mod_auth_kerb (Kerberos Module for Apache, whose package is part of OEL).

  • we install the mod_auth_kerb package and enable it in Apache (if it doesn't enable automatically) in httpd.conf
LoadModule   auth_kerb_module   modules/mod_auth_kerb.so
  • we upload the keytab file (mywebsite.keytab) to the server and place it in a secure directory so that Apache has access to it
  • we set the parameters for the directory in Apache where we want to use authentication

Configuring the Apache Directory

The configuration can be done using the .htaccess file or using the Directory or Location directive, either in the context of the entire web server or within a specific Virtual Host, typically in the httpd.conf file. We set the parameters for a specific directory where we will place the login script (if we use the standard login method and the data is further in the session, otherwise we can also set it for the entire web and each page will authenticate). Example configuration:

<Directory /var/www/mywebsite/sso/>
  AuthName "Kerberos Login"
  AuthType Kerberos
  KrbAuthRealms DC.DOMAIN.LOCAL DOMAIN.LOCAL
  KrbServiceName HTTP/mywebsite.domain.local@DOMAIN.LOCAL
  Krb5KeyTab /etc/apache2/mywebsite.keytab  	 	
  require valid-user  
</Directory>
  • AuthType Kerberos - we must specify that Kerberos authentication should be used
  • KrbServiceName - must exactly match the principal name we used when generating the keytab file
  • Krb5KeyTab - path to the keytab file stored in the file system

For even greater security, we can require the use of HTTPS on the directory by adding the directive:

SSLRequireSSL

In the Apache configuration, we also need to have the full name (FQDN, address) of the server set, either for the entire web or for the given Virtual Host (which we probably have):

ServerName mywebsite.domain.local

Using SSO in PHP

We described the communication principle (Kerberos authentication) in the previous article, now we'll just recap the exchange of information between the client (browser) and the web server.

  • The client (web browser) requests a page (GET request).
  • It is in a directory where we require Kerberos authentication, so the server responds in the HTTP header that it requires authentication (HTTP/1.1 401 Authorization Required, WWW-Authenticate: Negotiate, WWW-Authenticate: Basic realm="Kerberos Login").
  • If the client supports Kerberos, it sends the authentication credentials in the header (which is a service ticket, Authorization: Negotiate followed by encrypted content). If not, it doesn't respond in any way, but displays the HTTP authentication window (this is due to additional data it received from the server). On Apache, it is possible to set multiple authentication methods that will be used if one fails.
  • If everything is fine, the server sends confirmation again in the header (HTTP/1.1 302 Found, WWW-Authenticate: Negotiate encrypted server data).

If successful login occurs, Apache stores the user's name (username@domain, e.g., user@DOMAIN.LOCAL) in the server variable $_SERVER['REMOTE_USER'], from which we can easily retrieve it in PHP.

Simple use is to place the login script in a special directory and apply the above-described Apache settings to it. When a user tries to open such a page, SPNEGO (Kerberos) authentication will take place. If this fails, the script will not be invoked at all, but the server will send an error. Therefore, we can assume in the script that SSO was successful and only check the username. A very simple script /sso/login.php could look like this.

<?php
   session_start();
   $_SESSION['username'] = $_SERVER['REMOTE_USER'];
   header('Location: /');
?>

A more complicated situation, however, is when we want to ensure that in case of SSO failure (for example, the user doesn't have it enabled on the workstation), it falls back to a classic form-based authentication. Normally, when SSO fails, the browser window pops up with HTTP authentication (which doesn't work in our setup) and when we click Cancel or enter something, an error page is displayed. The fact that the HTTP authentication window normally pops up when SSO fails is because Apache sends the header

WWW-Authenticate: Basic realm='Kerberos Login'

Headers that Apache sends during Kerberos authentication, we can create manually and test if the response arrives (i.e., SSO is supported). In that case, we perform the SSO authentication, otherwise we display the classic authentication through the form. The following script /login.php schematically shows this method. It works on the principle that if the browser supports SSO for the given page, it accepts the request for negotiating authentication in the header and no longer displays the received page, but sends the authentication credentials to the same address. Otherwise, it displays the received page, so we can insert a standard login form into it.

<?php
  session_start();
  $headers = apache_request_headers();
  if(empty($headers['Authorization'])) {
    header("HTTP/1.1 401 Authorization Required");
    header("WWW-Authenticate: Negotiate");
    // SSO není podporováno, zobrazím standardní login či informace
    echo "SSO autentizace neprobehla.";
    exit;
  } else { 
    // SSO OK, přesměruju na SSO login
    header('Location: /SSO/login.php');
    exit;
  }
?>
Author:

Related articles:

Kerberos and Single Sign-On

Authentication protocol that is widely used (not only) by Microsoft. The articles focus on single sign-on (SSO), in practice it is very much about using Microsoft Active Directory Domain Services.

Active Directory and the LDAP protocol

Managing a corporate computer network using Microsoft OS usually means managing Active Directory Domain Services (AD DS). It is a very extensive group of technologies, protocols and services. The basis is directory services, authentication and the LDAP communication protocol.

If you want write something about this article use comments.

Comments
  1. [1] Ladislav Jech

    Ahoj,

    pěkný článek na téma SSO. Nechybí zde ale část o vlastní konfiguraci kerberos klienta na straně linuxového serveru?

    V mém případě vypadá takto:

    [logging]

    default = FILE:///var/log/krb5libs.log

    kdc = FILE:///var/log/krb5kdc.log

    admin_server = FILE:///var/log/kadmind.log

    [libdefaults]

    default_realm = DEVELOPMENT.TIMEIMPORT.CZ

    dns_lookup_realm = true

    dns_lookup_kdc = true

    ticket_lifetime = 3600h

    forwardable = yes

    default_keytab_name = FILE:///etc/krb5.keytab

    [realms]

    DEVELOPMENT.TIMEIMPORT.CZ = {

    kdc = andromeda.development.timeimport.cz:88

    admin_server = andromeda.development.timeimport.cz:749

    default_domain = development.timeimport.cz

    }

    [domain_realm]

    prometheus.development.timeimport.cz = DEVELOPMENT.TIMEIMPORT.CZ

    .development.timeimport.cz = DEVELOPMENT.TIMEIMPORT.CZ

    [appdefaults]

    pam = {

    debug = false

    ticket_lifetime = 36000

    renew_lifetime = 36000

    forwardable = true

    krb4_convert = false

    }

    Monday, 01.11.2010 14:55 | answer
  2. [2] Samuraj

    respond to [1]Ladislav Jech: Moc jsem to nepochopil, co je to za konfiguraci a čeho se týká? Pro web server nic takového nepotřebuji.

    Monday, 01.11.2010 15:18 | answer
  3. [3] Ladislav Jech

    respond to [2]Samuraj: Tohle se hodí v případě, že "něco" nefunguje tak jak má, je to prakticky zrcadlení konfiguračních informací z modulu kerberos pro apache do konfiguráku linuxového kerberos klienta, který je na CentOS v lokaci /etc/krb5.conf (verze 5), a pomocí kterého lze pak různé indispozice požadované funkcionality ladit. Klient podporuje následující příkazy: kinit, klist, kvno, kdestroy, ksu, kpasswd.

    Samozřejmě mód jako takový funguje i bez tohoto, a veškeré informace z modulu jdou do apache logu access_log, případně ssl_access.

    To je jen jako extra, návod je perfektní a funkční.;-)

    Tuesday, 16.11.2010 14:20 | answer
  4. [4] Josef Andrýsek

    Super článek. Na netu se na toto téma najde dost informací ale žádný zdroj nebyl takhle ucelený.

    Rozchodil jsem to bez problémů, ale Internet explorer mě zlobí (ve Firefoxu no problem). Když mu pošlu

    header("HTTP/1.1 401 Authorization Required");

    header("WWW-Authenticate: Negotiate");

    a on pro danou stránku SSO nepodporuje, tak stejně zobrazí ten ošklivý dialog, který chce jméno a heslo. až po kliknutí na "cancel" zobrazí můj formulář. Neexistuje nějaký trik, aby se IE choval taky takhle? Diky

    Friday, 11.02.2011 16:35 | answer
  5. [5] Samuraj

    Ve firmě to používám tak, jak je zde popsáno, a funguje to OK v IE i ve FF. Netuším, kde může být problém.

    Máte ten skript v adresáři, na kterém není nastaveno SSO v Apachi?

    Friday, 11.02.2011 17:14 | answer
  6. [6] Josef Andrýsek

    respond to [5]Samuraj: Děkuji za odpověď, mám ten skript v adresáři, kde není nastaveno SSO. Teď jsem provedl i test na serveru, kde SSO není vůbec. Tohle je komunikace IE a serveru zachycená Wiresharkem:

    GET /xsso.php HTTP/1.1

    Accept: */*

    Accept-Language: cs-CZ

    User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MALC)

    Accept-Encoding: gzip, deflate

    Host: www.diktatorek.cz

    Connection: Keep-Alive

    HTTP/1.1 401 Authorization Required

    Content-Type: text/html

    Server: Microsoft-IIS/7.0

    X-Powered-By: PHP/5.2.11

    WWW-Authenticate: Negotiate

    X-Powered-By: ASP.NET

    Date: Fri, 11 Feb 2011 19:19:09 GMT

    Content-Length: 66

    HTML formular = (odstranil jsem)

    Na základě těchto dat IE zobrazí standardní autentikační dialog, Firefox rovnou zobrazí to mojo HTML.

    Nevíte prosím o nějaké veřejně dostupné stránce, která by tento přístup používala? Podíval bych se co přesně server posílá a zařídil bych se podle toho. (potřebuju pouze aby se mi zobrazil login formulář.) Děkuju moc

    Friday, 11.02.2011 20:30 | answer
  7. [7] Samuraj

    respond to [6]Josef Andrýsek: Tak jsem to testoval a u mě v IE vyskočí to dialogové okno pouze, pokud se v hlavičce posílá:

    WWW-Authenticate: Basic realm="

    To tam posílá Apache, když přistupuji do adresáře, kde je nastaveno SSO.

    Na své testovací stránce to posílám bez tohoto parametru a IE 8.0 zareaguje zobrazením html, které je součástí dat.

    Wednesday, 16.02.2011 15:31 | answer
  8. [8] Josef Andrysek

    respond to [7]Samuraj: Děkuju, možná bude záležet na verzi I.E., nebo na nějakém dalším nastavení. Není ta Vaše testovací stránka na nějaké veřejné adrese? Jen abych měl 100% jistotu, že nedělám něco špatně. Diky

    Monday, 21.02.2011 20:12 | answer
  9. [9] Samuraj

    respond to [8]Josef Andrysek: Tak ten skript, který je na konci článku jsem uložil na adresu http://www.samuraj-cz.com/download/test-sso.php, pouze místo redirectu zobrazuji info. U mě to chodí správně, nevyskakuje žádné okno.

    Tuesday, 22.02.2011 08:56 | answer
  10. [10] Josef Andrýsek

    respond to [9]Samuraj: Děkuju moc, bohužel ten skript nevyhodí v clientu žádný dialog proto, že posílá nevalidní hlavičku:

    WWW-Authenticate: Negotiate realm="20041"

    IE 8 zobrazi rovnou chybovou hlasku. IE 6 zobrazi formular tak jak jsem chtel, ale nepokusi se o SSO, ikdyz muze. :-(

    Nechci Vas uz s tim otravovat. Kazdeopadne Diky

    Tuesday, 22.02.2011 16:07 | answer
  11. [11] samuraj

    respond to [10]Josef Andrýsek: Tak nevím, proč to tam doplňuje, ve skriptu to není a na produkčním prostředí, kde to používáme úplně stejně, to neposílá.

    Každopádně, mě se to v IE8 zachová správně a zobrazí ten text, že není podporováno SSO.

    Tuesday, 22.02.2011 16:30 | answer
  12. [12] ABerny

    respond to [11]samuraj: Tak tohle dela zapnutej safe mod v PHP. Kdyz ho vypnu, zustane tam jen spravne WWW-Authenticate: Negotiate

    Tuesday, 04.10.2011 14:03 | answer
Add comment

Insert tag: strong em link

Help:
  • maximum length of comment is 2000 characters
  • HTML tags are not allowed (they will be removed), you can use only the special tags listed above the input field
  • new line (ENTER) ends paragraph and start new one
  • when you respond to a comment, put the original comment number in squar brackets at the beginning of the paragraph (line)