Gids voor de Java Authentication And Authorization Service (JAAS)

Java Top

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS

1. Overzicht

Java Authentication And Authorization Service (JAAS) is een Java SE-beveiligingsframework op laag niveau dat vergroot het beveiligingsmodel van op code gebaseerde beveiliging naar op gebruikers gebaseerde beveiliging. We kunnen JAAS voor twee doeleinden gebruiken:

  • Authenticatie: identificatie van de entiteit die momenteel de code uitvoert
  • Autorisatie: zorg ervoor dat deze entiteit na authenticatie over de vereiste toegangscontrolerechten of machtigingen beschikt om gevoelige code uit te voeren

In deze zelfstudie behandelen we hoe u JAAS in een voorbeeldtoepassing instelt door de verschillende API's te implementeren en configureren, met name de LoginModule.

2. Hoe JAAS werkt

Bij het gebruik van JAAS in een applicatie zijn er verschillende API's bij betrokken:

  • CallbackHandler: Wordt gebruikt voor het verzamelen van gebruikersreferenties en wordt optioneel verstrekt bij het maken van het LoginContext
  • Configuratie: Verantwoordelijk voor laden LoginModule implementaties en kunnen optioneel worden geleverd op LoginContext creatie
  • LoginModule: Effectief gebruikt voor het authenticeren van gebruikers

We gebruiken de standaardimplementatie voor het Configuratie API en bieden onze eigen implementaties voor het CallbackHandler en de LoginModule API's.

3. Verstrekken CallbackHandler Implementatie

Voordat u zich in het LoginModule implementatie moeten we eerst bieden een implementatie voor de CallbackHandler interface, die wordt gebruikt voor het verzamelen van gebruikersreferenties.

Het heeft een enkele methode, handvat(), dat accepteert een array van Bel terugs. Bovendien biedt JAAS er al veel Bel terug implementaties, en we zullen de Naam Terugbellen en Wachtwoord Terugbellen voor het verzamelen van respectievelijk de gebruikersnaam en het wachtwoord.

Laten we eens kijken naar onze implementatie van het CallbackHandler koppel:

public class ConsoleCallbackHandler implementeert CallbackHandler {@Override public void handle (Callback [] callbacks) genereert UnsupportedCallbackException {Console console = System.console (); voor (Callback callback: callbacks) {if (callback instantie van NameCallback) {NameCallback nameCallback = (NameCallback) callback; nameCallback.setName (console.readLine (nameCallback.getPrompt ())); } else if (terugbelinstantie van PasswordCallback) {PasswordCallback passwordCallback = (PasswordCallback) terugbellen; passwordCallback.setPassword (console.readPassword (passwordCallback.getPrompt ())); } else {throw nieuwe UnsupportedCallbackException (callback); }}}}

Dus om de gebruikersnaam te vragen en te lezen, hebben we het volgende gebruikt:

NameCallback nameCallback = (NameCallback) terugbellen; nameCallback.setName (console.readLine (nameCallback.getPrompt ()));

Evenzo, om het wachtwoord te vragen en te lezen:

PasswordCallback passwordCallback = (PasswordCallback) terugbellen; passwordCallback.setPassword (console.readPassword (passwordCallback.getPrompt ()));

Later zullen we zien hoe u het CallbackHandler bij het implementeren van het LoginModule.

4. Verstrekken LoginModule Implementatie

Voor de eenvoud bieden we een implementatie die hardgecodeerde gebruikers opslaat. Dus laten we het noemen InMemoryLoginModule:

openbare klasse InMemoryLoginModule implementeert LoginModule {privé statische laatste String USERNAME = "testgebruiker"; private static final String PASSWORD = "testpassword"; privé onderwerp onderwerp; privé CallbackHandler callbackHandler; privékaart sharedState; privékaartopties; private boolean loginSucceeded = false; privé Hoofd userPrincipal; // ...}

In de volgende paragrafen geven we een implementatie voor de belangrijkere methoden: initialiseren (), Log in(), en plegen ().

4.1. initialiseren ()

De LoginModule wordt eerst geladen en vervolgens geïnitialiseerd met een Onderwerpen en een CallbackHandler. Bovendien, LoginModules kunnen een Kaart voor het delen van gegevens onderling, en een ander Kaart voor het opslaan van persoonlijke configuratiegegevens:

public void initialize (onderwerp onderwerp, CallbackHandler callbackHandler, Map sharedState, Map opties) {this.subject = subject; this.callbackHandler = callbackHandler; this.sharedState = sharedState; this.options = opties; }

4.2. Log in()

In de Log in() methode, roepen we de CallbackHandler.handle () methode met een Naam Terugbellen en een Wachtwoord Terugbellen om de gebruikersnaam en het wachtwoord te vragen. Vervolgens vergelijken we deze verstrekte inloggegevens met de hardgecodeerde:

@Override openbare booleaanse login () gooit LoginException {NameCallback nameCallback = nieuwe NameCallback ("gebruikersnaam:"); PasswordCallback passwordCallback = nieuw PasswordCallback ("wachtwoord:", false); probeer {callbackHandler.handle (nieuwe callback [] {nameCallback, passwordCallback}); String gebruikersnaam = nameCallback.getName (); String wachtwoord = nieuwe String (passwordCallback.getPassword ()); if (GEBRUIKERSNAAM.equals (gebruikersnaam) && PASSWORD.equals (wachtwoord)) {loginSucceeded = true; }} catch (IOException | UnsupportedCallbackException e) {// ...} retourneer loginSucceeded; }

De Log in() methode zou moeten terugkeren waar voor een succesvolle operatie en false voor een mislukte login.

4.3. plegen ()

Als alle oproepen naar LoginModule # login slagen, wij update het Onderwerpen met een extra Opdrachtgever:

@Override public boolean commit () gooit LoginException {if (! LoginSucceeded) {return false; } userPrincipal = nieuwe UserPrincipal (gebruikersnaam); subject.getPrincipals (). add (userPrincipal); terugkeer waar; }

Anders de afbreken () methode wordt genoemd.

Op dit punt, onze LoginModule implementatie is klaar en moet worden geconfigureerd zodat het dynamisch kan worden geladen met behulp van de Configuratie serviceprovider.

5. LoginModule Configuratie

JAAS gebruikt de Configuratie serviceprovider om te laden LoginModules tijdens runtime. Standaard biedt en gebruikt het de ConfigFile implementatie waar LoginModules worden geconfigureerd via een inlogbestand. Hier is bijvoorbeeld de inhoud van het bestand dat wordt gebruikt voor onze LoginModule:

jaasApplication {com.baeldung.jaas.loginmodule.InMemoryLoginModule vereist debug = true; };

Zoals we kunnen zien, we hebben de volledig gekwalificeerde klassenaam van de LoginModule implementatie, een verplicht vlag, en een optie voor foutopsporing.

Merk ten slotte op dat we het inlogbestand ook kunnen specificeren via het java.security.auth.login.config systeemeigenschap:

$ java -Djava.security.auth.login.config = src / main / resources / jaas / jaas.login.config

We kunnen ook een of meer inlogbestanden specificeren via de eigenschap login.config.url in het Java-beveiligingsbestand, $ {java.home} /jre/lib/security/java.security:

login.config.url.1 = bestand: $ {user.home} /. java.login.config

6. Authenticatie

Ten eerste, een applicatie initialiseert het authenticatieproces door een LoginContext voorbeeld. Om dit te doen, kunnen we de volledige constructor bekijken om een ​​idee te hebben over wat we nodig hebben als parameters:

LoginContext (Stringnaam, Onderwerponderwerp, CallbackHandler callbackHandler, Configuratieconfiguratie)
  • naam: gebruikt als een index voor het laden van alleen het corresponderende LoginModules
  • onderwerpen: staat voor een gebruiker of service die wil inloggen
  • callbackHandler: verantwoordelijk voor het doorgeven van gebruikersreferenties van de applicatie naar het LoginModule
  • config: verantwoordelijk voor het laden LoginModules die overeenkomen met de name parameter

Hier gebruiken we de overbelaste constructor waar we onze CallbackHandler implementatie:

LoginContext (String naam, CallbackHandler callbackHandler)

Nu we een CallbackHandler en een geconfigureerd LoginModule, we kunnen het authenticatieproces starten door een LoginContext voorwerp:

LoginContext loginContext = nieuwe LoginContext ("jaasApplication", nieuwe ConsoleCallbackHandler ());

Op dit punt, we kunnen een beroep doen op de Log in() methode om de gebruiker te authenticeren:

loginContext.login ();

De Log in() -methode maakt op zijn beurt een nieuw exemplaar van onze LoginModule en noemt zijn Log in() methode. En, bij succesvolle authenticatie kunnen we het geauthenticeerde ophalen Onderwerpen:

Onderwerp subject = loginContext.getSubject ();

Laten we nu een voorbeeldtoepassing uitvoeren met de extensie LoginModule bedraad in:

$ mvn schoon pakket $ java -Djava.security.auth.login.config = src / main / resources / jaas / jaas.login.config \ -classpath target / core-java-security-2-0.1.0-SNAPSHOT.jar com.baeldung.jaas.JaasAuthentication

Wanneer we worden gevraagd om de gebruikersnaam en het wachtwoord op te geven, gebruiken we testgebruiker en testwachtwoord als inloggegevens.

7. Autorisatie

Autorisatie komt in het spel wanneer de gebruiker voor het eerst wordt verbonden en geassocieerd met het AccessControlContext. Met behulp van het Java-beveiligingsbeleid kunnen we een of meer toegangsbeheerrechten verlenen aan Opdrachtgevers. We kunnen dan de toegang tot gevoelige code voorkomen door het SecurityManager # checkPermission methode:

SecurityManager.checkPermission (toestemming)

7.1. Machtigingen definiëren

Een toegangscontrole rechts of toestemming is de mogelijkheid om een ​​actie op een bron uit te voeren. We kunnen een toestemming implementeren door de Toestemming abstracte klasse. Om dit te doen, moeten we een resourcenaam en een reeks mogelijke acties opgeven. We kunnen bijvoorbeeld gebruiken FilePermission om toegangsbeheerrechten voor bestanden te configureren. Mogelijke acties zijn lezen, schrijven, uitvoeren, enzovoorts. Voor scenario's waarin acties niet nodig zijn, kunnen we eenvoudig de BasicPermision.

Vervolgens zorgen we voor een implementatie van toestemming via het ResourcePermission klasse waar gebruikers mogelijk toestemming hebben om toegang te krijgen tot een bron:

openbare laatste klasse ResourcePermission breidt BasicPermission uit {openbare ResourcePermission (tekenreeksnaam) {super (naam); }}

Later zullen we een vermelding voor deze toestemming configureren via het Java-beveiligingsbeleid.

7.2. Toestemmingen verlenen

Meestal hoeven we de syntaxis van het beleidsbestand niet te kennen, omdat we altijd de Policy Tool kunnen gebruiken om er een te maken. Laten we eens kijken naar ons beleidsdossier:

hoofdgever com.sun.security.auth.UserPrincipal testgebruiker {toestemming com.baeldung.jaas.ResourcePermission "test_resource"} verlenen;

In dit voorbeeld we hebben de test_resource toestemming voor de testgebruiker gebruiker.

7.3. Toestemmingen controleren

Zodra het Onderwerpen is geauthenticeerd en machtigingen zijn geconfigureerd, we kunnen controleren of er toegang is door de Onderwerp # doAs of Onderwerp # doAsPrivilieged statische methoden. Voor dit doel bieden we een PrivilegedAction waar we de toegang tot gevoelige code kunnen beschermen. In de rennen() methode noemen we de SecurityManager # checkPermission methode om ervoor te zorgen dat de geverifieerde gebruiker de test_resource toestemming:

openbare klasse ResourceAction implementeert PrivilegedAction {@Override public Object run () {SecurityManager sm = System.getSecurityManager (); if (sm! = null) {sm.checkPermission (new ResourcePermission ("test_resource")); } System.out.println ("Ik heb toegang tot test_resource!"); null teruggeven; }}

Het laatste is om het Onderwerp # doAsPrivileged methode:

Onderwerp subject = loginContext.getSubject (); PrivilegedAction privilegedAction = nieuwe ResourceAction (); Subject.doAsPrivileged (subject, privilegedAction, null);

Net als de authenticatie, zullen we een eenvoudige applicatie voor de autorisatie uitvoeren waar, naast de LoginModule, bieden we een configuratiebestand voor machtigingen:

$ mvn schoon pakket $ java -Djava.security.manager -Djava.security.policy = src / main / resources / jaas / jaas.policy \ -Djava.security.auth.login.config = src / main / resources / jaas / jaas.login.config \ -classpath target / core-java-security-2-0.1.0-SNAPSHOT.jar com.baeldung.jaas.JaasAuthorization

8. Conclusie

In dit artikel hebben we laten zien hoe JAAS geïmplementeerd kan worden door de belangrijkste klassen en interfaces te verkennen en te laten zien hoe je ze kunt configureren. Vooral hebben we een serviceprovider geïmplementeerd LoginModule.

Zoals gewoonlijk is de code in dit artikel beschikbaar op GitHub.

Java onderkant

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS