CAS SSO s proljetnim osiguranjem

1. Pregled

U ovom ćemo uputstvu pogledati Apereo Central Authentication Service (CAS) i vidjet ćemo kako ga usluga Spring Boot može koristiti za provjeru autentičnosti. CAS je rješenje za jedinstvenu prijavu u poduzeću (SSO) koje je također otvoreni izvor.

Što je SSO? Kada se na YouTube, Gmail i Maps prijavite s istim vjerodajnicama, to je Single Sign-On. To ćemo demonstrirati postavljanjem CAS poslužitelja i aplikacije Spring Boot. Aplikacija Spring Boot upotrebljavat će CAS za provjeru autentičnosti.

2. Postavljanje CAS poslužitelja

2.1. Ugradnja i ovisnosti CAS-a

Poslužitelj koristi Maven (Gradle) War Overlay stil za olakšavanje postavljanja i postavljanja:

git klon //github.com/apereo/cas-overlay-template.git cas-poslužitelj

Ova naredba će klonirati cas-overlay-predložak u cas-poslužitelj imenik.

Neki od aspekata koje ćemo pokriti uključuju registraciju usluge JSON i povezivanje baze podataka JDBC. Pa ćemo dodati njihove module u ovisnosti odjeljak graditi.gradle datoteka:

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

Svakako provjerimo najnoviju verziju casServera.

2.2. Konfiguracija CAS poslužitelja

Prije nego što možemo pokrenuti CAS poslužitelj, moramo dodati neke osnovne konfiguracije. Počnimo s izradom a cas-server / src / main / resources i u ovoj mapi. Nakon toga slijedi stvaranje primjena.svojstva u mapi, također:

server.port = 8443 spring.main.allow-bean-definition-overriding = true server.ssl.key-store = classpath: / etc / cas / thekeystore server.ssl.key-store-password = changeit

Nastavimo sa stvaranjem datoteke spremišta ključeva na koju se poziva gornja konfiguracija. Prvo, moramo stvoriti mape / itd. / cas i / etc / cas / config u cas-server / src / main / resources.

Zatim, moramo promijeniti direktorij u cas-server / src / main / resources / etc / cas i pokrenite naredbu za generiranje trgovina ključevima:

keytool -genkey -keyalg RSA -alias thekeystore -keystore thekeystore -storepass changeit -validnost 360 -keysize 2048

Da ne bismo imali SSL pogrešku rukovanja, trebali bismo koristiti lokalnihost kao vrijednost imena i prezimena. Isto bismo trebali koristiti i za naziv organizacije i jedinicu. Nadalje, moramo uvesti trgovina ključevima u JDK / JRE koji ćemo koristiti za pokretanje naše klijentske aplikacije:

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

Lozinka za izvornu i odredišnu pohranu ključeva je promijeni to. Na Unix sustavima, ovu ćemo naredbu možda morati pokrenuti s adminom (sudo) privilegija. Nakon uvoza trebali bismo ponovno pokrenuti sve instance Jave koja radi ili ponovno pokrenuti sustav.

Koristimo JDK11 jer to zahtijeva CAS verzija 6.1.x. Također, definirali smo varijablu okruženja $ JAVA11_HOME koja upućuje na njezin početni direktorij. Sada možemo pokrenuti CAS poslužitelj:

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

Kad se aplikacija pokrene, na terminalu ćemo vidjeti ispisano „SPREMNO“ a poslužitelj će biti dostupan na // localhost: 8443.

2.3. Korisnička konfiguracija CAS poslužitelja

Još se ne možemo prijaviti jer nismo konfigurirali nijednog korisnika. CAS ima različite metode upravljanja konfiguracijom, uključujući samostalni način rada. Stvorimo mapu config cas-server / src / main / resources / etc / cas / config u kojem ćemo stvoriti datoteku svojstava cas.vlasništva. Sada u datoteci svojstava možemo definirati statičnog korisnika:

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

Moramo priopćiti mjesto mape config serveru CAS da bi postavke stupile na snagu. Ažurirajmo zadaci.gradle tako da lokaciju možemo poslati kao JVM argument iz naredbenog retka:

izvršavanje zadatka (grupa: "build", opis: "Pokreni CAS web aplikaciju u načinu ugrađenog spremnika") {dependOn '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 {main = "-jar" jvmArgs = casRunArgs args = ["build / libs / $ {casWebApplicationBinaryName}"]] logger.info "Started $ {commandLine}"}}}

Zatim spremimo datoteku i izvodimo:

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

Napominjemo da vrijednost cas.standalone.configurationDirectory je apsolutni put. Sad možemo ići na // localhost: 8443 i prijavite se korisničkim imenom casuser i lozinku Mellon.

3. Postavljanje CAS klijenta

Upotrijebit ćemo Spring Initializr za generiranje klijentske aplikacije Spring Boot. Imat će mreža, Sigurnost, Freemarker i DevTools ovisnosti. Uz to ćemo dodati i ovisnost za Spring Security CAS modul pom.xml:

 org.springframework.security spring-security-cas 5.3.0.OSLOBOĐENJE 

Na kraju, dodamo sljedeća svojstva Spring Boot za konfiguriranje aplikacije:

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

4. Registracija usluge poslužitelja CAS

Klijentske aplikacije moraju se registrirati na CAS poslužitelju prije bilo kakve provjere autentičnosti. CAS poslužitelj podržava upotrebu registra klijenata YAML, JSON, MongoDB i LDAP.

U ovom uputstvu koristit ćemo metodu registra usluga JSON. Stvorimo još jednu mapu cas-server / src / main / resources / etc / cas / services. U ovoj će se mapi nalaziti JSON datoteke registra usluga.

Stvorit ćemo JSON datoteku koja sadrži definiciju naše klijentske aplikacije. Ime datoteke, casSecuredApp-8900.json, slijedi obrazac 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 atribut definira obrazac regularnog izraza URL-a za klijentsku aplikaciju. Uzorak treba odgovarati URL-u klijentske aplikacije.

The iskaznica atribut bi trebao biti jedinstven. Drugim riječima, ne bi trebalo postojati dvije ili više usluga s istim iskaznica registriran na isti CAS poslužitelj. Nakon duplikata iskaznica će dovesti do sukoba i poništavanja konfiguracija.

Također konfiguriramo i vrstu odjave NAZAD_KANAL i URL koji treba biti // localhost: 8900 / izlaz / cas tako da kasnije možemo obaviti pojedinačnu odjavu. Prije nego što CAS poslužitelj može koristiti našu konfiguracijsku datoteku JSON, moramo omogućiti JSON registar u našoj cas.vlasništva:
cas.serviceRegistry.initFromJson = istinito cas.serviceRegistry.json.location = put puta: / etc / cas / services

5. Konfiguracija pojedinačne prijave klijenta CAS-a

Sljedeći korak za nas je konfiguriranje Spring Security-a za rad s CAS poslužiteljem. Također bismo trebali provjeriti puni tijek interakcija, koji se naziva CAS sekvenca.

Dodajmo sljedeće konfiguracije graha u CasSecuredApplication razred naše aplikacije Spring Boot:

@Bean public CasAuthenticationFilter casAuthenticationFilter (AuthenticationManager authenticationManager, ServiceProperties serviceProperties) baca izuzetak {CasAuthenticationFilter filter = new CasAuthenticationFilter (); filter.setAuthenticationManager (authenticationManager); filter.setServiceProperties (serviceProperties); povratni filter; } @Bean public ServiceProperties serviceProperties () {logger.info ("svojstva usluge"); ServiceProperties serviceProperties = novi ServiceProperties (); serviceProperties.setService ("// cas-client: 8900 / login / cas"); serviceProperties.setSendRenew (netačno); usluga povrata svojstva; } @Bean public TicketValidator ticketValidator () {return new Cas30ServiceTicketValidator ("// localhost: 8443"); } @Bean public CasAuthenticationProvider casAuthenticationProvider (TicketValidator ticketValidator, ServiceProperties serviceProperties) {CasAuthenticationProvider provider = novi CasAuthenticationProvider (); provider.setServiceProperties (serviceProperties); provider.setTicketValidator (ticketValidator); provider.setUserDetailsService (s -> novi korisnik ("[e-mail zaštićen]", "Mellon", true, true, true, true, AuthorityUtils.createAuthorityList ("ROLE_ADMIN"))); provider.setKey ("CAS_PROVIDER_LOCALHOST_8900"); povratnik; }

The Svojstva usluge bean ima isti URL kao i serviceId u casSecuredApp-8900.json. To je važno jer identificira ovog klijenta na CAS poslužitelju.

The sendRenew vlasništvo Svojstva usluge postavljeno je na lažno. To znači da korisnik treba poslužitelju samo jednom predstaviti vjerodajnice za prijavu.

The AuthenticationEntryPoint bean će obraditi iznimke provjere autentičnosti. Dakle, preusmjerit će korisnika na URL za prijavu CAS poslužitelja radi provjere autentičnosti.

Ukratko, tijek provjere autentičnosti ide:

  1. Korisnik pokušava pristupiti sigurnoj stranici, što pokreće iznimku provjere autentičnosti
  2. Aktivira se iznimka AuthenticationEntryPoint. Kao odgovor, AuthenticationEntryPoint odvest će korisnika na stranicu za prijavu na CAS poslužitelj - // localhost: 8443 / prijava
  3. Nakon uspješne provjere autentičnosti, poslužitelj preusmjerava natrag na klijenta s ulaznicom
  4. CasAuthenticationFilter pokupiće preusmjeravanje i nazvati CasAuthenticationProvider
  5. CasAuthenticationProvider koristit ću TicketValidator za potvrdu predstavljene ulaznice na CAS serveru
  6. Ako je ulaznica važeća, korisnik će dobiti preusmjeravanje na traženi sigurni URL

Napokon, konfigurirajmo HttpSecurity kako bi osigurali neke rute u WebSecurityConfig. U tom ćemo procesu dodati i ulaznu točku za provjeru autentičnosti za rukovanje iznimkama:

@Override zaštićena void konfiguracija (HttpSecurity http) baca izuzetak {http.authorizeRequests (). AntMatchers ("/ secured", "/ login") .authenticated () .and (). ExceptionHandling () .authenticationEntryPoint (authenticationEntryPoint ()); }

6. Konfiguracija pojedinačne odjave CAS klijenta

Do sada smo se bavili jedinstvenom prijavom; razmotrimo sada CAS jednokratnu odjavu (SLO).

Aplikacije koje koriste CAS za upravljanje autentifikacijom korisnika mogu odjaviti korisnika s dva mjesta:

  • Klijentska aplikacija može lokalno odjaviti korisnika sa sebe - to neće utjecati na status prijave korisnika u drugim aplikacijama koje koriste isti CAS poslužitelj
  • Klijentska aplikacija također može odjaviti korisnika s CAS poslužitelja - to će dovesti do toga da se korisnik odjavi iz svih ostalih klijentskih aplikacija povezanih na isti CAS poslužitelj.

Prvo ćemo postaviti odjavu na klijentskoj aplikaciji, a zatim je proširiti na pojedinačnu odjavu na CAS poslužitelju.

Kako bismo očito vidjeli što se događa iza scene, stvorit ćemo Odjavite se() metoda za obradu lokalne odjave. U uspjehu će nas preusmjeriti na stranicu s vezom za pojedinačnu odjavu:

@GetMapping ("/ logout") javna odjava iz niza (HttpServletRequest zahtjev, HttpServletResponse odgovor, SecurityContextLogoutHandler logoutHandler) {Authentication auth = SecurityContextHolder .getContext (). GetAuthentication (); logoutHandler.logout (zahtjev, odgovor, autorizacija); novi CookieClearingLogoutHandler (AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY) .logout (zahtjev, odgovor, autorizacija); povratak "auth / logout"; }

U pojedinačnom postupku odjave, CAS poslužitelj prvo će isteći korisničku kartu, a zatim poslati zahtjev za asinkronizaciju svim registriranim klijentskim aplikacijama. Svaka klijentska aplikacija koja primi ovaj signal izvršit će lokalnu odjavu. Time će se jednom postići cilj odjave, posvuda će se odjaviti.

Nakon toga, dodajmo neke konfiguracije graha u našu klijentsku aplikaciju. Točnije, u CasSecuredApplicaiton:

@Bean public SecurityContextLogoutHandler securityContextLogoutHandler () {return new SecurityContextLogoutHandler (); } @Bean public LogoutFilter logoutFilter () {LogoutFilter logoutFilter = new LogoutFilter ("// localhost: 8443 / logout", securityContextLogoutHandler ()); logoutFilter.setFilterProcessesUrl ("/ odjava / cas"); povratak odjavaFilter; } @Bean public SingleSignOutFilter singleSignOutFilter () {SingleSignOutFilter singleSignOutFilter = novi SingleSignOutFilter (); singleSignOutFilter.setCasServerUrlPrefix ("// localhost: 8443"); singleSignOutFilter.setLogoutCallbackPath ("/ izlaz / cas"); singleSignOutFilter.setIgnoreInitConfiguration (true); vrati singleSignOutFilter; }

The odjavaFilter presresti će zahtjeve za / odjava / cas i preusmjerite aplikaciju na CAS poslužitelj. The SingleSignOutFilter presretnut će zahtjeve koji dolaze s CAS poslužitelja i izvršit će lokalnu odjavu.

7. Povezivanje CAS poslužitelja s bazom podataka

Možemo konfigurirati CAS poslužitelj za čitanje vjerodajnica iz MySQL baze podataka. Koristit ćemo test baza podataka MySQL poslužitelja koji radi na lokalnom stroju. Ažurirajmo cas-server / src / main / resources / etc / cas / config / cas.properties:

cas.authn.accept.users = cas.authn.jdbc.query [0] .sql = SELECT * FROM users WHERE email =? 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 casb.authn = root cas. [0] .password = root cas.authn.jdbc.query [0] .ddlAuto = nema cas.authn.jdbc.query [0] .driverClass = com.mysql.cj.jdbc.Driver cas.authn.jdbc.query [0] .fieldPassword = lozinka cas.authn.jdbc.query [0] .passwordEncoder.type = NONE

Postavili smo cas.authn.prihvati.korisnici isprazniti. Ovo će deaktivirati upotrebu statičkih korisničkih spremišta od strane CAS poslužitelja.

Prema gore navedenom SQL-u, vjerodajnice korisnika pohranjuju se u korisnika stol. The e-mail stupac je ono što predstavlja glavnicu korisnika (Korisničko ime).

Svakako provjerite popis podržanih baza podataka, dostupne upravljačke programe i dijalekte. Također smo postavili tip kodera lozinke na NITKO. Dostupni su i drugi mehanizmi šifriranja i njihova osobita svojstva.

Imajte na umu da glavnica u bazi podataka CAS poslužitelja mora biti ista kao i aplikacija klijenta.

Ažurirajmo CasAuthenticationProvider imati isto korisničko ime kao i CAS poslužitelj:

@Bean public CasAuthenticationProvider casAuthenticationProvider () {CasAuthenticationProvider provider = novi CasAuthenticationProvider (); provider.setServiceProperties (serviceProperties ()); provider.setTicketValidator (ticketValidator ()); provider.setUserDetailsService (s -> novi korisnik ("[e-mail zaštićen]", "Mellon", true, true, true, true, AuthorityUtils.createAuthorityList ("ROLE_ADMIN"))); provider.setKey ("CAS_PROVIDER_LOCALHOST_8900"); povratnik; }

CasAuthenticationProvider ne koristi lozinku za provjeru autentičnosti. Ipak, njegovo korisničko ime mora se podudarati s korisničkim imenom CAS poslužitelja da bi provjera autentičnosti bila uspješna. CAS poslužitelj zahtijeva rad MySQL poslužitelja lokalnihost u luci 3306. Korisničko ime i lozinka trebaju biti korijen.

Ponovno pokrenite CAS poslužitelj i aplikaciju Spring Boot. Zatim upotrijebite nove vjerodajnice za provjeru autentičnosti.

8. Zaključak

Pogledali smo kako koristiti CAS SSO s Spring Security i mnogim uključenim konfiguracijskim datotekama. Postoje mnogi drugi aspekti CAS SSO koji se može konfigurirati. U rasponu od tema i vrsta protokola do pravila provjere autentičnosti.

Ovi i drugi su u dokumentima. Izvorni kod za CAS poslužitelj i aplikaciju Spring Boot dostupan je na GitHubu.