Przewodnik integracji Keycloak: Zabezpieczanie punktów końcowych Java Spring za pomocą Keycloak

Przewodnik integracji Keycloak: Zabezpieczanie punktów końcowych Java Spring za pomocą Keycloak
Andrzej Chybicki: projekty związane z wykorzystaniem sztucznej inteligencji to znacząca część naszych projektów
Przewodnik integracji Keycloak: Zabezpieczanie punktów końcowych Java Spring za pomocą Keycloak

 

 

W dobie rozwoju aplikacji internetowych, zabezpieczanie punktów końcowych jest kluczowym zadaniem, aby mieć pewność, że tylko upoważnieni użytkownicy mogą uzyskać dostęp do określonych zasobów. Jednym z najbardziej niezawodnych sposobów obsługi uwierzytelniania i autoryzacji w aplikacjach Java Spring jest integracja z Keycloak, otwartoźródłowym rozwiązaniem do zarządzania tożsamością i dostępem.

Spring Security to potężne i elastyczne ramy do uwierzytelniania i kontroli dostępu dla ekosystemu Java Spring. Jednak zarządzanie i wdrażanie polityk bezpieczeństwa oraz mechanizmów uwierzytelniania od podstaw może być uciążliwe i podatne na błędy. Dzięki integracji z Keycloak, deweloperzy mogą przekazać wiele z tych obowiązków solidnemu, zewnętrznemu systemowi. Keycloak obsługuje zarządzanie użytkownikami, rolami i uprawnieniami oraz zapewnia łatwy w użyciu interfejs dla administratorów.

W tym artykule pokażemy, jak bezproblemowo zintegrować Keycloak z Spring Boot i zabezpieczyć punkty końcowe w oparciu o Role-Based Access Control (RBAC). Przeprowadzimy Cię przez niezbędne kroki, aby skonfigurować Keycloak, ustawić role i zastosować ograniczenia bezpieczeństwa w Twojej aplikacji. Na koniec tego przewodnika będziesz miał zaimplementowany system uwierzytelniania i autoryzacji w swoim projekcie Spring Boot.

Konfiguracja Keycloak

Przed integracją Keycloak z aplikacją Spring Boot, musisz skonfigurować serwer Keycloak. Oto szybki przewodnik, jak zacząć:

  1. Pobierz i zainstaluj Keycloak

Pobierz najnowszą wersję Keycloak z oficjalnej strony internetowej. Rozpakuj pobrany archiwum i uruchom serwer, przechodząc do katalogu bin i wykonując polecenie:

bin/kc.sh start-dev
2024-05-23 06:59:48,625 INFO  [io.quarkus] (main) Keycloak 24.0.4 on JVM (powered by Quarkus 3.8.4) started in 5.096s. Listening on: http://0.0.0.0:8080

2. Dostęp do konsoli administracyjnej

Otwórz przeglądarkę i przejdź do http://localhost:8080. Po utworzeniu konta administratora i zalogowaniu się powinieneś zostać przekierowany do /admin/master/console/.

3. Tworzenie Realm

Po pomyślnym zalogowaniu zostaniesz przeniesiony do konsoli administracyjnej, gdzie otworzy się domyślny realm Master. W tym scenariuszu stworzymy niestandardowy realm. Utwórz nowy realm, klikając przycisk „Add Realm”. Po kliknięciu przycisku „Create”, nowy realm zostanie utworzony, a Ty zostaniesz do niego przekierowany. Wszystkie operacje w następnych sekcjach będą wykonywane w tym nowym niestandardowym realmie.

Realm reprezentuje logiczną grupę użytkowników, poświadczeń, ról i konfiguracji. Działa zasadniczo jako izolowane środowisko w ramach serwera Keycloak, gdzie możesz zarządzać użytkownikami i definiować polityki bezpieczeństwa niezależnie od innych realmów. To oddzielenie umożliwia różnym aplikacjom lub organizacjom posiadanie własnych, odrębnych domen bezpieczeństwa w ramach jednej instancji Keycloak. Realmy zapewniają elastyczność dostosowywania ustawień uwierzytelniania i autoryzacji do specyficznych potrzeb różnych projektów lub klientów.

4. Tworzenie klienta

Teraz przejdziemy do strony „Clients”. Jak widać na poniższym obrazku, Keycloak zawiera już wbudowane profile. Wciąż musimy dodać nowego klienta do naszej aplikacji, klikamy więc przycisk „Create”.

Klient w Keycloak reprezentuje aplikację lub usługę, która żąda uwierzytelnienia i autoryzacji od serwera Keycloak. Klienci są konfigurowani w ramach realm i mogą mieć określone role, poświadczenia i polityki dostępu. Mogą to być aplikacje webowe, aplikacje mobilne lub inne rodzaje usług, które wymagają bezpiecznej kontroli dostępu. Definiując klientów, Keycloak może zarządzać, jak różne aplikacje współpracują z serwerem uwierzytelniania, zapewniając, że każdy klient przestrzega odpowiednich protokołów bezpieczeństwa i posiada niezbędne uprawnienia do uzyskiwania dostępu do chronionych zasobów.

 

5. Tworzenie ról i użytkowników

Zdefiniuj role i użytkowników dla swojej aplikacji. Przejdź do sekcji „Roles” i „Users”, aby je dodać i odpowiednio skonfigurować.

Integracja Keycloak ze Spring Boot

 

1. Dodanie zależności

Używamy klienta Spring Security OAuth2.0 do połączenia z serwerem Keycloak.

Zacznijmy od zadeklarowania zależności `spring-boot-starter-oauth2-client` w aplikacji Spring Boot w pliku `pom.xml`:

<dependency>   
    <groupId>org.springframework.boot</groupId> 
       <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

Ponieważ musimy używać Spring Security z Spring Boot, musimy dodać tę zależność:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Aby delegować kontrolę identyfikacji do serwera Keycloak, użyjemy biblioteki spring-boot-starter-oauth2-resource-server. Biblioteka ta ułatwia walidację tokena JWT za pomocą serwera Keycloak. Dlatego dodajmy ją do pliku pom.xml naszego projektu:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

2. Konfiguracja Keycloak w pliku application.properties

Ten typ autoryzacji jest odpowiedni do komunikacji serwer-serwer, gdzie sama aplikacja klienta jest uważana za właściciela zasobu. Polega na wymianie poświadczeń klienta (ID klienta i sekretny klucz klienta) na token dostępu.

spring.security.oauth2.client.registration.keycloak.authorization-grant-type=client_credentials

Te właściwości definiują ID klienta i sekretny klucz, które aplikacja będzie używać do uwierzytelniania się z Keycloak. W tym przykładzie sekretny klucz jest ustawiony na wartość zastępczą.

spring.security.oauth2.client.registration.keycloak.client-id=back-end-resource-server 
spring.security.oauth2.client.registration.keycloak.client-secret=test-secret

Na koniec dodajmy konfigurację potrzebną do walidacji tokena JWT za pomocą naszego serwera Keycloak:

spring.security.oauth2.client.provider.keycloak.token-uri=${test.keycloak-base-url}/realms/test/protocol/openid-connect/token 
spring.security.oauth2.resourceserver.jwt.issuer-uri=${app.keycloak-base-url}/realms/test-realm

Łącząc te konfiguracje, Twoja aplikacja Spring Boot będzie mogła uwierzytelniać się w Keycloak za pomocą przepływu poświadczeń klienta i weryfikować tokeny JWT wydane przez Keycloak, zapewniając bezpieczny dostęp do swoich punktów końcowych.

Teraz aplikacja Spring Boot może współpracować z Keycloak.

 

3. Konfiguracja Spring Security

Teraz przyjrzyjmy się konfiguracji serwera zasobów. Musimy wyodrębnić specyficzne informacje Keycloak z tokena JWT. Wszystkie żądania z nagłówkiem Authorization muszą zawierać token użytkownika z niezbędnym zakresem.

W tym przykładzie CORS jest włączony, a zarządzanie sesją jest ustawione na stateless, co jest typowe dla API, aby zapewnić, że każde żądanie jest niezależnie uwierzytelniane. Wyłączyliśmy również ochronę CSRF, ponieważ nasze API jest bezstanowe.

Aplikacja jest skonfigurowana jako serwer zasobów OAuth 2, który używa JWT do uwierzytelniania, a `jwtAuthenticationConverter` jest określony, aby obsługiwać konwersję roszczeń JWT na uprawnienia.

@Bean
public SecurityFilterChain setupOAuth(HttpSecurity http) throws Exception {
          http.cors().and()
         .sessionManagement().sessionCreationPolicy(STATELESS).and()
         .csrf().disable()
  .oauth2ResourceServer().jwt().jwtAuthenticationConverter(getJwtAuthenticationConverter()).and().and()
         .authorizeHttpRequests(authz -> authz
                 .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
                 .anyRequest().hasAnyAuthority("SCOPE_back-end-resource-server")
         );
    return http.build();
}
private CompositeJwtAuthenticationConverter getJwtAuthenticationConverter() {
    return new CompositeJwtAuthenticationConverter()
         .extractAuthorities("ROLE_", "realm_access", "roles")
         .extractAuthorities("SCOPE_", "scope");
}

Zabezpieczanie REST API

Ta konkretna konfiguracja gwarantuje, że tylko zweryfikowani użytkownicy posiadający odpowiednie role mogą uzyskać dostęp do zabezpieczonych treści. Załóżmy, że istnieje rola o nazwie ADMIN i chcemy ograniczyć dostęp do listy podmiotów wyłącznie dla użytkowników przypisanych do tej roli.

@RolesAllowed({Roles.ADMIN})
@GetMapping("/vehicles")
public ResponseEntity<?> getVehicles() {
return vehicleRepository.findAll();
}

Jednym ze sposobów uzyskania tokena JWT w przyjazny dla użytkownika sposób jest integracja Keycloak z klientem front-end, np. za pomocą odpowiednich bibliotek Angular, ale to prawdopodobnie będzie temat innego posta, więc przyjrzyjmy się szybko inicjalizacji KeycloakService (z biblioteki keycloak-angular) i przejdźmy dalej.

 

function initializeKeycloak(keycloak: KeycloakService) {
return () =>
     keycloak.init({
         config: {
             url: environment.keycloakUrl,
             realm: 'test',
             clientId: 'front-end',
         },
         initOptions: {
             checkLoginIframe: false,
             scope: 'back-end-resource-server'
         }
     });
}

Po pomyślnym uwierzytelnieniu powinniśmy otrzymać token JWT o podobnej strukturze.

"realm_access": {
"roles": [
     "offline_access",
     "default-roles-test",
     "uma_authorization",
     "ADMIN"
]
},
"scope": "openid profile email back-end-resource-server"

Podczas uruchamiania lokalnego serwera możemy użyć cURL do przetestowania naszego nowego punktu końcowego:

curl -H "Authorization: Bearer {valid_jwt_token}" http://localhost:4200/api/vehicles

Nawet jeśli posiadamy token JWT, brak roli admina spowoduje odpowiedź 403.

StatusCode: 403
StatusDescription: Forbidden

Rozważmy scenariusz, w którym użytkownik zalogował się na konto administratora:

StatusCode: 200
StatusDescription: OK

Jak widać, korzystanie z Keycloak Role-Based Access Control (RBAC) w aplikacjach internetowych posiada wiele zalet. Po pierwsze, zapewnia solidne i skalowalne rozwiązanie do zarządzania dostępem do zasobów na podstawie ról i uprawnień użytkowników. Definiując role w Keycloak i przypisując je użytkownikom lub grupom, administratorzy mogą łatwo kontrolować, kto może uzyskać dostęp do określonych funkcji lub danych w aplikacji. Ta szczegółowa kontrola dostępu zwiększa bezpieczeństwo, zapewniając, że tylko upoważnieni użytkownicy mogą wykonywać określone działania lub przeglądać poufne informacje.

Ponadto, Keycloak RBAC upraszcza zarządzanie politykami kontroli dostępu w wielu aplikacjach lub mikrousługach. Centralizacja ról i uprawnień użytkowników w Keycloak eliminuje potrzebę wdrażania i utrzymywania osobnych mechanizmów autoryzacji w każdej aplikacji. Ta centralizacja usprawnia zadania administracyjne, zmniejsza nakład pracy związany z rozwojem i zapewnia spójność polityk kontroli dostępu w całym ekosystemie aplikacji.

Podsumowując, wykorzystanie Keycloak RBAC w aplikacjach internetowych przynosi korzyści w postaci zwiększonego bezpieczeństwa, modułowości, centralizacji i adaptacyjności w zarządzaniu kontrolą dostępu. Te korzyści przyczyniają się do tworzenia bardziej bezpiecznych, łatwych w utrzymaniu i skalowalnych aplikacji internetowych, jednocześnie upraszczając zadania administracyjne i zapewniając spójność polityk kontroli dostępu w całym ekosystemie aplikacji.