4 kwietnia 2008

Mechanizm pojedynczego uwierzytelnienia, czyli Single Sign-On

Mechanizm pojedynczego uwierzytelnienia – czyli Single Sign-On, w skrócie SSO – to obszerny temat. Wyobraźmy sobie, że udostępniamy użytkownikom wiele odrębnych aplikacji, z których każda wymaga uwierzytelnienia. Czy nie byłoby dobrze, gdyby dało się używać ich wszystkich podając swój identyfikator i hasło (albo inne dane uwierzytelniające) tylko jednokrotnie? Z pewnością wygodniej niż gdybyśmy mieli to robić dla każdej aplikacji z osobna.

W dzisiejszym artykule opiszę swą wizję SSO dla środowiska złożonego z aplikacji WWW. SSO nie żyje jednak w próżni i same dla siebie, przeciwnie, jest częścią ogólnej architektury bezpieczeństwa dla systemów klasy korporacyjnej (ang. enterprise). Przynajmniej ja tak to widzę i tak też o SSO będę pisał. Zacznijmy od spojrzenia na poniższy diagram ilustrujący proces uwierzytelnienia i pokazujący kluczowe komponenty.




Na szczególną uwagę zasługuje komponent nazwany na powyższym diagramie serwerem bezpieczeństwa. Otóż mój pomysł na implementacje kompleksowego systemu bezpieczeństwa dla przedsiębiorstwa polega na tym, że wszystkie decyzje dotyczące bezpieczeństwa, tj. autoryzacja i uwierzytelnienie podejmowane są przez wyspecjalizowany komponent/serwer, nie przez każdą z aplikacji z osobna. Nie jest więc tak, że na potrzeby autoryzacji aplikacje pobierają listę ról przypisanych do bieżącej tożsamości i konfrontują tą listę z rolami przypisanymi do danego zasobu. Aplikacje wysyłają do serwera bezpieczeństwa zapytanie autoryzacyjne podając identyfikatory zasobów i identyfikator kontekstu a to serwer podejmuje decyzje na podstawie sobie tylko znanych kryteriów. Przede wszystkim, nie wydaje mi się być dobrym pomysłem zaszywanie w aplikacji informacji o związku zasobów z rolami. Ale jest to dyskusja na oddzielny artykuł. Wróćmy do SSO.

Filtr weryfikacji tożsamości to filtr servletowy, który sprawdza czy w żądaniu HTTP zostało przekazane ciasteczko o odpowiedniej nazwie. Jeśli ciasteczko jest dostępne to pobiera z niego identyfikator kontekstu bezpieczeństwa i przekazuje go do aplikacji, np. jako atrybut żądania HTTP (ang. HTTP request). Ewentualnie, filtr może uprzednio wywołać funkcję weryfikacji identyfikatora udostępnianą przez serwer bezpieczeństwa. Aplikacja (a dokładnie jej moduł autoryzacji) wysyła do serwera bezpieczeństwa zapytanie o autoryzację dostępu dla żądanego zasobu i identyfikatora kontekstu. Na podstawie wyniku podejmuje odpowiednie kroki – zwraca żądany zasób lub komunikat błędu. Serwer bezpieczeństwa pobiera z kontekstu dane o uwierzytelnionej tożsamości i przypisanych jej rolach. Zasoby opisane są odpowiednimi identyfikatorami. Jeśli role przypisane do uwierzytelnionej tożsamości zezwalają na uzyskanie dostępu do opisanego zasobu serwer udziela odpowiedzi pozytywnej. Oczywiście, jeśli przekazany do serwera bezpieczeństwa identyfikator kontekstu nie identyfikuje poprawnie żadnego kontekstu zwracany jest komunikat błędu. Serwer bezpieczeństwa może również odpowiedzieć, że użytkownik ma prawo do uzyskania dostępu, ale pod jakimś określonym warunkiem, np. podania poprawnego hasła jednorazowego.

Jeśli filtr weryfikacji tożsamości nie znajdzie w żądaniu odpowiedniego ciasteczka HTTP, to uruchomiona zostaje procedura uwierzytelniania. Rozpoczyna się ona przekierowaniem do aplikacji uwierzytelniającej. Żądania skierowane do tej aplikacji są filtrowane przez kolejny filtr servletowy – filtr uwierzytelniający. To właśnie ten filtr wykonuje główną pracę. Sprawdza on, czy w żądaniu HTTP znajdują się odpowiednie parametry, tj. identyfikator użytkownika i hasło. Jeśli tak, to są one weryfikowane, jeśli nie, to żądanie jest przekazywane do aplikacji uwierzytelniającej – wyświetlana jest w przeglądarce strona z formularzem uwierzytelniania. Po wypełnieniu i wysłaniu formularza żądanie znowu trafia do filtra. Identyfikator użytkownika i hasło są weryfikowane z użyciem serwera bezpieczeństwa. Poprawna weryfikacja powoduje utworzenie na tym serwerze kontekstu (sesji) bezpieczeństwa. Odsyłany jest identyfikator tego kontekstu. Filtr uwierzytelniający przekierowuje z powrotem do oryginalnie żądanego zasobu ustawiając jednocześnie ciasteczko z identyfikatorem utworzonego kontekstu. Od tej pory filtr weryfikacji tożsamości, niezależnie od tego, jaką aplikację zabezpiecza będzie posiadał prawidłowe informacje o uwierzytelnionym użytkowniku. Tym oto sposobem otrzymujemy efekt uwierzytelnienia do pracy z przeglądarką, niezależnie od tego, jaką aplikację w tej przeglądarce aktualnie użytkujemy – oczywiście pod warunkiem, że wszystkie one używają tej samej infrastruktury bezpieczeństwa. Implementacja opisanych tu mechanizmów już wkrótce – oczywiście, jak nie zabraknie czasu i zapału.

11 komentarzy:

Unknown pisze...

Gratuluję wyboru! Bezpieczeństwo i jego realizacja w Javie zawsze były moją piętą achillesową, więc teraz śledząc Twoje poczynania będę mógł nabrać większej pewności siebie w temacie. Już nie mogę doczekać się kolejnych wpisów odnośnie JAAS, JACC, JASPI czy podobnie. Chyba nie myślałeś, że wystarczy mi rysunek poglądowy i kilka zdań. Potrzebuję więcej! ;-)

Jacek
http://www.jaceklaskowski.pl

Mariusz Lipiński pisze...

Jestem żywo zainteresowany bezpieczeństwem, więc zdecydowanie będę drążył temat, aczkolwiek jak to ja - robie wiele rzeczy równolegle - więc pewnie kolejne artykuły nie będą spływały lawinowo :) Swoją drogą Jacku, znając twoje zamiłowanie do wszystkiego co pochodzi od SUN'a mógłbyś próbować wyprzedzić mnie z tematami typu JAAS do czego gorąco cię zachęcam!

Łukasz Lenart pisze...

Korzystając z ciasteczek HTTP musisz pamiętać, że przeglądarka przesyła ciasteczka przypisane tylko dla danej domeny. Więc wszystkie aplikacje muszą być postawione na tym samym serwerze, lub znajdować się za tym samym proxem ;-)
Ostatnio dostałem informację o takim to systemie http://www.ja-sig.org/products/cas/
Najlepsze jest to, że nie ogranicza się tylko do Javy, ale również obsługuje PHP, Perl, etc.
I ponoć to działa...

Jeśli nie chcesz zaszywać ról i ich powiązań w aplikacji, to możesz użyć Acegi i podejścia deklaratywnego lub programowania aspektowego. Gdyż dostęp do zasobu to jeden z aspektów bezpieczeństwa, dość często zmienia się logika aplikacji, czy też flow w zależności, kto jest zalogowany ;-)

Mariusz Lipiński pisze...

Tak, o CAS'ie wiem, ale zdecydowanie będę musiał się mu jeszcze bliżej przyjrzeć... kto wie, może jeden z kolejnych artykułów?

Natomiast co do Acegi i deklaratywnego przypisywania ról do zasobów w pliku XML zaszytym w aplikacji... chyba już widać co na ten temat myślę. Owszem, jest dużo lepiej niż gdybym miał robić jakieś if'y w kodzie, ale nadal nie jest to to czego bym chciał. Aczkolwiek Acegi również wymaga głębszego rozpoznania.

Janek pisze...

Gdyby mnie ktos poprosil o takie rozwiazanie to pewnie wskazalbym WebSeal'a
Janek

Mariusz Lipiński pisze...

Ale czy WebSeal to czasem nie jest reverse proxy, a co za tym idzie umożliwia tylko i wyłącznie zabezpieczenie zasobów identyfikowanych przez URL'e? Tj. da się zaimplementować autoryzacje dla konkretnych stron .jsp, ale do konkretnych jej fragmentów już nie. Popraw mnie, jeśli się mylę.

Pozdr. Mariusz

Janek pisze...

Mariusz,
WebSeal dziala jako security proxy, ale oprocz tego przesyla dodatkowe naglowki do docelowej aplikacji,które pozwalają na identyfikację osoby i zastosowanie dodatkowej autoryzacji. Pare słów o tym: http://www.ibm.com/developerworks/websphere/techjournal/0406_singh/0406_singh.html

z innych artykułów o WebSeal polecam także : http://www.ibm.com/developerworks/tivoli/library/t-webseal/

Warto wiedzieć, że w WAS można uzyskac efekt SSO poprzez wykorzystanie tokenów LTPA:
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/topic/com.ibm.websphere.nd.multiplatform.doc/info/ae/ae/csec_sso.html

WebSphere wspiera rowniez SPNEGO - czyli jesli ktos sie zaloguje na stacji Windowsowej to nie bedzie juz sie musial logowac do aplikacji webowych.
Sądzę,też, że warto pamiętać, że autentykacja i autoryzacja to są rozdzielne tematy. Czasami np. może być konieczność przesłania informacji o użytkowniku aż do systemów wewnętrznych, które podejmą decyzje czy dana osoba ma prawo dosŧpu do danych.
Pozdrawiam

Mariusz Lipiński pisze...

Wszystkie tematy które poruszyłeś są niezmiernie ciekawe. Może chciałbyś zaprezentować te technologie szerszemu gronu? Może na spotkaniach Warszawa JUG? Myślę, że chętnych do wysłuchania prezentacji byłoby bardzo wielu.

Pozdr. Mariusz

Paweł pisze...

tylko prosze nie autentykacja :) uwierzytelnienie

jestem wielkim przeciwnikiem wymyslania tlumaczen polskich ( co kocha Jacek Laskowski), ale jak juz tez mamy zakorzeniony odpowiednik polski to uzywajmy go.

wiec albo authorization, albo uwierzytelnienie, ale nie autentykacja.


to tak jak ostanio slyszalem ze "w Springu uzywa sie mechanizmu dependencjiiii"


pozdr.


ps. CAS jest milym narzeedziem, zwlaszcza jesli zaczynasz mieszac m w kodzie, ktory jest w miare czytelny

Paweł pisze...

authorization mialo byc authentication...

Unknown pisze...

Widać, że niektórzy są w malinach jeśli chodzi o temat bezpieczeństwa :)

Mieszacie dwa różne pojęcia:
Autentykacja i autoryzacja.

Autentykacja - to weryfikacja czy użytkownik jest tym za kogo się podaje.

autoryzacja - weryfikacja czy posiada określone uprawnienia wymagane przy dostępie do zasobu.