JavaRush /Blog Java /Random-PL /JAAS – Wprowadzenie do technologii (część 1)
Viacheslav
Poziom 3

JAAS – Wprowadzenie do technologii (część 1)

Opublikowano w grupie Random-PL
Bezpieczeństwo dostępu jest wdrażane w Javie już od dłuższego czasu, a architektura zapewniająca to bezpieczeństwo nosi nazwę JAAS - Java Authentication and Authorization Service. W tej recenzji spróbujemy rozwikłać tajemnicę, czym jest uwierzytelnianie, autoryzacja i co ma z tym wspólnego JAAS. Jak JAAS zaprzyjaźnia się z Servlet API i gdzie występują problemy w ich relacjach.
JAAS – Wprowadzenie do technologii (Część 1) – 1

Wstęp

W tej recenzji chciałbym poruszyć taki temat jak bezpieczeństwo aplikacji internetowych. Java ma kilka technologii zapewniających bezpieczeństwo: Ale nasza dzisiejsza rozmowa będzie dotyczyć innej technologii, która nazywa się „Usługą uwierzytelniania i autoryzacji Java (JAAS)”. To ona opisuje tak ważne rzeczy, jak uwierzytelnianie i autoryzacja. Przyjrzyjmy się temu bardziej szczegółowo.
JAAS – Wprowadzenie do technologii (Część 1) – 2

JAAS

JAAS jest rozszerzeniem Java SE i jest opisany w Przewodniku po usłudze uwierzytelniania i autoryzacji Java (JAAS) . Jak sugeruje nazwa technologii, JAAS opisuje, w jaki sposób należy przeprowadzać uwierzytelnianie i autoryzację:
  • Uwierzytelnienie ”: W tłumaczeniu z języka greckiego „authentikos” oznacza „prawdziwy, autentyczny”. Oznacza to, że uwierzytelnianie jest testem autentyczności. Że ktokolwiek jest uwierzytelniany, jest naprawdę tym, za kogo się podaje.

  • Upoważnienie ”: przetłumaczone z języka angielskiego oznacza „pozwolenie”. Oznacza to, że autoryzacja to kontrola dostępu przeprowadzana po pomyślnym uwierzytelnieniu.

Oznacza to, że JAAS polega na określeniu, kto żąda dostępu do zasobu i podjęciu decyzji, czy może uzyskać ten dostęp. Mała analogia z życia: jedziesz drogą i zatrzymuje cię inspektor. Proszę o dostarczenie dokumentów - uwierzytelnienie. Czy można prowadzić samochód mając dokumenty - uprawnienia. Lub na przykład chcesz kupić alkohol w sklepie. Najpierw zostaniesz poproszony o paszport - uwierzytelnienie. Następnie, na podstawie Twojego wieku, zapada decyzja, czy możesz kupić alkohol. To jest autoryzacja. W aplikacjach webowych uwierzytelnieniem jest zalogowanie się jako użytkownik (wpisanie nazwy użytkownika i hasła). Określenie, które strony można otworzyć, zależy od autoryzacji. W tym właśnie pomaga nam „Usługa uwierzytelniania i autoryzacji Java (JAAS)”. Rozważając JAAS, ważne jest, aby zrozumieć kilka kluczowych pojęć opisanych przez JAAS: przedmiot, zleceniodawcy, referencje. Temat jest przedmiotem uwierzytelnienia. Oznacza to, że jest nosicielem lub posiadaczem praw. W dokumentacji Temat definiuje się jako źródło żądania wykonania jakiejś akcji. Temat lub źródło musi być w jakiś sposób opisane i w tym celu używa się zleceniodawcy, który w języku rosyjskim jest czasami nazywany także zleceniodawcą. Oznacza to, że każdy pryncypał jest reprezentacją podmiotu z pewnego punktu widzenia. Żeby było jaśniej, podamy przykład: Pewna osoba jest Podmiotem. Następujące osoby mogą pełnić funkcję zleceniodawców:
  • jego prawo jazdy jako reprezentacja osoby jako użytkownika drogi
  • paszportu, jako reprezentację osoby jako obywatela swojego kraju
  • paszport zagraniczny, jako reprezentacja osoby jako uczestnika stosunków międzynarodowych
  • jego kartę biblioteczną w bibliotece, jako reprezentację osoby jako czytelnika dołączonej do biblioteki
Dodatkowo Podmiot posiada zestaw „Credential”, co w języku angielskim oznacza „tożsamość”. W ten sposób Podmiot potwierdza, że ​​jest sobą. Na przykład hasłem użytkownika może być Poświadczenie. Lub dowolny przedmiot, za pomocą którego użytkownik może potwierdzić, że to naprawdę on. Zobaczmy teraz, jak JAAS jest używany w aplikacjach internetowych.
JAAS – Wprowadzenie do technologii (Część 1) – 3

Aplikacja internetowa

Potrzebujemy więc aplikacji internetowej. Pomoże nam w jego stworzeniu system automatycznego budowania projektów Gradle. Dzięki zastosowaniu Gradle możemy wykonując małe polecenia złożyć projekt Java w potrzebnym nam formacie, automatycznie utworzyć niezbędną strukturę katalogów i wiele więcej. Więcej o Gradle możesz przeczytać w krótkim przeglądzie: „ Krótkie wprowadzenie do Gradle ” lub w oficjalnej dokumentacji „ Gradle Pierwsze kroki ”. Musimy zainicjalizować projekt (Inicjalizacja) i w tym celu Gradle ma specjalną wtyczkę: „ Gradle Init Plugin ” (Init to skrót od Inicjalizacja, łatwy do zapamiętania). Aby użyć tej wtyczki, uruchom polecenie w wierszu poleceń:
gradle init --type java-application
Po pomyślnym zakończeniu będziemy mieli projekt Java. Otwórzmy teraz skrypt kompilacji naszego projektu do edycji. Skrypt kompilacji to plik o nazwie build.gradle, który opisuje niuanse kompilacji aplikacji. Stąd nazwa, skrypt kompilacji. Można powiedzieć, że jest to skrypt budujący projekt. Gradle to takie wszechstronne narzędzie, którego podstawowe możliwości rozszerzane są za pomocą wtyczek. Dlatego przede wszystkim zwróćmy uwagę na blok „wtyczek”:
plugins {
    id 'java'
    id 'application'
}
Domyślnie Gradle, zgodnie z tym, co określiliśmy „ --type java-application”, skonfigurował zestaw kilku podstawowych wtyczek, to znaczy tych wtyczek, które są zawarte w dystrybucji samego Gradle. Jeżeli przejdziemy do sekcji „Dokumenty” (czyli dokumentacja) na stronie gradle.org , to po lewej stronie listy tematów w sekcji „Referencje” zobaczymy sekcję „ Core Plugins ”, czyli: sekcję z opisem tych bardzo podstawowych wtyczek. Wybierzmy dokładnie te wtyczki, których potrzebujemy, a nie te, które wygenerował dla nas Gradle. Zgodnie z dokumentacją „ Gradle Java Plugin ” zapewnia podstawowe operacje na kodzie Java, takie jak kompilacja kodu źródłowego. Ponadto zgodnie z dokumentacją „ wtyczka aplikacji Gradle ” udostępnia nam narzędzia do pracy z „wykonywalną aplikacją JVM”, tj. z aplikacją Java, którą można uruchomić jako samodzielną aplikację (na przykład aplikację konsolową lub aplikację z własnym interfejsem użytkownika). Okazuje się, że wtyczka „aplikacja” jest nam zbędna, bo… nie potrzebujemy samodzielnej aplikacji, potrzebujemy aplikacji internetowej. Usuńmy to. Jak również ustawienie „mainClassName”, które jest znane tylko tej wtyczce. Ponadto w tej samej sekcji „ Pakowanie i dystrybucja ”, w której podano łącze do dokumentacji wtyczki aplikacji, znajduje się łącze do wtyczki Gradle War. Wtyczka Gradle War , jak podano w dokumentacji, zapewnia obsługę tworzenia aplikacji internetowych Java w formacie wojennym. W formacie WAR oznacza, że ​​zamiast archiwum JAR zostanie utworzone archiwum WAR. Wydaje się, że właśnie tego nam potrzeba. Ponadto, jak mówi dokumentacja, „Wtyczka War rozszerza wtyczkę Java”. Oznacza to, że możemy zastąpić wtyczkę Java wtyczką war. Dlatego nasz blok wtyczek będzie ostatecznie wyglądał następująco:
plugins {
    id 'war'
}
Również w dokumentacji „Gradle War Plugin” jest powiedziane, że wtyczka wykorzystuje dodatkowy „Układ projektu”. Układ jest tłumaczony z języka angielskiego jako lokalizacja. Oznacza to, że wtyczka wojenna domyślnie oczekuje istnienia określonej lokalizacji plików, których będzie używać do swoich zadań. Będzie używać następującego katalogu do przechowywania plików aplikacji internetowych: src/main/webapp Zachowanie wtyczki opisano w następujący sposób:
JAAS – Wprowadzenie do technologii (część 1) – 4
Oznacza to, że wtyczka uwzględni pliki z tej lokalizacji podczas budowania archiwum WAR naszej aplikacji internetowej. Ponadto dokumentacja wtyczki Gradle War Plugin mówi, że ten katalog będzie „rootem archiwum”. I już w nim możemy stworzyć katalog WEB-INF i dodać tam plik web.xml. Co to za plik? web.xml- jest to „Deskryptor wdrożenia” lub „deskryptor wdrożenia”. Jest to plik opisujący sposób skonfigurowania naszej aplikacji webowej do działania. Plik ten określa, jakie żądania będzie obsługiwać nasza aplikacja, ustawienia zabezpieczeń i wiele więcej. W swej istocie jest nieco podobny do pliku manifestu z pliku JAR (zobacz „ Praca z plikami manifestu: podstawy ”). Plik Manifest informuje, jak pracować z aplikacją Java (tj. archiwum JAR), a plik web.xml informuje, jak pracować z aplikacją internetową Java (tj. archiwum WAR). Sama koncepcja „deskryptora wdrożenia” nie powstała sama, ale została opisana w dokumencie „ Specyfikacja API serwletu”". Każda aplikacja internetowa Java zależy od tego "Servlet API". Ważne jest, aby zrozumieć, że jest to API - to znaczy jest to opis jakiejś umowy interakcji. Aplikacje internetowe nie są aplikacjami niezależnymi. Działają na serwerze WWW , która zapewnia komunikację sieciową z użytkownikami. Czyli serwer www to swego rodzaju „kontener” na aplikacje webowe. Jest to logiczne, bo chcemy napisać logikę aplikacji webowej, czyli jakie strony zobaczy użytkownik i w jaki sposób powinny reagować na działania użytkownika. A my nie chcemy pisać kodu, w jaki sposób wiadomość zostanie wysłana do użytkownika, w jaki sposób będą przesyłane bajty informacji i inne rzeczy niskiego poziomu i bardzo wymagające pod względem jakości. Poza tym, okazuje się, że aplikacje internetowe są różne, ale transfer danych jest taki sam. Oznacza to, że milion programistów musiałoby w kółko pisać kod w tym samym celu. Zatem serwer WWW jest odpowiedzialny za część interakcji użytkownika i wymianę danych, a za generowanie tych danych odpowiedzialna jest aplikacja internetowa i jej programista. A żeby połączyć te dwie części, tj. serwer WWW i aplikacja internetowa, na ich interakcję potrzebna jest umowa, czyli tzw. jakich zasad będą się trzymać, aby to zrobić? Aby w jakiś sposób opisać umowę, jak powinna wyglądać interakcja pomiędzy aplikacją internetową a serwerem WWW, wymyślono Servlet API. Co ciekawe, nawet jeśli używasz frameworków takich jak Spring, pod maską nadal działa API serwletów. Oznacza to, że używasz Springa, a Spring współpracuje z Servlet API za Ciebie. Okazuje się, że nasz projekt aplikacji internetowej musi opierać się na Servlet API. W tym przypadku API serwletu będzie zależnością. Jak wiemy, Gradle pozwala także na opisanie zależności projektu w sposób deklaratywny. Wtyczki opisują sposób zarządzania zależnościami. Na przykład wtyczka Java Gradle wprowadza metodę zarządzania zależnościami „testImplementation”, która mówi, że taka zależność jest potrzebna tylko do testów. Ale wtyczka Gradle War dodaje metodę zarządzania zależnościami „providedCompile”, która mówi, że taka zależność nie zostanie uwzględniona w archiwum WAR naszej aplikacji internetowej. Dlaczego nie umieścimy interfejsu API serwletu w naszym archiwum WAR? Ponieważ Servlet API zostanie dostarczony do naszej aplikacji internetowej przez sam serwer WWW. Jeśli serwer WWW udostępnia interfejs API serwletów, wówczas serwer nazywany jest kontenerem serwletów. Dlatego też serwer WWW jest odpowiedzialny za udostępnienie nam Servlet API, a naszym obowiązkiem jest udostępnienie ServletAPI tylko w momencie kompilacji kodu. Dlatego providedCompile. Zatem blok zależności będzie wyglądał następująco:
dependencies {
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
    testImplementation 'junit:junit:4.12'
}
Wróćmy więc do pliku web.xml. Domyślnie Gradle nie tworzy żadnego deskryptora wdrożenia, więc musimy to zrobić sami. Stwórzmy katalog src/main/webapp/WEB-INF, a w nim utworzymy plik XML o nazwie web.xml. Otwórzmy teraz samą „Specyfikację serwletu Java” i rozdział „ ROZDZIAŁ 14 Deskryptor wdrażania ”. Jak stwierdzono w „14.3 Deskryptor wdrażania”, dokument XML deskryptora wdrożenia jest opisany przez schemat http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd . Schemat XML opisuje, z jakich elementów może składać się dokument i w jakiej kolejności powinny się one pojawiać. Które są obowiązkowe, a które nie. Ogólnie opisuje strukturę dokumentu i pozwala sprawdzić, czy dokument XML jest poprawnie skomponowany. Posłużmy się teraz przykładem z rozdziału „ 14.5 Przykłady ”, ale schemat musi być określony dla wersji 3.1, tj.
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd
Nasz pusty web.xmlbędzie wyglądał tak:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <display-name>JAAS Example</display-name>
</web-app>
Opiszmy teraz serwlet, który będziemy chronić za pomocą JAAS. Wcześniej Gradle generował dla nas klasę App. Zamieńmy go w serwlet. Jak stwierdzono w specyfikacji w „ ROZDZIAŁ 2 Interfejs serwletu ”, że „ W większości zastosowań programiści będą rozszerzać HttpServlet w celu implementacji swoich serwletów ”, to znaczy, aby uczynić klasę serwletem, należy dziedziczyć tę klasę z HttpServlet:
public class App extends HttpServlet {
	public String getGreeting() {
        return "Secret!";
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print(getGreeting());
    }
}
Jak powiedzieliśmy, Servlet API to umowa pomiędzy serwerem a naszą aplikacją internetową. Umowa ta pozwala nam opisać, że gdy użytkownik skontaktuje się z serwerem, serwer wygeneruje żądanie od użytkownika w postaci obiektu HttpServletRequesti przekaże je do serwletu. Udostępni także serwletowi obiekt, HttpServletResponsedzięki czemu będzie mógł napisać do niego odpowiedź dla użytkownika. Po zakończeniu działania serwletu serwer będzie mógł na jego podstawie udzielić użytkownikowi odpowiedzi HttpServletResponse. Oznacza to, że serwlet nie komunikuje się bezpośrednio z użytkownikiem, a jedynie z serwerem. Aby serwer wiedział, że mamy serwlet i do jakich żądań ma zostać użyty, musimy poinformować o tym serwer w deskryptorze wdrażania:
<servlet>
	<servlet-name>app</servlet-name>
	<servlet-class>jaas.App</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>app</servlet-name>
	<url-pattern>/secret</url-pattern>
</servlet-mapping>
W takim przypadku wszystkie żądania /secretnie będą kierowane do naszego jednego serwletu po nazwie app, która odpowiada klasie jaas.App. Jak powiedzieliśmy wcześniej, aplikację internetową można wdrożyć tylko na serwerze internetowym. Serwer WWW można zainstalować osobno (samodzielnie). Jednak na potrzeby tej recenzji odpowiednia jest alternatywna opcja - działanie na serwerze wbudowanym. Oznacza to, że serwer zostanie utworzony i uruchomiony programowo (wtyczka zrobi to za nas), a jednocześnie zostanie na nim wdrożona nasza aplikacja internetowa. System kompilacji Gradle umożliwia użycie wtyczki „ Gradle Gretty Plugin ” do następujących celów:
plugins {
    id 'war'
    id 'org.gretty' version '2.2.0'
}
Dodatkowo wtyczka Gretty ma dobrą dokumentację . Zacznijmy od tego, że wtyczka Gretty umożliwia przełączanie pomiędzy różnymi serwerami WWW. Jest to opisane bardziej szczegółowo w dokumentacji: „ Przełączanie pomiędzy kontenerami serwletów ”. Przejdźmy do Tomcata, bo... jest jednym z najpopularniejszych w użyciu, a także posiada dobrą dokumentację oraz wiele przykładów i analizowanych problemów:
gretty {
    // Переключаемся с дефолтного Jetty на Tomcat
    servletContainer = 'tomcat8'
    // Укажем Context Path, он же Context Root
    contextPath = '/jaas'
}
Teraz możemy uruchomić „gradle appRun”, a wtedy nasza aplikacja internetowa będzie dostępna pod adresem http://localhost:8080/jaas/secret
JAAS – Wprowadzenie do technologii (Część 1) – 5
Ważne jest, aby sprawdzić, czy Tomcat wybrał kontener serwletu (patrz #1) i sprawdzić, pod jakim adresem dostępna jest nasza aplikacja internetowa (patrz #2).
JAAS – Wprowadzenie do technologii (część 1) – 6

Uwierzytelnianie

Ustawienia uwierzytelniania często składają się z dwóch części: ustawień po stronie serwera i ustawień po stronie aplikacji internetowej działającej na tym serwerze. Ustawienia zabezpieczeń aplikacji internetowej nie mogą nie wchodzić w interakcję z ustawieniami zabezpieczeń serwera internetowego, choćby z innego powodu niż to, że aplikacja internetowa nie może nie wchodzić w interakcję z serwerem internetowym. Nie na próżno przeszliśmy na Tomcata, bo... Tomcat ma dobrze opisaną architekturę (patrz „ Architektura Apache Tomcat 8 ”). Z opisu tej architektury jasno wynika, że ​​Tomcat, jako serwer WWW, reprezentuje aplikację internetową jako pewien kontekst, który nazywany jest „ Kontekstem Tomcat ”. Ten kontekst pozwala każdej aplikacji internetowej mieć własne ustawienia, odizolowane od innych aplikacji internetowych. Dodatkowo aplikacja internetowa może mieć wpływ na ustawienia tego kontekstu. Elastyczny i wygodny. Aby uzyskać głębsze zrozumienie, zalecamy przeczytanie artykułu „ Zrozumienie kontenerów kontekstowych Tomcat ” i sekcji dokumentacji Tomcat „ Kontener kontekstowy ”. Jak wspomniano powyżej, nasza aplikacja internetowa może wpływać na kontekst Tomcat naszej aplikacji za pomocą pliku /META-INF/context.xml. Jednym z bardzo ważnych ustawień, na które możemy wpływać, są Security Realms. Security Realms to swego rodzaju „obszar bezpieczeństwa”. Obszar, dla którego określono określone ustawienia zabezpieczeń. W związku z tym, korzystając ze Dziedziny Bezpieczeństwa, stosujemy ustawienia bezpieczeństwa określone dla tej Dziedziny. Security Realms zarządzane są poprzez kontener, tj. serwer WWW, a nie nasza aplikacja internetowa. Możemy jedynie powiedzieć serwerowi, jaki zakres bezpieczeństwa należy rozszerzyć na naszą aplikację. Dokumentacja Tomcat w sekcji „ Komponent Realm ” opisuje dziedzinę jako zbiór danych o użytkownikach i ich rolach służących do przeprowadzania uwierzytelniania. Tomcat udostępnia zestaw różnych implementacji Security Realm, z których jedną jest „ Jaas Realm ”. Po zrozumieniu odrobiny terminologii, opiszemy kontekst Tomcat w pliku /META-INF/context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Realm className="org.apache.catalina.realm.JAASRealm"
           appName="JaasLogin"
           userClassNames="jaas.login.UserPrincipal"
           roleClassNames="jaas.login.RolePrincipal"
           configFile="jaas.config" />
</Context>
appName- Nazwa aplikacji. Tomcat spróbuje dopasować tę nazwę do nazw określonych w pliku configFile. configFile- jest to "plik konfiguracyjny logowania". Przykład tego można zobaczyć w dokumentacji JAAS: „ Załącznik B: Przykładowe konfiguracje logowania ”. Dodatkowo ważne jest, aby ten plik był najpierw przeszukiwany w zasobach. Dlatego nasza aplikacja internetowa może sama udostępnić ten plik. Atrybuty userClassNamesi roleClassNameszawierają wskazanie klas reprezentujących podmiot główny użytkownika. JAAS oddziela pojęcia „użytkownika” i „roli” jako dwa różne pojęcia java.security.Principal. Opiszmy powyższe klasy. Stwórzmy najprostszą implementację dla użytkownika głównego:
public class UserPrincipal implements Principal {
    private String name;
    public UserPrincipal(String name) {
        this.name = name;
    }
    @Override
    public String getName() {
        return name;
    }
}
Powtórzymy dokładnie tę samą implementację dla RolePrincipal. Jak widać z interfejsu, najważniejszą rzeczą dla zleceniodawcy jest przechowywanie i zwracanie nazwy (lub identyfikatora) reprezentującej zleceniodawcę. Mamy teraz Królestwo Bezpieczeństwa, mamy główne klasy. Pozostaje wypełnić plik z configFileatrybutu „ ”, czyli login configuration file. Jego opis można znaleźć w dokumentacji Tomcata: „ The Realm Component ”.
JAAS – Wprowadzenie do technologii (część 1) – 7
Oznacza to, że możemy umieścić ustawienie JAAS Login Config w zasobach naszej aplikacji internetowej i dzięki Tomcat Context będziemy mogli z niego skorzystać. Plik ten musi być dostępny jako zasób dla ClassLoader, więc jego ścieżka powinna wyglądać następująco: \src\main\resources\jaas.config Ustawmy zawartość tego pliku:
JaasLogin {
    jaas.login.JaasLoginModule required debug=true;
};
Warto zauważyć, że context.xmlta sama nazwa jest używana tutaj i w. Spowoduje to mapowanie obszaru zabezpieczeń na moduł logowania. Zatem kontekst Tomcat powiedział nam, które klasy reprezentują podmioty główne, a także jakiego modułu LoginModule użyć. Wszystko, co musimy zrobić, to zaimplementować ten LoginModule. LoginModule jest prawdopodobnie jedną z najciekawszych rzeczy w JAAS. Oficjalna dokumentacja pomoże nam w opracowaniu LoginModule: „ Usługa uwierzytelniania i autoryzacji Java (JAAS): Przewodnik programisty LoginModule ”. Zaimplementujmy moduł logowania. Stwórzmy klasę implementującą interfejs LoginModule:
public class JaasLoginModule implements LoginModule {
}
Najpierw opisujemy metodę inicjalizacji LoginModule:
private CallbackHandler handler;
private Subject subject;
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, <String, ?> sharedState, Map<String, ?> options) {
	handler = callbackHandler;
	this.subject = subject;
}
Metoda ta pozwoli zapisać plik Subject, który będziemy dalej uwierzytelniać i wypełniać informacjami o zleceniodawcy. Zachowamy także do wykorzystania w przyszłości CallbackHandlerto, co zostało nam dane. Z pomocą CallbackHandlermożemy nieco później poprosić o różne informacje na temat podmiotu uwierzytelnienia. Więcej na ten temat można przeczytać CallbackHandlerw odpowiedniej sekcji dokumentacji: „ Przewodnik referencyjny JAAS: CallbackHandler ”. Następnie wykonywana jest metoda loginuwierzytelniania Subject. To jest pierwsza faza uwierzytelniania:
@Override
public boolean login() throws LoginException {
	// Добавляем колбэки
	Callback[] callbacks = new Callback[2];
	callbacks[0] = new NameCallback("login");
	callbacks[1] = new PasswordCallback("password", true);
	// При помощи колбэков получаем через CallbackHandler логин и пароль
	try {
		handler.handle(callbacks);
		String name = ((NameCallback) callbacks[0]).getName();
		String password = String.valueOf(((PasswordCallback) callbacks[1]).getPassword());
		// Далее выполняем валидацию.
		// Тут просто для примера проверяем определённые значения
		if (name != null && name.equals("user123") && password != null && password.equals("pass123")) {
			// Сохраняем информацию, которая будет использована в методе commit
			// Не "пачкаем" Subject, т.к. не факт, что commit выполнится
			// Для примера проставим группы вручную, "хардkodно".
			login = name;
			userGroups = new ArrayList<String>();
			userGroups.add("admin");
			return true;
		} else {
			throw new LoginException("Authentication failed");
		}
	} catch (IOException | UnsupportedCallbackException e) {
		throw new LoginException(e.getMessage());
	}
}
Ważne jest, abyśmy loginnie zmieniali pliku Subject. Zmiany takie powinny nastąpić jedynie w metodzie potwierdzenia commit. Następnie musimy opisać metodę potwierdzania udanego uwierzytelnienia:
@Override
public boolean commit() throws LoginException {
	userPrincipal = new UserPrincipal(login);
	subject.getPrincipals().add(userPrincipal);
	if (userGroups != null && userGroups.size() > 0) {
		for (String groupName : userGroups) {
			rolePrincipal = new RolePrincipal(groupName);
			subject.getPrincipals().add(rolePrincipal);
		}
	}
	return true;
}
Oddzielenie metody logini commit. Ale chodzi o to, że moduły logowania można łączyć. Aby uwierzytelnienie przebiegło pomyślnie, może być konieczne pomyślne działanie kilku modułów logowania. I tylko jeśli wszystkie niezbędne moduły zadziałały, zapisz zmiany. To drugi etap uwierzytelniania. Zakończmy metodami aborti logout:
@Override
public boolean abort() throws LoginException {
	return false;
}
@Override
public boolean logout() throws LoginException {
	subject.getPrincipals().remove(userPrincipal);
	subject.getPrincipals().remove(rolePrincipal);
	return true;
}
Metoda abortwywoływana jest w przypadku niepowodzenia pierwszej fazy uwierzytelniania. Metoda logoutwywoływana jest w momencie wylogowania się z systemu. Po zaimplementowaniu Login Modulei skonfigurowaniu naszego Security Realm, musimy teraz wskazać web.xmlfakt, że chcemy użyć konkretnego Login Config:
<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>JaasLogin</realm-name>
</login-config>
Podaliśmy nazwę naszego obszaru bezpieczeństwa i określiliśmy metodę uwierzytelniania - BASIC. Jest to jeden z typów uwierzytelniania opisanych w Servlet API w sekcji „ 13.6 Uwierzytelnianie ”. Pozostał n
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION