Jakarta EE 8 sigurnosni API

1. Pregled

Jakarta EE 8 Security API novi je standard i prijenosni način rješavanja sigurnosnih problema u Java spremnicima.

U ovom članku, pogledat ćemo tri osnovne značajke API-ja:

  1. Mehanizam provjere autentičnosti HTTP
  2. Trgovina identiteta
  3. Sigurnosni kontekst

Prvo ćemo razumjeti kako konfigurirati predviđene implementacije, a zatim kako implementirati prilagođenu.

2. Ovisnosti Mavena

Da bismo postavili sigurnosni API Jakarta EE 8, potrebna nam je implementacija koju pruža poslužitelj ili eksplicitna.

2.1. Korištenje implementacije poslužitelja

Jakarta EE 8 kompatibilni poslužitelji već pružaju implementaciju sigurnosnog API-ja Jakarta EE 8, pa nam stoga treba samo artefakt API-ja Jakarta EE Web Profile:

  javax javaee-web-api 8.0 

2.2. Korištenje eksplicitne implementacije

Prvo specificiramo artefakt Maven za sigurnosni API Jakarta EE 8:

  javax.security.enterprise javax.security.enterprise-api 1.0 

A zatim ćemo dodati implementaciju, na primjer, Soteria - referentna implementacija:

  org.glassfish.soteria javax.security.enterprise 1.0 

3. Mehanizam provjere autentičnosti HTTP-a

Prije Jakarte EE 8, deklarativno smo konfigurirali mehanizme provjere autentičnosti putem web.xml datoteka.

U ovoj je verziji Jakarta EE 8 Security API dizajnirao novo HttpAuthenticationMechanism sučelje kao zamjena. Stoga web aplikacije sada mogu konfigurirati mehanizme provjere autentičnosti pružajući implementacije ovog sučelja.

Srećom, spremnik već nudi implementaciju za svaku od tri metode provjere autentičnosti definirane specifikacijom Servlet: Osnovna HTTP provjera autentičnosti, provjera autentičnosti na temelju obrasca i prilagođena provjera autentičnosti na temelju obrasca.

Također pruža napomenu za pokretanje svake implementacije:

  1. @BasicAuthenticationMechanismDefinition
  2. @FormAuthenticationMechanismDefinition
  3. @CustomFormAuthenrticationMechanismDefinition

3.1. Osnovna HTTP provjera autentičnosti

Kao što je gore spomenuto, web aplikacija može konfigurirati osnovnu HTTP provjeru autentičnosti samo pomoću @BasicAuthenticationMechanismDefinition napomena na CDI grahu:

@BasicAuthenticationMechanismDefinition (realmName = "userRealm") @ApplicationScoped javna klasa AppConfig {}

U ovom trenutku, spremnik Servlet pretražuje i instancira pruženu implementaciju HttpAuthenticationMechanism sučelje.

Po primanju neovlaštenog zahtjeva, spremnik izaziva klijenta da pruži odgovarajuće podatke za provjeru autentičnosti putem WWW-Autentifikacija zaglavlje odgovora.

WWW-autentifikacija: Osnovno područje = "userRealm"

Klijent zatim šalje korisničko ime i lozinku, odvojene dvotočkom ":" i kodirane u Base64, putem Ovlaštenje zaglavlje zahtjeva:

// korisnik = baeldung, lozinka = baeldung Ovlaštenje: Osnovni YmFlbGR1bmc6YmFlbGR1bmc = 

Imajte na umu da dijaloški okvir za pružanje vjerodajnica dolazi iz preglednika, a ne s poslužitelja.

3.2. HTTP provjera autentičnosti na temelju obrasca

The @FormAuthenticationMechanismDefinition napomena pokreće provjeru autentičnosti na temelju obrasca kako je definirano specifikacijom Servleta.

Tada imamo mogućnost navesti stranice za prijavu i pogreške ili upotrijebiti zadane razumne /prijaviti se i /Pogreška pri prijavi:

@FormAuthenticationMechanismDefinition (loginToContinue = @LoginToContinue (loginPage = "/login.html", errorPage = "/login-error.html")) @ApplicationScoped javna klasa AppConfig {}

Kao rezultat pozivanja loginPage, poslužitelj treba poslati obrazac klijentu:

Klijent bi zatim trebao poslati obrazac u unaprijed definirani postupak provjere autentičnosti koji osigurava spremnik.

3.3. Prilagođena HTTP autentifikacija temeljena na obrascu

Web aplikacija može pokrenuti prilagođenu provedbu provjere autentičnosti na temelju obrasca pomoću bilješke @CustomFormAuthenticationMechanismDefinition:

@CustomFormAuthenticationMechanismDefinition (loginToContinue = @LoginToContinue (loginPage = "/login.xhtml")) @ApplicationScoped javna klasa AppConfig {}

No, za razliku od zadane provjere autentičnosti zasnovane na obrascu, mi konfiguriramo prilagođenu stranicu za prijavu i pozivamo se na SecurityContext.authenticate () metoda kao pomoćni postupak provjere autentičnosti.

Pogledajmo pozadinu LoginBean također, koji sadrži logiku prijave:

@Named @RequestScoped javna klasa LoginBean {@Inject private SecurityContext securityContext; @NotNull privatno korisničko ime niza; @NotNull privatna lozinka za niz; javna void prijava () {Vjerodajnica za vjerodajnice = novo korisničko imePasswordCredential (korisničko ime, nova lozinka (lozinka)); AuthenticationStatus status = securityContext .authenticate (getHttpRequestFromFacesContext (), getHttpResponseFromFacesContext (), withParams (). Vjerodajnica (vjerodajnica)); // ...} // ...}

Kao rezultat pozivanja na običaj login.xhtml stranicu, klijent preda primljeni obrazac na PrijavaBean 's prijaviti se() metoda:

//... 

3.4. Prilagođeni mehanizam provjere autentičnosti

The HttpAuthenticationMechanism sučelje definira tri metode. Najvažnija je validateRequest () koju moramo osigurati provedbu.

Zadano ponašanje za druge dvije metode, secureResponse () i cleanSubject (), je u većini slučajeva dovoljna.

Pogledajmo primjer implementacije:

@ApplicationScoped javna klasa CustomAuthentication implementira HttpAuthenticationMechanism {@Override public AuthenticationStatus validateRequest (HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMsgContextExmeterPreseptionPhertceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentceptionPhentseptionPhertPressArthentPressPressName Niz lozinke = response.getParameter ("lozinka"); // ruganje UserDetail, ali u stvarnom životu možemo ga dobiti iz baze podataka UserDetail userDetail = findByUserNameAndPassword (korisničko ime, lozinka); if (userDetail! = null) {return httpMsgContext.notifyContainerAboutLogin (novi CustomPrincipal (userDetail), novi HashSet (userDetail.getRoles ())); } vratiti httpMsgContext.responseUnauthorized (); } // ...}

Ovdje implementacija pruža poslovnu logiku postupka provjere valjanosti, ali u praksi se preporučuje delegiranje na IdentityStore kroz IdentityStoreHandler bg prizivajući potvrditi.

Također smo primijetili implementaciju @ApplicationScoped napomena, jer je trebamo učiniti CDI omogućenom.

Nakon valjane provjere vjerodajnice i eventualnog dohvata korisničkih uloga, implementacija bi tada trebala obavijestiti spremnik:

HttpMessageContext.notifyContainerAboutLogin (Glavni ravnatelj, Postavi grupe)

3.5. Provođenje sigurnosti servleta

Web aplikacija može primijeniti sigurnosna ograničenja pomoću @ServletSecurity napomena o implementaciji Servleta:

@WebServlet ("/ secured") @ServletSecurity (value = @HttpConstraint (roleAllowed = {"admin_role"}), httpMethodConstraints = {@HttpMethodConstraint (value = "GET", roleAllowed = {"user_role"}), @HttpMethodCon = "POST", roleAllowed = {"admin_role"})})) javna klasa SecuredServlet proširuje HttpServlet {}

Ova bilješka ima dva atributa - httpMethodConstraints i vrijednost; httpMethodConstraints koristi se za specificiranje jednog ili više ograničenja, od kojih svako predstavlja kontrolu pristupa HTTP metodi popisom dopuštenih uloga.

Spremnik će zatim provjeriti, za svaki url-uzorak i HTTP metodu, ako povezani korisnik ima prikladnu ulogu za pristup resursu.

4. Trgovina identiteta

Ovu značajku apstrahira the IdentityStore sučelje, a koristi se za provjeru vjerodajnica i na kraju za dohvaćanje članstva u grupi. Drugim riječima, može pružiti mogućnosti za autentifikaciju, autorizaciju ili oboje.

IdentityStore namijenjen je i potiče na upotrebu HttpAuthenticationMecanism kroz pozvanu IdentityStoreHandler sučelje. Zadana implementacija IdentityStoreHandler pruža Servletkontejner.

Aplikacija može osigurati njegovu provedbu IdentityStore ili koristi jednu od dvije ugrađene implementacije koje pruža spremnik za bazu podataka i LDAP.

4.1. Ugrađene prodavaonice identiteta

Poslužitelj Jakarta EE trebao bi osigurati implementacije za dvije trgovine identiteta: baza podataka i LDAP.

Baza podataka IdentityStore implementacija se inicijalizira prosljeđivanjem podataka o konfiguraciji na @DataBaseIdentityStoreDefinition napomena:

@DatabaseIdentityStoreDefinition (dataSourceLookup = "java: comp / env / jdbc / securityDS", callerQuery = "odaberite lozinku od korisnika gdje je korisničko ime =?", GroupsQuery = "odaberite GROUPNAME iz grupa gdje je username =?", Prioritet = 30) @ApplicationScoped public razred AppConfig {}

Kao konfiguracijski podaci, potreban nam je izvor podataka JNDI za vanjsku bazu podataka, konfigurirana su dva JDBC izraza za provjeru pozivatelja i njegovih grupa i na kraju parametar prioriteta koji se koristi u slučaju pohrane višestrukih podataka.

IdentityStore s visokim prioritetom obrađuje kasnije IdentityStoreHandler.

Kao i baza podataka, Implementacija LDAP IdentityStore inicijalizira se putem @LdapIdentityStoreDefinition prosljeđivanjem podataka o konfiguraciji:

@LdapIdentityStoreDefinition (url = "ldap: // localhost: 10389", callerBaseDn = "ou = caller, dc = baeldung, dc = com", groupSearchBase = "ou = group, dc = baeldung, dc = com", groupSearchFilter = " (& (member =% s) (objectClass = groupOfNames)) "") @ApplicationScoped javna klasa AppConfig {}

Ovdje nam treba URL vanjskog LDAP poslužitelja, kako pretražiti pozivatelja u LDAP direktoriju i kako dohvatiti njegove grupe.

4.2. Implementacija prilagođenog IdentityStore

The IdentityStore sučelje definira četiri zadane metode:

zadana CredentialValidationResult provjera valjanosti (vjerodajnica vjerodajnica) default Postavi getCallerGroups (CredentialValidationResult validationResult) zadani int prioritet () zadani Postavi validationTypes ()

The prioritet() metoda vraća vrijednost za redoslijed ponavljanja koji obrađuje ova implementacija IdentityStoreHandler. An IdentityStore s nižim prioritetom obrađuje se prvo.

Prema zadanim postavkama, IdentityStore obrađuje provjeru valjanosti obje vjerodajnice (ValidationType.VALIDATE) i skupno preuzimanje (ValidationType.PROVIDE_GROUPS). To ponašanje možemo nadjačati tako da može pružiti samo jednu sposobnost.

Dakle, možemo konfigurirati IdentityStore da se koristi samo za provjeru vjerodajnica:

@Override public Set validationTypes () {return EnumSet.of (ValidationType.VALIDATE); }

U ovom bismo slučaju trebali pružiti primjenu za potvrditi () metoda:

@ApplicationScoped javna klasa InMemoryIdentityStore implementira IdentityStore {// init iz datoteke ili ukucanih korisnika privatne karte = new HashMap (); @Preuzmi javni int prioritet () {return 70; } @Override public Set validationTypes () {return EnumSet.of (ValidationType.VALIDATE); } javna CredentialValidationResult potvrda (UsernamePasswordCredential vjerodajnica) {UserDetails user = users.get (credential.getCaller ()); if (credential.compareTo (user.getLogin (), user.getPassword ())) {return new CredentialValidationResult (user.getLogin ()); } vratiti INVALID_RESULT; }}

Ili možemo odabrati konfiguriranje IdentityStore tako da se može koristiti samo za skupno dohvaćanje:

@Override public Set validationTypes () {return EnumSet.of (ValidationType.PROVIDE_GROUPS); }

Tada bismo trebali osigurati provedbu za getCallerGroups () metode:

@ApplicationScoped javna klasa InMemoryIdentityStore implementira IdentityStore {// init iz datoteke ili ukucanih korisnika privatne karte = new HashMap (); @Preuzmi javni int prioritet () {return 90; } @Override public Set validationTypes () {return EnumSet.of (ValidationType.PROVIDE_GROUPS); } @Override public Set getCallerGroups (CredentialValidationResult validationResult) {UserDetails user = users.get (validationResult.getCallerPrincipal (). GetName ()); vrati novi HashSet (user.getRoles ()); }}

Jer IdentityStoreHandler očekuje da će implementacija biti CDI grah, mi ga ukrašavamo ApplicationScoped bilješka.

5. API sigurnosnog konteksta

Jakarta EE 8 Security API pruža pristupna točka programskoj sigurnosti putem SecurityContext sučelje. Alternativa je kada deklarativni sigurnosni model koji provodi spremnik nije dovoljan.

Zadana implementacija SecurityContext sučelje bi se trebalo osigurati za vrijeme izvođenja kao CDI grah, pa ga stoga moramo ubrizgati:

@Inject SecurityContext securityContext;

U ovom trenutku možemo autentificirati korisnika, doći do autentificiranog, provjeriti članstvo u ulozi i odobriti ili odbiti pristup web resursima putem pet dostupnih metoda.

5.1. Dohvaćanje podataka o pozivima

U prethodnim verzijama Jakarte EE dohvatili bismo Glavni ili različito provjerite članstvo u ulozi u svakom spremniku.

Dok koristimo getUserPrincipal () i isUserInRole () metode HttpServletRequest u spremniku servleta, slične metode getCallerPrincipal () i metode isCallerInRole () od EJBContext koriste se u EJB spremniku.

Novi Jakarta EE 8 Security API to je standardizirao po pružajući sličnu metodu putem SecurityContext sučelje:

Ravnatelj getCallerPrincipal (); boolean isCallerInRole (uloga niza); Postavite getPrincipalsByType (tip klase);

The getCallerPrincipal () metoda vraća prikaz specifičnog kontejnera ovjerenog pozivatelja dok getPrincipalsByType () metoda dohvaća sve principale dane vrste.

Može biti korisno u slučaju da se pozivač koji se odnosi na aplikaciju razlikuje od onog u spremniku.

5.2. Testiranje pristupa web resursima

Prvo, moramo konfigurirati zaštićeni resurs:

@WebServlet ("/ protectedServlet") @ServletSecurity (@HttpConstraint (roleAllowed = "USER_ROLE")) javna klasa ProtectedServlet proširuje HttpServlet {// ...}

A zatim, da bismo provjerili pristup ovom zaštićenom resursu, trebali bismo pozvati hasAccessToWebResource () metoda:

securityContext.hasAccessToWebResource ("/ protectedServlet", "GET");

U ovom slučaju, metoda vraća true ako je korisnik u ulozi KORISNIČKA ULOGA.

5.3. Programska autentifikacija pozivatelja

Aplikacija može programski pokrenuti postupak provjere autentičnosti pozivanjem potvrditi identitet ():

AuthenticationStatus provjera autentičnosti (zahtjev HttpServletRequest, odgovor HttpServletResponse, parametri AuthenticationParameters);

Potom se obavijesti spremnik koji će zauzvrat pozvati mehanizam provjere autentičnosti konfiguriran za aplikaciju. AuthenticationParameters parametar pruža vjerodajnicu za HttpAuthenticationMechanism:

withParams (). vjerodajnica (vjerodajnica)

The USPJEH i POŠALJI_USPUST vrijednosti Status provjere autentičnosti dizajnirati uspješnu i neuspjelu autentifikaciju dok SEND_CONTINUE signalizira status provjere autentičnosti u tijeku.

6. Pokretanje primjera

Za isticanje ovih primjera koristili smo najnoviju razvojnu verziju Open Liberty Server koja podržava Jakarta EE 8. Ovo se preuzima i instalira zahvaljujući dodatku liberty-maven koji također može primijeniti aplikaciju i pokrenuti poslužitelj.

Da biste pokrenuli primjere, samo pristupite odgovarajućem modulu i pozovite ovu naredbu:

mvn čist paket sloboda: trči

Kao rezultat toga, Maven će preuzeti poslužitelj, izgraditi, implementirati i pokrenuti aplikaciju.

7. Zaključak

U ovom smo članku pokrili konfiguraciju i implementaciju glavnih značajki novog sigurnosnog API-ja Jakarta EE 8.

Prvo smo započeli s prikazom kako konfigurirati zadane ugrađene mehanizme provjere autentičnosti i kako implementirati prilagođeni. Kasnije smo vidjeli kako konfigurirati ugrađenu trgovinu identiteta i kako implementirati prilagođenu. I na kraju, vidjeli smo kako nazvati metode SecurityContext.

Kao i uvijek, primjeri koda za ovaj članak dostupni su na GitHubu.


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