www.SAMURAJ-cz.com 

20.04.2024 Marcela Translate to English by Google     VÍTEJTE V MÉM SVĚTĚ

Články

Kerberos SSO v PHP aplikaci s Apachem na Linuxu

Upraveno 08.04.2013 16:29 | vytvořeno 22.09.2010 17:58 | Samuraj - Petr Bouška |
V minulých článcích jsme se věnovali popisu protokolu Kerberos a jeho použití při Single sign-on. Dále používání SSO z pohledu Windows klienta, primárně při ověřování k webové aplikaci. Dnes se podíváme na druhou stranu a to na webový server a využití SSO v naší webové aplikaci. Základní popis je obecný, ale v detailech musíme vycházet z přesně daných podmínek. Opět budeme využívat to, že máme správu uživatelů v doméně Active Directory, a tedy autentizace vůči AD pomocí protokolu Kerberos. Klienti budou na Windows, tak jak jsme je popsali v minulém článku. Na serveru budeme využívat aplikační server Apache a malá zmínka kódu se bude týkat jazyka PHP.

Věcem, které popisuji v tomto článku, jsem se věnoval nově a detailněji a připravil rozsáhlý seriál Kerberos protokol se zaměřením na SSO v AD DS. S tímto článkem hlavně souvisí posledních několik dílů, nejvíce díl Kerberos část 11 - konfigurace Apache a využití v PHP.

Rozchození Kerberosu v Apachi a použití v PHP se věnoval můj kolega Ondra, který vymyslel i řešení pro přechod na standardní autentizaci, když SSO nefunguje u klienta. Bohužel je tu jedna zásadní podmínka, Apache musí běžet na Linuxu. Nepodařilo se nám nalézt jedinou Kerberos knihovnu (ani jinou pro využití SSO) pro Apache na Windows. Na Windows ovšem můžeme použít jiný aplikační server, třeba IIS nebo Tomcat, kde SSO knihovny máme.

Související články jsou Kerberos protokol a Single sign-on a Kerberos SSO - nastavení Internet Exploreru a Firefoxu.

Vytvoření účtu pro Apache službu v AD

Z principu Kerberosu víme, že každá služba, ke které se chceme přihlašovat, musí mít záznam (účet) v Active Directory. A že aplikační server potřebuje secret key, aby mohl dešifrovat komunikaci, která mu bude přicházet. Protože náš aplikační server je Linuxový, tak jej nemůžeme normálně zařadit do domény, ale musíme ručně vytvořit účet a vyexportovat šifrovací klíč.

Dále popisovaný postup je možno použít na Windows Sever 2000, 2003, 2008 i 2008 R2. Liší se pouze nějaké detaily, jako jsou podporované šifrovací algoritmy. Uvedené příklady jsou testované na Windows Server 2008 R2. Používaný příkaz ktpass je dostupný na Windows 2000 Resource Kit, Windows 2003 Support Tools a u Server 2008 je součástí nástrojů, které se instalují na doménový kontrolér. Vždy je třeba použít verzi odpovídající úrovni domény.

Vytvoření záznamu v DNS

Pokud ještě nemáme, tak musíme nejprve vytvořit v DNS záznam pro server/službu (adresa web serveru, třeba mujweb.domena.local).

Vytvoření uživatelského účtu v AD

Potřebujeme jakoby zařadit náš Linuxový server do domény, takže by se zdálo, že budeme vytvářet účet počítač. Ve skutečnosti nám jde pouze o účet služby, ten nemůžeme vytvořit samostatně, ale můžeme jej navázat na účet uživatele. Takže vytváříme uživatelský účet pro náš server/službu.

  • například pomocí Active Directory Users and Computers vytvoříme v AD uživatelský účet
  • tento účet musí být umístěn v defaultním kontejneru Users
  • jméno můžeme zvolit stejné (není podmínkou), jako jméno serveru (třeba mujweb)
  • samozřejmě žádný takový účet již nesmí existovat a nesmíme nastavit vyžadování změny hesla

Nastavení SPN a exportování keytab souboru

Service Principal Name (SPN) je název služby, jak ji bude volat klient (webový prohlížeč), když chceme provést Kerberos autentizaci k webu. SPN je svázáno s účtem (uživatele, počítače, skupiny). Můžeme jej vytvořit pomocí příkazu setspn, ale my použijeme rovnou příkaz ktpass, který nám zajistí i vytvoření keytab souboru. Pro webovou aplikaci má SPN tvar HTTP/<hostname> (tedy HTTP/mujweb.domena.local), kde hostname musí odpovídat DNS adrese serveru. To platí i v případě, že používáme protokol HTTPS (stále je to HTTP/hostname). Toto SPN svážeme s naším vytvořeným uživatelem (mujweb@domena.local).

Pozn.: Hostname v SPN musí odpovídat A záznamu v DNS a nikoliv Aliasu (CNAME). Například když máme server web.domena.local se stejným jménem v DNS a k tomu máme alias www.domena.local, tak do SPN musíme dát web.domena.local, i když uživatelé pro přístup používají alias.

Pomocí příkazu ktpass provedeme namapování SPN a zároveň exportování Kerberos keytab souboru. Syntaxe a příklad pro naši situaci:

ktpass -out <jméno souboru> -princ HTTP/<hostname>@<DNS JMÉNO AD DOMÉNY VELKÝMI PÍSMENY> -mapUser <název uživatele>@<název domény> -mapOp set -pass * -ptype KRB5_NT_PRINCIPAL -kvno 0

ktpass -out mujweb.keytab -princ HTTP/mujweb.domena.local@DOMENA.LOCAL -mapUser mujweb@domena.local -mapOp set -pass * -ptype KRB5_NT_PRINCIPAL -kvno 0

Výstupní keytab soubor (mujweb.keytab) obsahuje SPN a secret key služby. Principal name (parametr princ) se skládá z SPN a určení domény vůči které budeme uživatele autentizovat (musí být zadáno velkými písmeny). MapOp určí, že se SPN nastaví na účet (ne přidá další). Pokud chceme uložit keytab soubor, tak musíme zadat heslo. Toto heslo se nastaví na uživatelský účet (změní se původní heslo). Když zadáme hvězdičku, tak jsme následně dotázáni na heslo.

Ve chvíli, kdy vytváříme keytab soubor, se uživatelský účet musí nacházet v kontejneru Users, jinak dostaneme následující chybovou hlášku (možná je to bug ve Windows Server 2008 R2). Po vytvoření souboru již můžeme účet přesunout do libovolné organizační jednotky.

Password set failed!  0x00000020
Aborted.

Důležité je zajistit bezpečnost keytab souboru, protože obsahuje údaje pro přihlášení k AD jménem dané služby. Nějaké informace můžete nalézt v MS článcích o Service Principal Names a o nástroji Ktpass.

Doplněno 8.4.2013 - Vyšel Firefox 20.0 a v něm přestalo fungovat SSO nastavené dle tohoto popisu. Místo aby došlo k přihlášení, tak se zobrazil dialog na HTTP autentizaci. Po celém dni bádání jsem přišel na to, že novému Firefoxu vadí, že server se jmenuje mujweb.domena.local a toto jméno používáme v SPN, ale pro přístup na web používáme www.domena.local. Když jsem vytvořil nový Keytab soubor a použil jsem www.domena.local, tak ve Firefoxu začalo SSO fungovat, ale zas přestalo chodit z Internet Exploreru. Takže jsem ještě musel změnit DNS záznamy, aby A záznam byl www.domena.local a CNAME mujweb.domena.local. Po několika minutách pak vše začalo fungovat.

Kerberos modul pro Apache - mod_auth_kerb

Testování jsme prováděli na Oracle Enterprise Linux 5.5 (OEL). Zvolili jsme nejrozšířenější knihovnu mod_auth_kerb (Kerberos Module for Apache), jejíž balíček je součástí OEL.

  • nainstalujeme balíček mod_auth_kerb a povolíme jej v Apachi (pokud se nepovolí automaticky) v httpd.conf
LoadModule   auth_kerb_module   modules/mod_auth_kerb.so
  • keytab soubor (mujweb.keytab) nahrajeme na server a umístíme jej do bezpečného adresáře tak, aby k němu měl přístup Apache
  • nastavíme parametry pro adresář v Apachi, kde chceme použít autentizaci

Konfigurace Apache Directory

Konfiguraci můžeme provést pomocí souboru .htaccess nebo pomocí directivy Directory či Location, buď v kontextu celého web serveru nebo v rámci určitého Virtual Hosta, standardně v souboru httpd.conf. Parametry nastavujeme na jeden určitý adresář, kam umístíme přihlašovací skript (pokud použijeme standardní metodu přihlášení a údaje dále máme v session, jinak můžeme nastavit i na celý web a každá stránka se bude autentizovat). Ukázka konfigurace:

<Directory /var/www/mujweb/sso/>
  AuthName "Kerberos Login"
  AuthType Kerberos
  KrbAuthRealms DC.DOMENA.LOCAL DOMENA.LOCAL
  KrbServiceName HTTP/mujweb.domena.local@DOMENA.LOCAL
  Krb5KeyTab /etc/apache2/mujweb.keytab  	 	
  require valid-user  
</Directory>
  • AuthType Kerberos - musíme zadat, aby se použila autentizace Kerberos
  • KrbServiceName - musí přesně odpovídat principal name, které jsme použili při generování keytab souboru
  • Krb5KeyTab - cesta ke keytab souboru uloženém na filesystému

Pro ještě větší zabezpečení můžeme na adresář vyžadovat použití HTTPS přidáním directivy:

SSLRequireSSL

V konfiguraci Apache je ještě třeba mít nastaveno plné jméno (FQDN, adresu) serveru, buď pro celý web nebo pro daný Virtual Host (což asi máme):

ServerName mujweb.domena.local

Použití SSO v PHP

Princip komunikace (Kerberos autentizace) jsme si popsali v minulém článku, nyní jen zopakujeme výměnu informací mezi klientem (prohlížečem) a web serverem.

  • Klient (webový prohlížeč) požaduje nějakou stránku (GET požadavek).
  • Ta je v adresáři, kde vyžadujeme Kerberos autentizaci, takže server odpoví v HTTP hlavičce, že požaduje autentizaci (HTTP/1.1 401 Authorization Required, WWW-Authenticate: Negotiate, WWW-Authenticate: Basic realm="Kerberos Login").
  • Pokud klient podporuje Kerberos, tak odešle v hlavičce autentizační údaje (což je service ticket, Authorization: Negotiate následuje šifrovaný obsah). Pokud ne, tak nijak neodpovídá, ale zobrazí okno pro HTTP autentizaci (to je dáno dalšími údaji, které dostal ze serveru). Na Apachi je možno nastavit více autentizačních metod, které se použijí když některá selže.
  • Pokud je vše v pořádku, tak server opět v hlavičce odešle potvrzení (HTTP/1.1 302 Found, WWW-Authenticate: Negotiate šifrovaná data serveru).

Pokud dojde k úspěšnému přihlášení, tak Apache uloží jméno uživatele (uživatelské-ID@doména, třeba user@DOMENA.LOCAL) do serverové proměnné $_SERVER['REMOTE_USER'], z které jej můžeme v PHP jednoduše získat.

Jednoduché použití tedy je, že přihlašovací skript umístíme do speciálního adresáře a na něj aplikujeme výše popsané nastavení Apache. Když se takovou stránku pokusí uživatel otevřít, tak proběhne SPNEGO (Kerberos) autentizace. Pokud tato selže, tak se vůbec nevyvolá skript, ale server odešle chybu. Proto můžeme ve skriptu počítat s tím, že SSO proběhlo úspěšně a již pouze kontrolujeme uživatelské jméno. Velice jednoduchý skript /sso/login.php může vypadat třeba takto.

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

Složitější situace ovšem je, pokud chceme zajistit, aby při selhání SSO (například uživatel ji nemá na stanici povolenu) došlo k přepadu na klasickou form-based autentizaci. Běžně při selhání SSO vyskočí okno prohlížeče s HTTP autentizací (která v našem nastavení nefunguje) a když klikneme na Cancel nebo něco zadáme, tak se zobrazí chybová stránka. To, že standardně vyskočí okno pro HTTP autentizaci, když selže SSO, je způsobeno tím, že Apache odesílá v hlavičce

WWW-Authenticate: Basic realm='Kerberos Login'

Hlavičky, které odesílá Apache při Kerberos autentizaci, můžeme vytvořit ručně a otestovat, jestli přichází odpověď (tedy je podporováno SSO). V tom případě provedeme SSO autentizaci, v opačném případě zobrazíme klasickou autentizaci přes formulář. Schématicky tuto metodu ukazuje následující skript /login.php. Funguje to na tom principu, že pokud prohlížeč podporuje SSO pro danou stránku, tak přijme v hlavičce požadavek na vyjednání autentizace a již nezobrazuje stránku, kterou přijal, ale odešle autentizační údaje na stejnou adresu. V opačném případě zobrazí přijatou stránku, takže do ní můžeme vložit běžný přihlašovací formulář.

<?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;
  }
?>
zobrazeno: 37056krát | Komentáře [12]

Autor:

Související články:

Kerberos a Single Sign-On

Autentizační protokol, který hojně využívá (nejen) Microsoft. Články se věnují jednotnému přihlašování (SSO), v praxi jde hodně o využití Microsoft Active Directory Domain Services.

Active Directory a protokol LDAP

Správa počítačové sítě ala Microsoft, to je Active Directory. Jedná se o velice rozsáhlou skupinu technologií a služeb. Základem jsou adresářové služby, adresáře a komunikační protokol LDAP.

Pokud se chcete vyjádřit k tomuto článku, využijte komentáře níže.

Komentáře

  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

    }

    Pondělí, 01.11.2010 14:55 | odpovědět
  2. [2] Samuraj

    odpověď na [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.

    Pondělí, 01.11.2010 15:18 | odpovědět
  3. [3] Ladislav Jech

    odpověď na [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í.;-)

    Úterý, 16.11.2010 14:20 | odpovědět
  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

    Pátek, 11.02.2011 16:35 | odpovědět
  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?

    Pátek, 11.02.2011 17:14 | odpovědět
  6. [6] Josef Andrýsek

    odpověď na [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

    Pátek, 11.02.2011 20:30 | odpovědět
  7. [7] Samuraj

    odpověď na [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.

    Středa, 16.02.2011 15:31 | odpovědět
  8. [8] Josef Andrysek

    odpověď na [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

    Pondělí, 21.02.2011 20:12 | odpovědět
  9. [9] Samuraj

    odpověď na [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.

    Úterý, 22.02.2011 08:56 | odpovědět
  10. [10] Josef Andrýsek

    odpověď na [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

    Úterý, 22.02.2011 16:07 | odpovědět
  11. [11] samuraj

    odpověď na [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.

    Úterý, 22.02.2011 16:30 | odpovědět
  12. [12] ABerny

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

    Úterý, 04.10.2011 14:03 | odpovědět
Přidat komentář

Vložit tag: strong em link

Vložit smajlík: :-) ;-) :-( :-O

Nápověda:
  • maximální délka komentáře je 2000 znaků
  • HTML tagy nejsou povoleny (budou odstraněny), použít se mohou pouze speciální tagy (jsou uvedeny nad vstupním polem)
  • nový řádek (ENTER) ukončí odstavec a začne nový
  • pokud odpovídáte na jiný komentář, vložte na začátek odstavce (řádku) číslo komentáře v hranatých závorkách