Panduan untuk Java GSS API

Java Top

Saya baru saja mengumumkan kursus Learn Spring baru , yang berfokus pada dasar-dasar Spring 5 dan Spring Boot 2:

>> LIHAT KURSUSnya

1. Ikhtisar

Dalam tutorial ini, kita akan memahami Generic Security Service API (GSS API) dan bagaimana kita dapat menerapkannya di Java. Kita akan melihat bagaimana kita dapat mengamankan komunikasi jaringan menggunakan GSS API di Java.

Dalam prosesnya, kami akan membuat komponen klien dan server sederhana, mengamankannya dengan GSS API.

2. Apa itu GSS API?

Jadi, apa yang dimaksud dengan API Layanan Keamanan Generik? GSS API menyediakan kerangka kerja umum bagi aplikasi untuk menggunakan mekanisme keamanan yang berbeda seperti Kerberos , NTLM, dan SPNEGO dengan cara yang dapat dicolokkan. Akibatnya, ini membantu aplikasi untuk memisahkan diri dari mekanisme keamanan secara langsung.

Untuk memperjelas, keamanan di sini mencakup otentikasi, integritas data, dan kerahasiaan.

2.1. Mengapa Kami Membutuhkan GSS API?

Mekanisme keamanan seperti Kerberos, NTLM, dan Digest-MD5 sangat berbeda dalam kapabilitas dan implementasinya. Biasanya, aplikasi yang mendukung salah satu mekanisme ini merasa cukup sulit untuk beralih ke yang lain.

Di sinilah kerangka kerja umum seperti GSS API menyediakan aplikasi dengan abstraksi . Oleh karena itu, aplikasi yang menggunakan GSS API dapat menegosiasikan mekanisme keamanan yang sesuai dan menggunakannya untuk komunikasi. Semua itu tanpa benar-benar harus menerapkan detail spesifik mekanisme apa pun.

2.2. Bagaimana Cara Kerja GSS API?

GSS API adalah mekanisme berbasis token . Ia bekerja dengan pertukaran token keamanan antar rekan . Pertukaran ini biasanya terjadi melalui jaringan tetapi GSS API tidak terpengaruh oleh detail tersebut.

Token ini dibuat dan diproses oleh implementasi spesifik dari GSS API. The sintaks dan semantik dari token ini khusus untuk mekanisme keamanan dinegosiasikan antara rekan-rekan:

Tema sentral GSS API berkisar pada konteks keamanan. Kami dapat menetapkan konteks ini di antara rekan-rekan melalui pertukaran token. Kami mungkin membutuhkan banyak pertukaran token antara rekan untuk menetapkan konteksnya.

Setelah berhasil dibuat di kedua ujungnya, kita dapat menggunakan konteks keamanan untuk bertukar data dengan aman. Ini mungkin termasuk pemeriksaan integritas data dan enkripsi data, tergantung pada mekanisme keamanan yang mendasarinya.

3. Dukungan GSS API di Java

Java mendukung GSS API sebagai bagian dari paket "org.ietf.jgss". Nama paket mungkin tampak aneh. Itu karena pengikatan Java untuk GSS API didefinisikan dalam spesifikasi IETF . Spesifikasi itu sendiri tidak tergantung pada mekanisme keamanan.

Salah satu mekanisme keamanan yang populer untuk Java GSS adalah Kerberos v5.

3.1. Java GSS API

Mari kita coba memahami beberapa API inti yang membangun Java GSS:

  • GSSContext merangkum konteks keamanan GSS API dan menyediakan layanan yang tersedia dalam konteks tersebut
  • GSSCredential merangkum kredensial API GSS untuk entitas yang diperlukan untuk menetapkan konteks keamanan
  • GSSName merangkum entitas utama GSS API yang menyediakan abstraksi untuk namespace berbeda yang digunakan oleh mekanisme yang mendasarinya

Selain antarmuka di atas, ada beberapa kelas penting lainnya yang perlu diperhatikan:

  • GSSManager berfungsi sebagai kelas pabrik untuk kelas API GSS penting lainnya seperti GSSName , GSSCredential , dan GSSContext
  • Oid mewakili Universal Object Identifiers (OIDs) yang merupakan pengidentifikasi hierarki yang digunakan dalam GSS API untuk mengidentifikasi mekanisme dan format nama
  • MessageProp membungkus properti untuk menunjukkan GSSContext pada hal-hal seperti Quality of Protection (QoP) dan kerahasiaan untuk pertukaran data
  • ChannelBinding merangkum informasi pengikatan saluran opsional yang digunakan untuk memperkuat kualitas dengan otentikasi entitas peer yang disediakan

3.2. Penyedia Keamanan GSS Java

Meskipun Java GSS mendefinisikan kerangka inti untuk mengimplementasikan API GSS di Java, Java GSS tidak menyediakan implementasi. Java mengadopsi implementasi pluggable berbasis Penyedia untuk layanan keamanan termasuk Java GSS.

Mungkin ada satu atau lebih penyedia keamanan yang terdaftar dengan Java Cryptography Architecture (JCA). Setiap penyedia keamanan dapat menerapkan satu atau beberapa layanan keamanan, seperti Java GSSAPI dan mekanisme keamanan di bawahnya.

Ada penyedia GSS default yang dikirimkan bersama JDK. Namun, ada penyedia GSS khusus vendor lainnya dengan mekanisme keamanan berbeda yang dapat kami gunakan. Salah satu penyedia tersebut adalah IBM Java GSS. Kami harus mendaftarkan penyedia keamanan tersebut dengan JCA untuk dapat menggunakannya.

Selain itu, jika diperlukan, kami dapat menerapkan penyedia keamanan kami sendiri dengan kemungkinan mekanisme keamanan khusus . Namun, ini hampir tidak diperlukan dalam praktiknya.

4. GSS API Melalui Contoh

Sekarang, kita akan melihat Java GSS beraksi melalui sebuah contoh. Kami akan membuat aplikasi klien dan server sederhana. Klien lebih sering disebut sebagai inisiator dan server sebagai penerima di GSS. Kami akan menggunakan Java GSS dan Kerberos v5 di bawahnya untuk autentikasi.

4.1. Konteks GSS untuk Klien dan Server

Untuk memulainya, kita harus membuat GSSContext , baik di server dan sisi klien aplikasi.

Pertama mari kita lihat bagaimana kita dapat melakukan ini di sisi klien:

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);

Ada cukup banyak hal yang terjadi di sini, mari kita uraikan:

  • Kami mulai dengan membuat instance GSSManager
  • Kemudian kami menggunakan instance ini untuk membuat GSSContext , dengan meneruskan:
    • a GSSName representing the server principal, note the Kerberos specific principal name here
    • the Oid of mechanism to use, Kerberos v5 here
    • the initiator's credentials, null here means that default credentials will be used
    • the lifetime for the established context
  • Finally, we prepare the context for mutual authentication, confidentiality, and data integrity

Similarly, we have to define the server-side context:

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

As we can see, this is much simpler than the client-side context. The only difference here is that we need acceptor's credentials which we have used as null. As before, null means that the default credentials will be used.

4.2. GSS API Authentication

Although we have created the server and client-side GSSContext, please note that they are unestablished at this stage.

To establish these contexts, we need to exchange tokens specific to the security mechanism specified, that is 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);

This finally makes the context established at both the ends:

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

4.3. GSS API Secure Communication

Now, that we have context established at both the ends, we can start sending data with integrity and confidentiality:

// 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);

There are a couple of things happening here, let's analyze:

  • MessageProp is used by the client to set the wrap method and generate the token
  • The method wrap also adds cryptographic MIC of the data, the MIC is bundled as part of the token
  • That token is sent to the server (possibly over a network call)
  • The server leverages MessageProp again to set the unwrap method and get data back
  • Also, the method unwrap verifies the MIC for the received data, ensuring the data integrity

Hence, the client and server are able to exchange data with integrity and confidentiality.

4.4. Kerberos Set-up for the Example

Now, a GSS mechanism like Kerberos is typically expected to fetch credentials from an existing Subject. The class Subject here is a JAAS abstraction representing an entity like a person or a service. This is usually populated during a JAAS-based authentication.

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.

Secara keseluruhan, GSS API cukup ampuh dalam menyediakan layanan keamanan dengan mekanisme agnostik. Namun, dukungan untuk lebih banyak mekanisme keamanan di Java akan membawa ini lebih jauh dalam penerapan.

7. Kesimpulan

Singkatnya, dalam tutorial ini, kami memahami dasar-dasar GSS API sebagai framework keamanan. Kami mempelajari Java API untuk GSS dan memahami bagaimana kami dapat memanfaatkannya. Dalam prosesnya, kami membuat komponen klien dan server sederhana yang melakukan otentikasi timbal balik dan bertukar data dengan aman.

Lebih lanjut, kami juga melihat apa saja aplikasi praktis dari GSS API dan apa saja alternatif yang tersedia di Java.

Seperti biasa, kode dapat ditemukan di GitHub.

Jawa bawah

Saya baru saja mengumumkan kursus Learn Spring baru , yang berfokus pada dasar-dasar Spring 5 dan Spring Boot 2:

>> LIHAT KURSUSnya