CAS SSO s jarnou bezpečnosťou

1. Prehľad

V tomto tutoriáli sa pozrieme na Apereo Central Authentication Service (CAS) a uvidíme, ako ho služba Spring Boot môže použiť na autentifikáciu. CAS je podnikové riešenie jednotného prihlásenia (SSO), ktoré je tiež otvoreným zdrojom.

Čo je SSO? Keď sa prihlásite do služby YouTube, Gmail a Mapy pomocou rovnakých prihlasovacích údajov, jedná sa o jednotné prihlásenie. Ukážeme to nastavením servera CAS a aplikácie Spring Boot. Aplikácia Spring Boot bude na autentifikáciu používať CAS.

2. Nastavenie servera CAS

2.1. Inštalácia a závislosti CAS

Server na uľahčenie nastavenia a nasadenia používa štýl vojny Maven (Gradle):

git clone //github.com/apereo/cas-overlay-template.git cas-server

Tento príkaz klonuje cas-overlay-template do cas-server adresár.

Medzi niektoré aspekty, ktorým sa budeme venovať, patrí registrácia služby JSON a pripojenie k databáze JDBC. Takže ich moduly pridáme do závislosti časť build.gradle spis:

kompilovať "org.apereo.cas: cas-server-support-json-service-registry: $ {casServerVersion}" kompilovať "org.apereo.cas: cas-server-support-jdbc: $ {casServerVersion}"

Nezabudnite skontrolovať najnovšiu verziu casServeru.

2.2. Konfigurácia servera CAS

Predtým, ako môžeme spustiť server CAS, musíme pridať niekoľko základných konfigurácií. Začnime vytvorením a cas-server / src / main / resources priečinku a v tomto priečinku. Potom bude nasledovať vytvorenie application.properties v priečinku tiež:

server.port = 8443 spring.main.allow-bean-definition-overriding = skutočný server.ssl.key-store = cesta k triede: / etc / cas / thekeystore server.ssl.key-store-heslo = changeit

Pokračujme k vytvoreniu súboru úložiska kľúčov, na ktorý sa odkazuje v konfigurácii vyššie. Najskôr musíme vytvoriť priečinky / etc / cas a / etc / cas / config v cas-server / src / main / resources.

Potom musíme zmeniť adresár na cas-server / src / main / resources / etc / cas a spustite príkaz na vygenerovanie obchod s klienmi:

keytool -genkey -keyalg RSA -alias thekeystore -keystore thekeystore -storepass changeit -validity 360 -keys size 2048

Aby sme nemali chybu spojenia SSL, mali by sme použiť localhost ako hodnota mena a priezviska. To isté by sme mali používať aj pre názov organizácie a jednotku. Ďalej musíme dovážať obchod s klienmi do JDK / JRE, ktoré použijeme na spustenie našej klientskej aplikácie:

keytool -importkeystore -srckeystore thekeystore -destkeystore $ JAVA11_HOME / jre / lib / security / cacerts

Heslo pre zdrojový a cieľový obchod s kľúčmi je Zmeň to. V systémoch Unix bude možno potrebné spustiť tento príkaz s administrátorom (sudo) privilégium. Po importe by sme mali reštartovať všetky inštancie Java, ktoré sú spustené, alebo reštartovať systém.

Používame JDK11, pretože to vyžaduje CAS verzia 6.1.x. Definovali sme tiež premennú prostredia $ JAVA11_HOME, ktorá smeruje na jej domovský adresár. Teraz môžeme spustiť server CAS:

./gradlew run -Dorg.gradle.java.home = $ JAVA11_HOME

Po spustení aplikácie sa na termináli zobrazí „READY“ a server bude k dispozícii na // localhost: 8443.

2.3. Konfigurácia používateľa servera CAS

Zatiaľ sa nemôžeme prihlásiť, pretože sme nenakonfigurovali žiadneho používateľa. CAS má rôzne spôsoby riadenia konfigurácie vrátane samostatného režimu. Vytvorme konfiguračný priečinok cas-server / src / main / resources / etc / cas / config v ktorom vytvoríme súbor vlastností cas.vlastnosti. Teraz môžeme definovať statického používateľa v súbore vlastností:

cas.authn.accept.users = casuser :: Mellon

Aby sa nastavenia prejavili, musíme komunikovať s umiestnením konfiguračného priečinka na server CAS. Poďme sa aktualizovať úlohy.gradle takže môžeme zadať umiestnenie ako argument JVM z príkazového riadku:

beh úlohy (skupina: "build", popis: "Spustiť webovú aplikáciu CAS v režime vloženého kontajnera") {dependsOn 'build' doLast {def casRunArgs = new ArrayList (Arrays.asList ("-server -noverify -Xmx2048M -XX: + TieredCompilation -XX: TieredStopAtLevel = 1 ".split (" "))) if (project.hasProperty ('args')) {casRunArgs.addAll (project.args.split ('\ s +'))} javaexec {hlavný = "-jar" jvmArgs = casRunArgs args = ["build / libs / $ {casWebApplicationBinaryName}"] logger.info "Spustené $ {commandLine}"}}}

Potom súbor uložíme a spustíme:

./gradlew run -Dorg.gradle.java.home = $ JAVA11_HOME -Pargs = "- Dcas.standalone.configurationDirectory = / cas-server / src / main / resources / etc / cas / config"

Upozorňujeme, že hodnota cas.standalone.configurationDirectory je absolútna cesta. Teraz môžeme ísť na // localhost: 8443 a prihláste sa pomocou používateľského mena casuser a heslo Mellon.

3. Nastavenie klienta CAS

Na vygenerovanie klientskej aplikácie Spring Boot použijeme Spring Initializr. Bude mať Web, Bezpečnosť, Slobodný znalec a DevTools závislosti. Okrem toho do neho pridáme aj závislosť modulu Spring Security CAS pom.xml:

 org.springframework.security spring-security-cas 5.3.0.RELEASE 

Na záver pridajme nasledujúce vlastnosti Spring Boot na konfiguráciu aplikácie:

server.port = 8900 spring.freemarker.suffix = .ftl

4. Registrácia serverovej služby CAS

Aplikácie klientov sa musia zaregistrovať na serveri CAS pred každou autentifikáciou. Server CAS podporuje použitie registrov klientov YAML, JSON, MongoDB a LDAP.

V tejto príručke použijeme metódu JSON Service Registry. Vytvorme ešte ďalší priečinok cas-server / src / main / resources / etc / cas / services. Je to tento priečinok, v ktorom budú uložené súbory JSON servisného registra.

Vytvoríme súbor JSON, ktorý obsahuje definíciu našej klientskej aplikácie. Názov súboru, casSecuredApp-8900.json, nasleduje vzor serviceName-Id.json:

{"@class": "org.apereo.cas.services.RegexRegisteredService", "serviceId": "// localhost: 8900 / login / cas", "name": "casSecuredApp", "id": 8900, "logoutType" ":" BACK_CHANNEL "," logoutUrl ":" // localhost: 8900 / exit / cas "}

The serviceId atribút definuje vzor adresy URL regulárneho výrazu pre klientsku aplikáciu. Vzor by sa mal zhodovať s adresou URL klientskej aplikácie.

The id atribút by mal byť jedinečný. Inými slovami, nemali by existovať dve alebo viac služieb s rovnakými id zaregistrovaný na rovnakom serveri CAS. S duplikátom id povedie ku konfliktom a prepísaniu konfigurácií.

Konfigurujeme tiež typ odhlásenia BACK_CHANNEL a adresu URL, ktorá má byť // localhost: 8900 / exit / cas aby sme mohli neskôr vykonať samostatné odhlásenie. Predtým, ako server CAS bude môcť používať náš konfiguračný súbor JSON, musíme povoliť register JSON v našom cas.vlastnosti:
cas.serviceRegistry.initFromJson = true cas.serviceRegistry.json.location = classpath: / etc / cas / services

5. Konfigurácia CAS Client Single Sign-On

Ďalším krokom je konfigurácia Spring Security na prácu so serverom CAS. Mali by sme tiež skontrolovať úplný tok interakcií, ktorý sa nazýva sekvencia CAS.

Pridajme nasledujúce konfigurácie fazule do CasSecuredApplication trieda našej aplikácie Spring Boot:

@Bean public CasAuthenticationFilter casAuthenticationFilter (AuthenticationManager authenticationManager, ServiceProperties serviceProperties) vyvolá výnimku {CasAuthenticationFilter filter = nový CasAuthenticationFilter (); filter.setAuthenticationManager (authenticationManager); filter.setServiceProperties (serviceProperties); spätný filter; } @Bean public ServiceProperties serviceProperties () {logger.info ("vlastnosti služby"); ServiceProperties serviceProperties = nový ServiceProperties (); serviceProperties.setService ("// cas-client: 8900 / login / cas"); serviceProperties.setSendRenew (false); návratová službaVlastnosti; } @Bean public TicketValidator ticketValidator () {vrátiť nový Cas30ServiceTicketValidator ("// localhost: 8443"); } @Bean public CasAuthenticationProvider casAuthenticationProvider (TicketValidator ticketValidator, ServiceProperties serviceProperties) {CasAuthenticationProvider provider = nový CasAuthenticationProvider (); provider.setServiceProperties (serviceProperties); provider.setTicketValidator (ticketValidator); provider.setUserDetailsService (s -> nový používateľ ("[chránený e-mailom]", "Mellon", true, true, true, true, AuthorityUtils.createAuthorityList ("ROLE_ADMIN"))); provider.setKey ("CAS_PROVIDER_LOCALHOST_8900"); poskytovateľ návratu; }

The Vlastnosti služby fazuľa má rovnakú adresu URL ako serviceId v casSecuredApp-8900.json. To je dôležité, pretože identifikuje tohto klienta na serveri CAS.

The sendRenew majetok Vlastnosti služby je nastavený na nepravdivé. To znamená, že používateľ musí na server predložiť prihlasovacie poverenia iba raz.

The AuthenticationEntryPoint bean spracuje výnimky autentifikácie. Presmeruje teda používateľa na prihlasovaciu adresu URL servera CAS na autentifikáciu.

Stručne povedané, postup autentifikácie ide:

  1. Používateľ sa pokúsi získať prístup na zabezpečenú stránku, ktorá spustí výnimku autentifikácie
  2. Výnimka sa spustí AuthenticationEntryPoint. V reakcii na to AuthenticationEntryPoint zavedie používateľa na prihlasovaciu stránku servera CAS - // localhost: 8443 / login
  3. Po úspešnej autentifikácii sa server presmeruje späť na klienta s lístkom
  4. CasAuthenticationFilter zdvihne presmerovanie a zavolá CasAuthenticationProvider
  5. CasAuthenticationProvider bude používať TicketValidator na potvrdenie predloženého tiketu na serveri CAS
  6. Ak je lístok platný, používateľ dostane presmerovanie na požadovanú zabezpečenú adresu URL

Nakoniec poďme nakonfigurovať HttpSecurity zabezpečiť niektoré trasy v WebSecurityConfig. V tomto procese tiež pridáme vstupný bod autentifikácie pre spracovanie výnimiek:

@Override protected void configure (HttpSecurity http) vyvolá výnimku {http.authorizeRequests (). AntMatchers ("/ secure", "/ login") .authenticated () .and (). ExceptionHandling () .authenticationEntryPoint (authenticationEntryPoint ()); }

6. Konfigurácia jediného odhlásenia klienta CAS

Doteraz sme sa zaoberali jednotným prihlásením; uvažujme teraz o jednom odhlásení CAS (SLO).

Aplikácie, ktoré používajú CAS na správu autentifikácie užívateľa, môžu odhlásiť používateľa z dvoch miest:

  • Klientská aplikácia môže lokálne odhlásiť používateľa od seba - nebude to mať vplyv na stav prihlásenia používateľa v iných aplikáciách, ktoré používajú ten istý server CAS.
  • Klientská aplikácia môže tiež odhlásiť používateľa zo servera CAS - toto spôsobí odhlásenie používateľa zo všetkých ostatných klientskych aplikácií pripojených k rovnakému serveru CAS.

Najskôr zavedieme odhlásenie z klientskej aplikácie a potom ho rozšírime o jedno odhlásenie na serveri CAS.

Aby bolo zrejmé, čo sa deje v zákulisí, vytvoríme a odhlásiť sa() spôsob spracovania miestneho odhlásenia. V prípade úspechu nás presmeruje na stránku s odkazom na jednotné odhlásenie:

@GetMapping ("/ logout") verejné odhlásenie reťazca (požiadavka HttpServletRequest, odpoveď HttpServletResponse, SecurityContextLogoutHandler logoutHandler) {Authentication auth = SecurityContextHolder .getContext (). GetAuthentication (); logoutHandler.logout (požiadavka, odpoveď, autorizácia); nový CookieClearingLogoutHandler (AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY) .logout (požiadavka, odpoveď, autorizácia); vrátiť "autorizáciu / odhlásenie"; }

V procese jednotného odhlásenia server CAS najskôr vyprší platnosť lístka používateľa a potom pošle žiadosť o asynchronizáciu všetkým zaregistrovaným klientskym aplikáciám. Každá klientská aplikácia, ktorá dostane tento signál, vykoná miestne odhlásenie. Tým sa dosiahne jednorazové odhlásenie, ktoré spôsobí odhlásenie všade.

Po týchto úvahách pridáme do našej klientskej aplikácie niekoľko konfigurácií fazule. Konkrétne v CasSecuredApplicaiton:

@Bean public SecurityContextLogoutHandler securityContextLogoutHandler () {vrátiť nový SecurityContextLogoutHandler (); } @Bean public LogoutFilter logoutFilter () {LogoutFilter logoutFilter = nový LogoutFilter ("// localhost: 8443 / logout", securityContextLogoutHandler ()); logoutFilter.setFilterProcessesUrl ("/ logout / cas"); vrátiť odhlásenieFilter; } @Bean public SingleSignOutFilter singleSignOutFilter () {SingleSignOutFilter singleSignOutFilter = nový SingleSignOutFilter (); singleSignOutFilter.setCasServerUrlPrefix ("// localhost: 8443"); singleSignOutFilter.setLogoutCallbackPath ("/ výstup / cas"); singleSignOutFilter.setIgnoreInitConfiguration (true); vrátiť singleSignOutFilter; }

The odhlasovací filter zachytí žiadosti do / odhlásenie / cas a presmerujte aplikáciu na server CAS. The SingleSignOutFilter zachytí požiadavky prichádzajúce zo servera CAS a vykoná miestne odhlásenie.

7. Pripojenie servera CAS k databáze

Môžeme nakonfigurovať server CAS tak, aby čítal poverenia z databázy MySQL. Použijeme test databáza servera MySQL, ktorý je spustený na lokálnom počítači. Poďme sa aktualizovať cas-server / src / main / resources / etc / cas / config / cas.properties:

cas.authn.accept.users = cas.authn.jdbc.query [0] .sql = VYBERTE * OD POUŽÍVATEĽOV KDE e-mail =? cas.authn.jdbc.query [0] .url = jdbc: mysql: //127.0.0.1: 3306 / test? useUnicode = true & useJDBCCompliantTimezoneShift = true & useLegacyDatetimeCode = false & serverTimezone = UTC cas.authn.jdbc.query [0] .dialect = org.hibernate.dialect.MySQLDialect cas.authn.jdbc.query [0] .user = root cas.authn.jpg [0] .password = root cas.authn.jdbc.query [0] .ddlAuto = žiadny cas.authn.jdbc.query [0] .driverClass = com.mysql.cj.jdbc.Driver cas.authn.jdbc.query [0] .fieldPassword = heslo cas.authn.jdbc.query [0] .passwordEncoder.type = ŽIADNE

Nastavili sme cas.authn.accept.users do prázdna. Týmto sa deaktivuje použitie statických úložísk používateľov serverom CAS.

Podľa vyššie uvedeného SQL sú poverenia používateľov uložené v priečinku používateľov stôl. The e-mail stĺpec predstavuje to, čo predstavuje principál používateľov (používateľské meno).

Nezabudnite skontrolovať zoznam podporovaných databáz, dostupných ovládačov a dialektov. Nastavili sme tiež typ kódovača hesla na ŽIADNE. K dispozícii sú aj ďalšie šifrovacie mechanizmy a ich zvláštne vlastnosti.

Pamätajte, že principál v databáze servera CAS musí byť rovnaký ako principál klientskej aplikácie.

Poďme sa aktualizovať CasAuthenticationProvider mať rovnaké používateľské meno ako server CAS:

@Bean public CasAuthenticationProvider casAuthenticationProvider () {poskytovateľ CasAuthenticationProvider = nový CasAuthenticationProvider (); provider.setServiceProperties (serviceProperties ()); provider.setTicketValidator (ticketValidator ()); provider.setUserDetailsService (s -> nový používateľ ("[chránený e-mailom]", "Mellon", true, true, true, true, AuthorityUtils.createAuthorityList ("ROLE_ADMIN"))); provider.setKey ("CAS_PROVIDER_LOCALHOST_8900"); poskytovateľ návratu; }

CasAuthenticationProvider nepoužíva heslo na autentifikáciu. Aby bolo overenie úspešné, jeho používateľské meno sa musí zhodovať s menom servera CAS. Server CAS vyžaduje, aby bol spustený server MySQL localhost v prístave 3306. Používateľské meno a heslo by mali byť koreň.

Reštartujte server CAS a aplikáciu Spring Boot ešte raz. Potom použite nové poverenia na autentifikáciu.

8. Záver

Pozreli sme sa na to, ako používať CAS SSO s Spring Security a mnohými príslušnými konfiguračnými súbormi. Existuje mnoho ďalších aspektov CAS SSO, ktoré sú konfigurovateľné. Od tém a typov protokolov až po zásady autentifikácie.

Tieto a ďalšie sú v dokumentoch. Zdrojový kód pre server CAS a aplikáciu Spring Boot je k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found