Ein Handbuch zur Java GSS API

Java Top

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs

1. Übersicht

In diesem Tutorial lernen wir die GSS-API (Generic Security Service API) kennen und wie wir sie in Java implementieren können. Wir werden sehen, wie wir die Netzwerkkommunikation mithilfe der GSS-API in Java sichern können.

Dabei erstellen wir einfache Client- und Serverkomponenten und sichern sie mit der GSS-API.

2. Was ist die GSS- API?

Was ist die Generic Security Service API? Die GSS-API bietet ein generisches Framework für Anwendungen, mit dem verschiedene Sicherheitsmechanismen wie Kerberos , NTLM und SPNEGO steckbar verwendet werden können. Folglich hilft es Anwendungen, sich direkt von den Sicherheitsmechanismen zu entkoppeln.

Zur Verdeutlichung umfasst die Sicherheit hier Authentifizierung, Datenintegrität und Vertraulichkeit.

2.1. Warum brauchen wir GSS API?

Sicherheitsmechanismen wie Kerberos, NTLM und Digest-MD5 unterscheiden sich in ihren Funktionen und Implementierungen erheblich. In der Regel ist es für eine Anwendung, die einen dieser Mechanismen unterstützt, ziemlich entmutigend, zu einem anderen zu wechseln.

Hier bietet ein generisches Framework wie die GSS-API Anwendungen eine Abstraktion . Daher können Anwendungen, die die GSS-API verwenden, einen geeigneten Sicherheitsmechanismus aushandeln und diesen für die Kommunikation verwenden. All dies, ohne dass mechanismusspezifische Details implementiert werden müssen.

2.2. Wie funktioniert die GSS- API?

Die GSS-API ist ein tokenbasierter Mechanismus . Es funktioniert durch den Austausch von Sicherheitstoken zwischen Peers . Dieser Austausch findet normalerweise über ein Netzwerk statt, aber die GSS-API reagiert nicht auf diese Details.

Diese Token werden von den spezifischen Implementierungen der GSS-API generiert und verarbeitet. Die Syntax und Semantik dieser Token sind spezifisch für den zwischen den Peers ausgehandelten Sicherheitsmechanismus :

Das zentrale Thema der GSS-API dreht sich um einen Sicherheitskontext. Wir können diesen Kontext zwischen Gleichaltrigen durch den Austausch von Token herstellen. Wir können mehrere Austausch von Token zwischen Peers müssen den Kontext zu etablieren.

Sobald dies an beiden Enden erfolgreich eingerichtet wurde, können wir den Sicherheitskontext verwenden, um Daten sicher auszutauschen. Dies kann abhängig vom zugrunde liegenden Sicherheitsmechanismus Datenintegritätsprüfungen und Datenverschlüsselung umfassen.

3. GSS API-Unterstützung in Java

Java unterstützt die GSS-API als Teil des Pakets „org.ietf.jgss“. Der Paketname mag eigenartig erscheinen. Dies liegt daran, dass die Java-Bindungen für die GSS-API in einer IETF-Spezifikation definiert sind . Die Spezifikation selbst ist unabhängig vom Sicherheitsmechanismus.

Einer der beliebtesten Sicherheitsmechanismen für Java GSS ist Kerberos v5.

3.1. Java GSS API

Lassen Sie uns versuchen, einige der Kern-APIs zu verstehen, die Java GSS erstellen:

  • GSSContext kapselt den GSS-API-Sicherheitskontext und stellt im Kontext verfügbare Dienste bereit
  • GSSCredential kapselt die GSS-API-Anmeldeinformationen für eine Entität, die zum Einrichten des Sicherheitskontexts erforderlich ist
  • GSSName kapselt die Hauptentität der GSS-API, die eine Abstraktion für verschiedene Namespaces bereitstellt, die von zugrunde liegenden Mechanismen verwendet werden

Abgesehen von den oben genannten Schnittstellen sind nur wenige andere wichtige Klassen zu beachten:

  • GSSManager dient als Factory-Klasse für andere wichtige GSS-API-Klassen wie GSSName , GSSCredential und GSSContext
  • Oid stellt die Universal Object Identifiers (OIDs) dar, bei denen es sich um hierarchische Bezeichner handelt, die in der GSS-API zur Identifizierung von Mechanismen und Namensformaten verwendet werden
  • MessageProp verpackt Eigenschaften, um GSSContext zu Themen wie Quality of Protection (QoP) und Vertraulichkeit für den Datenaustausch anzuzeigen
  • ChannelBinding kapselt die optionalen Kanalbindungsinformationen , die zur Verbesserung der Qualität der Peer-Entity-Authentifizierung verwendet werden

3.2. Java GSS-Sicherheitsanbieter

Während Java GSS das Kernframework für die Implementierung der GSS-API in Java definiert, bietet es keine Implementierung. Java Nimmt Provider basierte Plug - Implementierungen für Sicherheitsdienste einschließlich Java GSS.

Es können ein oder mehrere solcher Sicherheitsanbieter bei der Java Cryptography Architecture (JCA) registriert sein . Jeder Sicherheitsanbieter kann einen oder mehrere Sicherheitsdienste wie Java GSSAPI und darunter liegende Sicherheitsmechanismen implementieren.

Es gibt einen Standard-GSS-Anbieter, der mit dem JDK geliefert wird. Es gibt jedoch andere herstellerspezifische GSS-Anbieter mit unterschiedlichen Sicherheitsmechanismen, die wir verwenden können. Ein solcher Anbieter ist IBM Java GSS. Wir müssen einen solchen Sicherheitsanbieter bei JCA registrieren, um ihn verwenden zu können.

Darüber hinaus können wir bei Bedarf unseren eigenen Sicherheitsanbieter mit möglicherweise benutzerdefinierten Sicherheitsmechanismen implementieren . Dies wird in der Praxis jedoch kaum benötigt.

4. GSS-API anhand eines Beispiels

Jetzt sehen wir Java GSS anhand eines Beispiels in Aktion. Wir erstellen eine einfache Client- und Serveranwendung. Der Client wird in GSS häufiger als Initiator und Server als Akzeptor bezeichnet. Wir werden Java GSS und Kerberos v5 darunter zur Authentifizierung verwenden.

4.1. GSS-Kontext für Client und Server

Zunächst müssen wir einen GSSContext sowohl auf der Server- als auch auf der Clientseite der Anwendung einrichten .

Lassen Sie uns zunächst sehen, wie wir dies auf der Client-Seite tun können:

GSSManager manager = GSSManager.getInstance(); String serverPrinciple = "HTTP/[email protected]"; GSSName serverName = manager.createName(serverPrinciple, null); Oid krb5Oid = new Oid("1.2.840.113554.1.2.2"); GSSContext clientContext = manager.createContext( serverName, krb5Oid, (GSSCredential)null, GSSContext.DEFAULT_LIFETIME); clientContext.requestMutualAuth(true); clientContext.requestConf(true); clientContext.requestInteg(true);

Hier passiert eine Menge, lasst uns sie aufschlüsseln:

  • Wir beginnen mit der Erstellung einer Instanz des GSSManager
  • Dann verwenden wir diese Instanz, um GSSContext zu erstellen und weiterzuleiten :
    • ein GSSName den Server Haupt darstellt, beachten Sie die Kerberos - spezifische Prinzipalnamen hier
    • Die Oid des zu verwendenden Mechanismus, Kerberos v5 hier
    • Die Anmeldeinformationen des Initiators, hier null , bedeuten, dass Standardanmeldeinformationen verwendet werden
    • die Lebensdauer für den etablierten Kontext
  • Schließlich bereiten wir den Kontext für gegenseitige Authentifizierung, Vertraulichkeit und Datenintegrität vor

Ebenso müssen wir den serverseitigen Kontext definieren:

GSSManager manager = GSSManager.getInstance(); GSSContext serverContext = manager.createContext((GSSCredential) null);

Wie wir sehen können, ist dies viel einfacher als der clientseitige Kontext. Der einzige Unterschied besteht darin, dass wir die Anmeldeinformationen des Akzeptors benötigen, die wir als null verwendet haben . Nach wie vor bedeutet null , dass die Standardanmeldeinformationen verwendet werden.

4.2. GSS-API-Authentifizierung

Obwohl wir den server- und clientseitigen GSSContext erstellt haben , beachten Sie bitte, dass diese zu diesem Zeitpunkt noch nicht eingerichtet sind.

Um diese Kontexte herzustellen, müssen Token ausgetauscht werden, die für den angegebenen Sicherheitsmechanismus spezifisch sind, dh Kerberos v5:

// On the client-side clientToken = clientContext.initSecContext(new byte[0], 0, 0); sendToServer(clientToken); // This is supposed to be send over the network // On the server-side serverToken = serverContext.acceptSecContext(clientToken, 0, clientToken.length); sendToClient(serverToken); // This is supposed to be send over the network // Back on the client side clientContext.initSecContext(serverToken, 0, serverToken.length);

Dadurch wird der Kontext an beiden Enden endgültig hergestellt:

assertTrue(serverContext.isEstablished()); assertTrue(clientContext.isEstablished());

4.3. GSS API Sichere Kommunikation

Nachdem wir an beiden Enden einen Kontext eingerichtet haben, können wir Daten mit Integrität und Vertraulichkeit senden :

// On the client-side byte[] messageBytes = "Baeldung".getBytes(); MessageProp clientProp = new MessageProp(0, true); byte[] clientToken = clientContext.wrap(messageBytes, 0, messageBytes.length, clientProp); sendToClient(serverToken); // This is supposed to be send over the network // On the server-side MessageProp serverProp = new MessageProp(0, false); byte[] bytes = serverContext.unwrap(clientToken, 0, clientToken.length, serverProp); String string = new String(bytes); assertEquals("Baeldung", string);

Hier passieren ein paar Dinge, analysieren wir:

  • MessageProp wird vom Client verwendet, um die Wrap- Methode festzulegen und das Token zu generieren
  • Das Verfahren Wrap fügt auch kryptographischen MIC der Daten wird der MIC als Teil des Tokens gebündelt
  • Dieses Token wird an den Server gesendet (möglicherweise über einen Netzwerkanruf).
  • Der Server nutzt MessageProp erneut, um die Unwrap- Methode festzulegen und Daten zurückzugewinnen
  • Außerdem überprüft die Methode zum Auspacken die MIC für die empfangenen Daten, um die Datenintegrität sicherzustellen

Somit können Client und Server Daten mit Integrität und Vertraulichkeit austauschen.

4.4. Kerberos-Setup für das Beispiel

Von einem GSS-Mechanismus wie Kerberos wird normalerweise erwartet, dass er Anmeldeinformationen von einem vorhandenen Betreff abruft . Die Klasse Subject ist hier eine JAAS-Abstraktion, die eine Entität wie eine Person oder eine Dienstleistung darstellt. Dies wird normalerweise während einer JAAS-basierten Authentifizierung ausgefüllt.

However, for our example, we'll not directly use a JAAS-based authentication. We'll let Kerberos obtain credentials directly, in our case using a keytab file. There is a JVM system parameter to achieve that:

-Djavax.security.auth.useSubjectCredsOnly=false

However, the defaults Kerberos implementation provided by Sun Microsystem relies on JAAS to provide authentication.

This may sound contrary to what we just discussed. Please note that we can explicitly use JAAS in our application which will populate the Subject. Or leave it to the underlying mechanism to authenticate directly, where it anyways uses JAAS. Hence, we need to provide a JAAS configuration file to the underlying mechanism:

com.sun.security.jgss.initiate { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab=example.keytab principal="client/localhost" storeKey=true; }; com.sun.security.jgss.accept { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab=example.keytab storeKey=true principal="HTTP/localhost"; };

This configuration is straight-forward, where we have defined Kerberos as the required login module for both initiator and acceptor. Additionally, we have configured to use the respective principals from a keytab file. We can pass this JAAS configuration to JVM as a system parameter:

-Djava.security.auth.login.config=login.conf

Here, the assumption is that we have access to a Kerberos KDC. In the KDC we have set up the required principals and obtained the keytab file to use, let's say “example.keytab”.

Additionally, we need the Kerberos configuration file pointing to the right KDC:

[libdefaults] default_realm = EXAMPLE.COM udp_preference_limit = 1 [realms] EXAMPLE.COM = { kdc = localhost:52135 }

This simple configuration defines a KDC running on port 52135 with a default realm as EXAMPLE.COM. We can pass this to JVM as a system parameter:

-Djava.security.krb5.conf=krb5.conf

4.5. Running the Example

To run the example, we have to make use of the Kerberos artifacts discussed in the last section.

Also, we need to pass the required JVM parameters:

java -Djava.security.krb5.conf=krb5.conf \ -Djavax.security.auth.useSubjectCredsOnly=false \ -Djava.security.auth.login.config=login.conf \ com.baeldung.jgss.JgssUnitTest

This is sufficient for Kerberos to perform the authentication with credentials from keytab and GSS to establish the contexts.

5. GSS API in Real World

While GSS API promises to solve a host of security problems through pluggable mechanisms, there are few use cases which have been more widely adopted:

  • It's widely used in SASL as a security mechanism, especially where Kerberos is the underlying mechanism of choice. Kerberos is a widely used authentication mechanism, especially within an enterprise network. It is really useful to leverage a Kerberised infrastructure to authenticate a new application. Hence, GSS API bridges that gap nicely.
  • It's also used in conjugation with SPNEGO to negotiate a security mechanism when one is not known beforehand. In this regard, SPNEGO is a pseudo mechanism of GSS API in a sense. This is widely supported in all modern browsers making them capable of leveraging Kerberos-based authentication.

6. GSS API in Comparision

GSS API is quite effective in providing security services to applications in a pluggable manner. However, it's not the only choice to achieve this in Java.

Let's understand what else Java has to offer and how do they compare against GSS API:

  • Java Secure Socket Extension (JSSE): JSSE is a set of packages in Java that implements Secure Sockets Layer (SSL) for Java. It provides data encryption, client and server authentication, and message integrity. Unlike GSS API, JSSE relies on a Public Key Infrastructure (PKI) to work. Hence, the GSS API works out to be more flexible and lightweight than JSSE.
  • Java Simple Authentication and Security Layer (SASL): SASL is a framework for authentication and data security for internet protocols which decouples them from specific authentication mechanisms. This is similar in scope to GSS API. However, Java GSS has limited support for underlying security mechanisms through available security providers.

Insgesamt ist die GSS-API sehr leistungsfähig, um Sicherheitsdienste mechanismusunabhängig bereitzustellen. Die Unterstützung für mehr Sicherheitsmechanismen in Java wird dies jedoch weiter vorantreiben.

7. Fazit

Zusammenfassend haben wir in diesem Tutorial die Grundlagen der GSS-API als Sicherheitsrahmen verstanden. Wir haben die Java-API für GSS durchgesehen und verstanden, wie wir sie nutzen können. Dabei haben wir einfache Client- und Serverkomponenten erstellt, die eine gegenseitige Authentifizierung durchführen und Daten sicher austauschen.

Außerdem haben wir gesehen, welche praktischen Anwendungen die GSS-API bietet und welche Alternativen in Java verfügbar sind.

Wie immer ist der Code auf GitHub zu finden.

Java unten

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs