Uwierzytelnienie użytkownika domenowego w PHP (Single Sign On)

Wprowadzenie
Czasami, pisząc różne aplikacje w PHP, przydaje się zautomatyzować kwestię logowania. Pamiętanie loginów i haseł, szczególnie jak trzeba się logować do kilku różnych programów, nie jest zbyt wygodne i fajnie byłoby, gdyby można by to jakoś uprościć. Technika zwana single sign-on (pojedyncze logowanie) występuje np. w systemie Windows w przypadku dostępu do różnych zasobów w obrębie danej domeny - przykładowo, użytkownik loguje się na danym komputerze do swojego konta domenowego i uzyskuje dostęp do ustalonych zasobów sieciowych a także stron/serwisów internetowych. Rozwiązanie jest łatwe do zaimplementowania, jeśli się korzysta z oprogramowania MS IIS, gorzej to wygląda w przypadku (bardziej popularnego) serwera Apache lub innych rozwiązań.

Możliwe rozwiązania
Dla serwera Apache powstało kilka modułów, pomagających w uwierzytelnieniu użytkownika. Niestety są to albo jakieś starsze wersje, niedziałające z najnowszą wersją Apache (2.2 czy 2.4), albo nie oferują oczekiwanej funkcjonalności (tj. weryfikacji tożsamości bez konieczności znajomości hasła użytkownika). Moduły te mają zazwyczaj kiepską dokumentację i muszę przyznać, że nie udało mi się zmusić żadnego z nich do współpracy z posiadanym w pracy serwerem Apache 2.2.9. Skłoniło mnie to do poszukiwań alternatywnych rozwiązań, które mógłbym wykorzystać w tworzonych przez siebie aplikacjach internetowych dla firmowego intranetu. Zdecydowanie unikam korzystania z zamkniętych rozwiązań Microsoftu typu ASP.NET i SharePoint - preferuję wieloplatformowe rozwiązania typu otwarte oprogramowanie, np. PHP.

Poszukiwania w internecie
Zacząłem szukać jakichś rozwiązań powyższego problemu w językach, które mógłbym wykorzystać w swoim przypadku (PHP, C/C++). Szukałem rozwiązań "niskopoziomowych" (w warstwie pakietów TCP/IP) - przejrzałem mnóstwo artykułów dotyczących uwierzytelniania NTLM w domenie, w tym wiele materiałów dotyczących podsłuchiwania przesyłanych pakietów i łamania przechwyconego (zaszyfrowanego) hasła. Niestety nie natrafiłem na żaden praktyczny opis rozwiązania, które by mnie satysfakcjonowało.
W końcu trafiłem na bardzo ogólny opis rozwiązania uwierzytelnienia użytkownika w PHP w artykule "Uwierzytelnianie NTLM i Single Sign On: czyli jak w PHP zalogować się do ActiveDirectory bez znajomości loginu i hasła". Niestety autor (specjalnie czy przypadkowo) opisał rozwiązanie dość ogólnikowo i nie podał gotowego skryptu, a tylko kilka wskazówek. Ponieważ nie wszystko była dla mnie jasne, nawiązałem z autorem kontakt e-mailowy - w swojej odpowiedzi na mój list doprecyzował użyte przez siebie rozwiązanie, które - jak się okazało - było w sumie zawarte na stronie z opisem, ale na tyle ogólnie, jakby nie było ważne (kluczowe) w tym rozwiązaniu. Dopiero po tym e-mailu zrozumiałem, jaką metodę zastosował autor tego rozwiązania.

Przykładowe rozwiązanie
Ponieważ autor (Artur Graniszewski) nie podał mi gotowego rozwiązania (a ja go o to bynajmniej nie prosiłem), a tylko sam pomysł, to zdecydowałem się napisać ten artykuł i podać tu swoje autorskie rozwiązanie, które uważam, że jest nawet lepsze i bardziej uniwersalne, niż to opracowane przez Artura i opisane na jego blogu.
Generalnie cały pomysł polega na tym, by do uwierzytelnienia danego użytkownika wykorzystać już istniejący i działający w firmie serwer www (IIS), korzystający z uwierzytelnienia domenowego przy użyciu Active Directory (co jest standardem w przypadku serwera IIS). Musimy jeszcze napisać dodatkowy skrypt, który będzie pośredniczył pomiędzy naszą aplikacją (napisaną w PHP i działającą np. na serwerze Apache) a serwerem IIS. Skrypt można napisać w dowolnym języku, ale ja zdecydowałem się użyć do tego PHP, ponieważ w tym języku tworzę swoje aplikacje (mam tu na myśli kod po stronie serwera).
Na serwerze IIS należy przygotować jakiś zasób (stronę - czyli adres intranetowy - np. z pustą zawartością), który będzie wymagał uwierzytelnienia domenowego (konfigurując IIS możemy zawęzić ten dostęp, ale ja sugeruję nadać go dla wszystkich posiadających aktywne konta w AD, a potem w swojej aplikacji - mając już zweryfikowanego użytkownika - decydować o dalszym dostępie/uprawnieniach).
Teraz nasz program pośredniczący ma za zadanie spróbować otworzyć ustaloną stronę intranetową na IIS i odczytać otrzymaną z serwera odpowiedź - chodzi o odebrane nagłówki, bo w nich jest właśnie przesyłane żądanie uwierzytelnienia. Stronę otwieram przy pomocy biblioteki cURL (ale jest też możliwość skorzystania ze zwykłego fsockopen) i odbieram przesłane przez serwer IIS nagłówki, które przekazuję do właściwego skryptu (tego, który chce skorzystać z uwierzytelnienia domenowego), który te nagłówki wysyła na przeglądarki użytkownika (korzystając z funkcji header). Przeglądarka użytkownika zachowuje się wtedy tak samo, jakby otwierana była wybrana strona intranetowa (na serwerze IIS) i realizuje uwierzytelnienie domenowe - w przypadku Internet Explorera jest to realizowane w tle bez interakcji z użytkownikiem, w przypadku pozostałych przeglądarek może być konieczność podania loginu i hasła. Uwierzytelnienie domenowe (NTLM Authenticate) składa się z kilku etapów, polegających na wymianie nagłówków pomiędzy przeglądarką użytkownika a serwerem IIS i należy (w programie pośredniczącym) kontrolować, na jakim etapie jesteśmy, by wiedzieć, kiedy cały proces uwierzytelnienia się zakończył i z jakim wynikiem - wtedy możemy odkodować pełną nazwę konta domenowego (nazwę konta użytkownika oraz nazwę domeny - ważne w przypadku używania w firmie kilku domen), które to dane przekazujemy do skryptu głównego (ja to trzymam w zmiennej sesyjnej $_SESSION) i może on podjąć decyzję, co dalej (na podstawie własnej listy uprawnień). Co ważne - na żadnym z tych etapów nie mamy do czynienia bezpośrednio z hasłem użytkownika, więc metoda ta jest bezpieczna (ale oczywiście przesyłane w nagłówkach dane można wykorzystać do złamania hasła danego użytkownika, ale jest to bardzo czasochłonne zadanie - analogicznie możemy sniffować istniejący w firmie ruch sieciowy).

Przykładowa komunikacja pomiędzy przeglądarką użytkownika a serwerem IIS mająca na celu jego uwierzytelnienie przebiega według poniższego schematu:
  - klient/przeglądarka wysyła do serwera IIS żądanie otwarcia ustalonej strony www;
  - serwer IIS odpowie nagłówkiem zawierającym "401 Unauthorized" oraz "WWW-Authenticate: Negotiate";
  - klient/przeglądarka wysyła żądanie "Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFASgKAAAADw==" (message type 1);
  - serwer odpowiada nagłówkiem zawierającym "401 Unauthorized" oraz "WWW-Authenticate: Negotiate oYIBLTCCASmgAwoBAaEMBgorBgEEAYI3AgIKooIBEgSCAQ ..." (message type 2);
  - klient/przeglądarka wysyła żądanie "Authorization: Negotiate oYH8MIH5oAMKAQGigd0EgdpOVExNU1NQAAMAAAAYABgAmgAAABgAGACyAAAAEgA ... jKwcAAAAA" (message type 3);
  - możliwe odpowiedzi serwera IIS:
      "401 Unauthorized" oraz brak jest w nagłówku "WWW-Authenticate: Negotiate" - brak autoryzacji (konto nie istnieje, nie jest kontem domenowym, nie jest aktywne lub nie ma uprawnień do danego zasobu/strony www);
      "401 Unauthorized" oraz jest w nagłówku "WWW-Authenticate: Negotiate" - konieczność ponowienia autoryzacji (być może przy użyciu innego loginu - ale wymusza wtedy okienko logowania w przeglądarce);
      "200 OK" - autoryzacja użytkownika zakończona sukcesem - można z danych zawartych w nagłówku "Authorization: NTLM/Negotiate ...", wysłanym ostatnio przez przeglądarkę użytkownika, odkodować jego dane (m.in. nazwę konta i domeny oraz nazwę stacji roboczej).

Poniżej prezentuję dwie przydatne funkcje służące do odczytania bieżącego etapu (message type) uwierzytelnienia (pierwsza funkcja) oraz do zdekodowania otrzymanych danych po uwierzytelnieniu użytkownika zakończonym sukcesem (druga funkcja) - do funkcji przekazujemy (jako parametr wywołania) fragment nagłówka (ciąg) występujący po "WWW-Authenticate: Negotiate " (odpowiedź serwera) lub "Authorization: NTLM/Negotiate " (żądanie przeglądarki):
function parseNTLMSSPMessage($message)
{
  
$message=base64_decode($message);
  
$i=strpos($message,"NTLMSSP\0");
  if (
$i===false) return -1;
  return 
ord(substr($message,$i+8,1));
}

function 
decodeNTLMSSPAuthenticationData($data)
{
  
$data=base64_decode($data);
  
$i=strpos($data,"NTLMSSP\0");
  if (
$i===false) return null;
  if (
$i>0$data=substr($data,$i);
  
$domain=iconv('UTF-16LE','UTF-8',substr($data,ord(substr($data,0x20,1)),ord(substr($data,0x1c,1))));
  
$login=iconv('UTF-16LE','UTF-8',substr($data,ord(substr($data,0x28,1)),ord(substr($data,0x24,1))));
  
$host=iconv('UTF-16LE','UTF-8',substr($data,ord(substr($data,0x30,1)),ord(substr($data,0x2c,1))));
  return array(
$login,$domain,$host);
}

Powyższe funkcje nie korzystają z biblioteki Multibyte String (mb_strpos oraz mb_substr), która w tym przypadku wcale nie jest potrzebna (a dodatkowo nie zawsze jest dostępna, szczególnie w starszym środowisku). Przydatna jest natomiast funkcja iconv (też co prawda nie zawsze dostępna), służąca do zdekodowania danych w formacie UTF-16LE na format UTF-8 (lub inny, który akurat używamy w naszej aplikacji) - w prezentowanych przeze mnie skryptach wyeliminowałem tę funkcję i napisałem swoją funkcję dekodującą (o nazwie ntlm_utf16le2utf8).
Tak samo nie używam w swoich skryptach funkcji file_get_contents oraz file_put_contents (niedostępnych w starszych środowiskach PHP), zastępując je swoimi wersjami (o nazwach z przedrostkiem ntlm_). Podobnie zrobiłem z funkcją microtime, która dopiero w PHP od wersji 5.0 może zwracać czas w postaci float (zmiennoprzecinkowej).

Na potrzeby analizy zawartości przesyłanych podczas uwierzytelnienia NTLM nagłówków napisałem funkcją podobną do poniżej prezentowanej (znajduje się ona na samym końcu skryptu auth.php), zapisującą te nagłówki do lokalnego pliku debug.txt, który jest potem przetwarzany i wyświetlany w postaci czytelnej tabelki przez skrypt analyze.php:
function debug($msg)
{
  
$time=explode(' ',microtime());
  
$fp=fopen(__DIR__.'\\debug.txt','a');
  
$msg=((float)$time[1]+(float)$time[0])."\t".$msg."|";
  
fwrite($fp,$msg);
  
fclose($fp);
}

Tę funkcjonalność warto usunąć ze skryptu auth.php po jego przetestowaniu i zweryfikowaniu, że w naszym środowisku działa on poprawnie.

Istniejące ograniczenia
Jest kilka ważnych spraw, które są wymagane przez obecną wersję skryptu do uwierzytelniania NTLM - przede wszystkim w sieci lokalnej (intranecie) musi działać serwer IIS mający wbudowaną możliwość uwierzytelniania użytkowników za pomocą kont domenowych (AD) - w moim przypadku wykorzystałem istniejący w firmie serwer IIS służący do przeglądania różnego rodzaju raportów, używający właśnie takiego uwierzytelniania. Oczywistym jest, że w sieci firmowej musi też działać odpowiednio skonfigurowany serwer Active Directory, a automatyczne uwierzytelnianie użytkownika (bez konieczności podawania hasła) zadziała głównie w przeglądarkach Internet Explorer (w niektórych wersjach/konfiguracjach trzeba jeszcze wybrać odpowiedni poziom zabezpieczeń lub zaznaczyć stosowną opcję, by dało się z tej funkcji korzystać: menu Narzędzia -> Opcje internetowe -> Zabezpieczenia -> Lokalny intranet -> Poziom niestandardowy -> Uwierzytelnianie użytkownika -> Zaloguj automatycznie z bieżącą nazwą użytkownika i bieżącym hasłem). Automatyczne uwierzytelnianie działa obecnie również w innych przeglądarkach internetowych - w niektórych (Firefox z domyślną konfiguracją) pojawi się standardowe okienko logowania, gdzie trzeba podać login i hasło (ale te dane nie są przesyłane do naszego skryptu w postaci jawnej), inne zaś (np. Chrome) mają już wbudowaną i domyślnie aktywną obsługę tego typu uwierzytelniania i zadziałają analogicznie jak Internet Explorer. Aby w Firefoksie móc również używać takiego mechanizmu, należy w pasku adresu wpisać i otworzyć lokalizację "about:config", jeśli trzeba to potwierdzić chęć modyfikacji zaawansowanych ustawień programu, wpisać ciąg "network.automatic-ntlm-auth.trusted-uris" w pole wyszukiwania, otworzyć ten klucz i wpisać tam adresy url domen (oddzielone przecinkiem), które mogą korzystać z automatycznego uwierzytelniania NTLM i zatwierdzić zmiany. Adresy domen należy wpisywać w formacie "http://domena1,http://domena2,http://domena3" (bez odstępów). Szczegóły można znaleźć w artykule Enabling NTLM Authentication (Single Sign-On) in Firefox.
Program pośredniczący w komunikacji pomiędzy przeglądarką użytkownika a serwerem IIS musi nawiązywać z tym serwerem połączenie trwałe i go utrzymywać aż do końca procesu uwierzytelnienia (które w najprostszym przypadku składa się z 3 etapów), co nie jest trudne do zrealizowania przy użyciu biblioteki cURL i ustawieniu odpowiedniego nagłówka, ale wymusza użycie do tej operacji osobnego programu, ponieważ główny skrypt musi kilka razy wysłać do przeglądarki użytkownika kolejno odbierane nagłówki. Program pośredniczący może być uruchomionym cały czas procesem (trudniejsze zadanie, ponieważ wymaga uprawnień do uruchomienia na serwerze www własnego procesu), a może to być osobny skrypt uruchamiany każdorazowo przy konieczności dokonania uwierzytelnienia użytkownika (w moim przypadku jest to ten sam skrypt auth.php, uruchamiany wywołaniem go przez cURL jako osobny adres strony intranetowej). Skrypt ten musi się zatem znajdować w miejscu dostępnym do wywołania go z poziomu przeglądarki (cURL), ale jest on tak napisany, że zwykłe jego otwarcie w przeglądarce nie spowoduje żadnego działania (bo skrypt oczekuje przesłania mu jednego parametru metodą POST). Skrypt auth.php rozpoznaje, czy został uruchomiony w wyniku wywołania z poziomu przeglądarki, czy poprzez załączenie jego kodu funkcją include/require a następnie uruchomienia jego funkcji checkLogin i dzięki temu "rozwidla się" (nieco podobnie jak linuksowa funkcja fork w jezyku C/C++) wykonując dwa niezależne działania. Wywołując skrypt funkcją cURL rozwiązujemy w sprytny sposób potrzebę uruchomienia jakiegoś drugiego procesu biorącego udział w uwierzytelnianiu (tego, który bezpośrednio komunikuje się z serwerem IIS) i który nie przerwie nawiązanego z tym serwerem połączenia do czasu zakończenia procedury uwierzytelnienia.
Trzeba wziąć pod uwagę to, że może nastąpić kilkukrotne (zazwyczaj 3-krotne) przeładowanie strony (w przeglądarce użytkownika) zawierającej wywołanie żądania uwierzytelnienia NTLM - oczywiście zazwyczaj ten proces jest całkowicie niewidoczny dla użytkownika, ale jeśli jest to jakiś problem dla korzystającej z takiego uwierzytelniania aplikacji, można skorzystać z ramki IFRAME, osadzonej na takiej stronie i pośredniczącej w uwierzytelnieniu. Kod zawarty w ramce dokona tego uwierzytelnienia bez odświeżania całej strony (odświeży się sama ramka, która może być nawet niewidoczna/ukryta). Ponieważ mamy pełny dostęp do zawartości takiej ramki (po stronie użytkownika w jego przeglądarce), możemy wykrywać poprawne lub nie uwierzytelnienie kodem JavaScript (skrypty w PHP będą miały standardowy dostęp do danych uwierzytelniających, które są zapisywane w tablicy $_SESSION). Przed zakończeniem procesu uwierzytelniania (w przypadku gdy nie korzystamy z ramki IFRAME) nie wolno wyświetlić na ekranie żadnych danych HTML, bo zaburzy to ten proces (sytuacja analogiczna jak przy włączaniu obsługi sesji funkcją session_start).
Trzeba też pamiętać, że uwierzytelnienie wnosi pewne (zazwyczaj nieduże) opóźnienie i uwzględnić to w swoim programie - w przypadku konieczności podania loginu i hasła w okienku przeglądarki (nie wspierającej automatycznego uwierzytelniania), czas ten zależy od reakcji użytkownika - może się zatem okazać, że skrypt pośredniczący (uruchamiany wywołaniem cURL) zakończy wcześniej swoje działanie (upłynie zdefiniowany w stałej DEF_NTLM_MAX_EXECUTION_TIME_LIMIT czas jego maksymalnego działania lub przekroczony zostanie maksymalny czas działania skryptu dla danego środowiska PHP) i uwierzytelnienie się nie powiedzie (mimo podania poprawnych danych) - wtedy można automatycznie ponowić ten proces lub odmówić dalszego działania aplikacji i czekać na akcję użytkownika.
Kolejną kwestią jest metoda komunikacji obu programów/skryptów między sobą (tego głównego z tym pośredniczącym) - można do tego wykorzystać różne techniki, ja użyłem bardzo prostej (i możliwej do realizacji praktycznie w każdym środowisku PHP), a mianowicie komunikację poprzez plik tekstowy o ustalonej, niepowtarzalnej nazwie (którą u mnie jest id sesji), którą znają oba skrypty (ten pośredniczący otrzymuje ją od skryptu głównego podczas swojego wywołania jako parametr typu POST). Ponieważ przekazujemy między sobą tylko czysto tekstowe dane (nagłówki HTTP), to taka metoda jest szybka i prosta w zastosowaniu, a przede wszystkim nie wymaga instalacji dodatkowych modułów (minusem była konieczność napisania i przetestowania stosownych funkcji, ale taka komunikacja jest synchroniczna i o z góry znanym kierunku, więc funkcje są bardzo proste).
Napisane przeze mnie rozwiązanie zostało opracowane i przetestowane na działającym w firmie serwerze Active Directory opartym o system Windows Server 2008 R2 Standard SP1, ale może się okazać, że w innych firmach są wykorzystywane inne metody uwierzytelniania, niż te które ja przetestowałem oraz tutaj opisałem i może nastąpić konieczność dostosowania skryptu do istniejących rozwiązań. Dlatego sugeruję najpierw zbadać i przetestować, jak to wygląda u kogoś na miejscu (np. przy wykorzystaniu zaprezentowanej przeze mnie powyżej, lub podobnej, aplikacji do analizy przesyłanych nagłówków), bo być może trzeba będzie dokonać pewnych zmian w kodzie, a dopiero potem go wdrożyć.
Wszystkie funkcje, które są zdefiniowane w skrypcie auth.php (poza główną checkLogin), mają nazwy zawierające przedrostek ntlm_, żeby nie kolidować z nazwami funkcji w innych skryptach użytkownika.

Kod źródłowy skryptu
Postanowiłem opublikować swoje autorskie rozwiązanie - skrypt przeprowadzający uwierzytelnienie NTLM, wraz z dodatkowymi narzędziami, został spakowany do archiwum zip, które zawiera następujące pliki:
  auth.php - główny skrypt odpowiadający za uwierzytelnienie NTLM;
  check.php - skrypt sprawdzający środowisko i ustawienia, wykonuje wstępny test konfiguracji;
  auth2.php - specjalnie przygotowany skrypt, powstały na bazie kodu auth.php, służący do testowania poprawności działania zastosowanych przeze mnie mechanizmów komunikacji między skryptami;
  check2.php - skrypt uruchamiający prosty test działania komunikacji pomiędzy dwoma procesami/skryptami (używa do tego skryptu auth2.php);
  analyze.php - przykładowa aplikacja do analizy danych przesyłanych w nagłówkach podczas procesu uwierzytelniania NTLM (używa skryptu auth.php);
  login.php - przykładowy program korzystający ze skryptu auth.php;
  login2.php - wersja skryptu korzystająca z ramki IFRAME;
  iframe.php - przykładowy skrypt mogący zostać użyty w ramce IFRAME;
Główny skrypt auth.php zawiera na początku definicje kilku stałych, z których najważniejszą jest stała DEF_NTLM_AUTHENTICATE_URL, zdefiniowana w wierszu nr 20. Musi ona zawierać adres strony na serwerze IIS, który przeprowadza właściwe uwierzytelnianie NTLM - w moim przypadku jest to specjalna strona serwisu intranetowego, dostępna dla wszystkich użytkowników domenowych.
Aby ułatwić korzystanie z mojego rozwiązania, przygotowałem skrypt check.php, który sprawdza zastane środowisko PHP pod kątem spełniania wymogów poprawnego działania skryptu auth.php a także dokonuje podstawowe testy konfiguracji tego skryptu (między innymi pod kątem poprawnego zdefiniowania stałych, w tym najważniejszej DEF_NTLM_AUTHENTICATE_URL). Skrypt ten sprawdza poprawne działanie funkcji komunikacyjnych (bazujących na plikach tekstowych), pobierania nagłówków wysyłanych przez przeglądarkę internetową, a także pobiera nagłówki strony służącej do właściwego uwierzytelniania NTLM, której adres wskazuje stała DEF_NTLM_AUTHENTICATE_URL. Przykładowe wyniki działania tego skryptu można zobaczyć poniżej:
  sprawdzenie konfiguracji bez znalezionych błędów (PHP 4.3.0, libcurl 7.9.8);
  sprawdzenie konfiguracji z błędem braku dostępności biblioteki cURL (PHP 5.2.6-1+lenny8);
  sprawdzenie konfiguracji bez znalezionych błędów (5.2.6-1+lenny8) - użyto własnej wersji biblioteki cURL opisanej tutaj;
  sprawdzenie konfiguracji z dwoma wykrytymi błędami (PHP 5.4.7);
Dla zainteresowanych poznaniem szczegółów mechanizmu uwierzytelniania NTLM przygotowałem skrypt analyze.php, który (korzystając ze skryptu auth.php) zapisuje do pliku tekstowego wszystkie przesyłane podczas takiego uwierzytelnienia nagłówki, a następnie wyświetla je w czytelnej postaci oraz dodatkowo dekoduje i wypisuje najważniejsze dane, które są zawarte w nagłówkach WWW-Authenticate oraz Authorization. Przykładowe wyniki działania tego skryptu można zobaczyć poniżej:
  komputer z Windows XP i IE 8 (uwierzytelnienie poprawne);
  komputer z Windows 7 i IE 9 (uwierzytelnienie poprawne);
  komputer z Windows 7 i Chrome 30 (uwierzytelnienie poprawne);
  komputer z Windows 7 i Firefox 24 (uwierzytelnienie niepoprawne) - w okienku logowania specjalnie podałem błędne hasło;
  komputer z Windows 7 i Firefox 24 (uwierzytelnienie poprawne) - włączyłem automatyczne uwierzytelnienie NTLM;

Licencja
Moje rozwiązanie, tj. skrypt auth.php oraz towarzyszące mu dodatkowe programy udostępniam wszystkim na licencji Creative Commons Uznanie Autorstwa (CC-BY) - również dla zastosowań komercyjnych. Dodatkowo będę wdzięczny za wszelkie informacje o zauważonych błędach i praktycznych wdrożeniach oraz za sugestie mające na celu poprawienie i usprawnienie tego projektu.

Przydatne linki
Dla zainteresowanych tą tematyką przygotowałem kilka przydanych linków:
  Single Sign On In Windows Domains - różne rozwiąznia zintegrowania uwierzytelnienia użytkownika w oprogramowaniu Zope Plone działającego na serwerze Apache;
  Simple lightweight NTLM in PHP - opis aplikacji w PHP, która pozwala odczytać login użytkownika (ale nie uwierzytelnia go w AD);
  NTLM authentication in PHP – Now with NTLMv2 hash checking - opis modułu w PHP do uwierzytelnienia NTLMv2 w AD, ale przy jego użyciu i tak trzeba podać hasło dla danego konta użytkownika;
  NTLM Authentication Scheme for HTTP - bardzo dobry opis schematu uwierzytelniania NTLM używanego w przeglądarkach Internet Explorer i serwerach IIS;
  The NTLM Authentication Protocol and Security Support Provider - dokumentacja dotycząca uwierzytelniania NTLMSSP;
  Dokumentacja modułu NTLMConstants klasy NTLMUtilities frameworka Apache MINA napisanego w Javie;
  Prezentacja Kurta Grutzmachera na Defcon 16 opisująca uwierzytelnianie NTLM i metody jego łamania;
  Opis protokołu NTLM w angielskiej wersji Wikipedii;

Powrót do strony z wykazem projektów

Valid HTML 4.01 TransitionalValid CSS