Semua JAAS itu

Pernahkah Anda perlu membuat mekanisme otentikasi login untuk aplikasi? Kemungkinannya adalah, Anda memiliki, dan mungkin lebih dari sekali, dengan setiap implementasi baru hampir sama, tetapi tidak identik, dengan yang sebelumnya. Misalnya, satu implementasi mungkin menggunakan database Oracle, implementasi lainnya mungkin menggunakan otentikasi NT, dan yang lainnya, direktori LDAP (protokol direktori akses ringan). Bukankah menyenangkan untuk mendukung semua mekanisme keamanan ini tanpa mengubah kode tingkat aplikasi apa pun?

Sekarang di dunia Java, Anda dapat melakukannya dengan Java Authentication and Authorization Service (JAAS). API yang relatif baru ini merupakan perpanjangan dari J2SE (Java 2 Platform, Standard Edition) 1.3, merupakan inti API di J2SE 1.4, dan juga merupakan bagian dari spesifikasi J2EE (Java 2 Platform, Enterprise Edition) 1.3. Dalam artikel ini, kami akan mengajari Anda hal-hal penting JAAS dan menunjukkan kepada Anda bagaimana menerapkan JAAS secara efektif ke aplikasi dunia nyata. Kami mendasarkan aplikasi artikel ini pada pengalaman kami sendiri dalam mengintegrasikan JAAS ke dalam sistem berbasis Web Java yang sudah ada yang menggunakan RDBMS (sistem manajemen basis data relasional) untuk menyimpan informasi login pengguna. Dengan JAAS, kami merancang mekanisme login dan otentikasi yang lebih kuat, fleksibel, dan konsisten.

Anda dapat mengunduh satu set lengkap contoh kerja dari Sumber daya di bawah ini (termasuk sumber Java, JSP (Halaman JavaServer), konfigurasi JAAS, dengan basis data dan skrip build). Kami menguji contoh ini menggunakan server Resin dengan JDBC (Java Database Connectivity) dan database MySQL.

Otentikasi dan Otorisasi Java: Gambaran besarnya

Sebelum JAAS, model keamanan Java sebagian besar dibentuk oleh asalnya sebagai bahasa platform-independen untuk aplikasi jaringan yang terdistribusi. Di masa-masa awalnya, Java sering kali muncul sebagai kode seluler, seperti applet berbasis browser, dan oleh karena itu, model keamanan awal difokuskan untuk melindungi pengguna berdasarkan asal kode dan siapa yang membuatnya. Mekanisme keamanan Java awal seperti SecurityManagers, konsep kotak pasir, penandatanganan kode, dan file kebijakan semuanya dimaksudkan untuk melindungi pengguna dari sistem.

Penemuan JAAS mencerminkan evolusi Java menjadi bahasa pemrograman tujuan umum, yang digunakan untuk mengimplementasikan aplikasi klien dan server tradisional yang memerlukan login dan kontrol akses. JAAS melindungi sistem dari pengguna dengan mengizinkan atau menolak akses berdasarkan siapa atau apa yang menjalankan program. Meskipun JAAS dapat melakukan otentikasi dan otorisasi, dalam artikel ini, kami fokus pada otentikasi.

JAAS dapat menyederhanakan pengembangan keamanan Java Anda dengan menempatkan lapisan abstraksi antara aplikasi Anda dan otentikasi yang mendasari dan mekanisme otorisasi yang berbeda. Kemandirian dari platform dan algoritme ini memungkinkan Anda menggunakan mekanisme keamanan yang berbeda tanpa mengubah kode tingkat aplikasi Anda. Seperti kebanyakan API keamanan Java, JAAS mencapai implementasi-kemandirian ini melalui kerangka kerja yang dapat diperluas dari antarmuka penyedia layanan yang dapat dicolokkan (SPI): sekumpulan kelas dan antarmuka abstrak yang menjadi tempat pengembangan implementasi khusus.

Gambar 1 di bawah ini memberikan gambaran umum tingkat tinggi tentang bagaimana JAAS mencapai kemampuan memasukkan ini. Kode lapisan aplikasi Anda terutama berhubungan dengan LoginContext. Di bawahnya LoginContextada satu atau lebih konfigurasi dinamis LoginModule, yang menangani otentikasi aktual menggunakan infrastruktur keamanan yang sesuai.

JAAS menyediakan beberapa LoginModuleimplementasi referensi , seperti JndiLoginModule; Anda juga dapat mengembangkannya sendiri, seperti yang akan kita lakukan di sini dengan RdbmsLoginModule. Kami juga akan menunjukkan bagaimana Anda dapat dengan cepat menyiapkan aplikasi dengan pilihan implementasi menggunakan file konfigurasi sederhana.

Selain dapat dicolokkan, JAAS dapat ditumpuk: dalam konteks satu login, satu set modul keamanan dapat ditumpuk satu sama lain, masing-masing dipanggil secara berurutan dan masing-masing berinteraksi dengan infrastruktur keamanan yang berbeda.

Aspek JAAS dimodelkan pada beberapa pola arsitektur keamanan yang sudah dikenal dan kerangka kerja yang ada. Fitur stackable, misalnya, sengaja menyerupai kerangka kerja Unix Pluggable Authentication Module (PAM). Dari sudut pandang transaksional, JAAS mengadopsi perilaku yang mirip dengan protokol komit dua fase (2PC). Konsep konfigurasi keamanan JAAS, termasuk Policyfile dan Permissions, berasal dari paket keamanan J2SE 1.2. JAAS juga meminjam ide dari kerangka keamanan mapan lainnya, seperti sertifikat X.509, dari mana nama Subjecttersebut berasal (Anda akan mempelajari lebih lanjut Subjectnanti).

Catatan: JAAS hanyalah salah satu dari beberapa API keamanan Java baru. Untuk informasi lebih lanjut tentang keamanan Java, lihat sidebar "The Java Security Puzzle" dan Sumberdaya di bawah.

JAAS sisi klien dan server

Anda dapat menerapkan JAAS pada klien dan server. Menggunakannya di sisi klien sangat mudah, seperti yang akan kami tunjukkan sebentar lagi. Di sisi server, hal-hal tumbuh sedikit lebih kompleks. Saat ini, JAAS di pasar server aplikasi agak tidak konsisten; Server aplikasi J2EE menggunakan JAAS dengan sedikit berbeda, bergantung pada yang Anda gunakan. Misalnya, JBossSX, menggunakan arsitekturnya sendiri, dengan baik mengintegrasikan JAAS ke dalam kerangka keamanannya secara keseluruhan (yang dirinci dalam artikel JavaWorld yang sangat baik dari Scott Stark "Integrasikan Infrastruktur Keamanan dengan JBossSX" (Agustus 2001)). Namun, meskipun WebLogic 6.x mendukung JAAS, detailnya berbeda.

Agar Anda dapat memahami JAAS dari perspektif sisi server dan sisi klien, kami akan menunjukkan contoh keduanya di artikel ini. Dan untuk tujuan kesederhanaan di server, kita akan menggunakan server aplikasi Resin sehingga kita dapat memulai dengan batu tulis yang lebih bersih (Resin memang memiliki skema otentikasi yang dapat dicolokkan sendiri, tetapi tidak standar, jadi menggunakan JAAS memberi kita lebih banyak portabilitas pilihan nanti).

Inti JAAS

Untuk memulai JAAS, Anda harus terlebih dahulu memastikannya terpasang. J2SE 1.4 sudah termasuk JAAS; J2SE 1.3 tidak. Jika Anda ingin terus menggunakan J2SE 1.3, unduh JAAS dari Sun Microsystems. Setelah Anda mendownload dan menginstal JAAS ke direktori tertentu, Anda akan melihat subdirektori bernama lib, yang berisi satu file bernama jaas.jar. Anda harus menambahkan file ini ke classpath Anda atau menyalinnya ke direktori ekstensi JRE (Java Runtime Environment) (di \lib\ext, di mana lokasi JRE Anda). Anda kemudian siap JAAS. Catatan: Jika Anda menggunakan server aplikasi, mungkin sudah termasuk JAAS. Periksa dokumentasi server Anda untuk detailnya.

With any of these approaches, note that you can change some of the JAAS-related system property settings (as well as many other Java security settings) in the Java security properties file. This file, java.security, is located in the /lib/security directory and written in the standard Java properties file format.

Using JAAS authentication from your application typically involves the following steps:

  1. Create a LoginContext
  2. Optionally pass a CallbackHandler to the LoginContext, for gathering or processing authentication data
  3. Perform authentication by calling the LoginContext's login() method
  4. Perform privileged actions using the returned Subject (assuming login succeeds)

Here's a minimal example:

 LoginContext lc = new LoginContext("MyExample"); try { lc.login(); } catch (LoginException) { // Authentication failed. } // Authentication successful, we can now continue. // We can use the returned Subject if we like. Subject sub = lc.getSubject(); Subject.doAs(sub, new MyPrivilegedAction()); 

Underneath the covers, a few other things occur:

  1. During initialization, the LoginContext finds the configuration entry "MyExample" in a JAAS configuration file (which you configured) to determine which LoginModules to load (see Figure 2)
  2. During login, the LoginContext calls each LoginModule's login() method
  3. Each login() method performs the authentication or enlists a CallbackHandler
  4. The CallbackHandler uses one or more Callbacks to interact with the user and gather input
  5. A new Subject instance is populated with authentication details such as Principals and credentials

We'll explain further details below, but to begin, let's look at the key JAAS classes and interfaces involved in the process. These are typically divided into the following three groups:

Table 1. JAAS classes and interfaces

Common Subject, Principal, credential (credential is not any specific class, but can be any object)
Authentication LoginContext, LoginModule, CallbackHandler, Callback
Authorization Policy, AuthPermission, PrivateCredentialPermission

Most of these classes and interfaces are in the javax.security.auth package's subpackages, with some prebuilt implementations in the com.sun.security.auth package, included only in J2SE 1.4.

Note: Because we focus on authentication in this article, we don't delve into the authorization classes.

Common: Subjects, Principals, and Credentials

The Subject class represents an authenticated entity: an end-user or administrator, or a Web service, device, or another process. The class contains three sets of security information types:

  • Identities: In the form of one or more Principals
  • Public credentials: Such as name or public keys
  • Private credentials: Like passwords or private keys

Principals represent Subject identities. They implement the java.security.Principal interface (which predates JAAS) and java.io.Serializable. A Subject's most important method is getName(), which returns an identity's string name. Since a Subject instance contains an array of Principals, it can thus have multiple names. Because a social security number, login ID, email address, and so on, can all represent one user, multiple identities prove common in the real world.

The last element here, credential, is not a class or an interface, but can be any object. Credentials can include any authentication artifact, such as a ticket, key, or password, that specific security systems might require. The Subject class maintains unique Sets of private and public credentials, which can be retrieved with methods such as getPrivateCredentials() and getPublicCrendentials(). These methods are more often used by security subsystems than at the application layer.

Authentication: LoginContext

Your application layer uses LoginContext as its primary class for authenticating Subjects. LoginContext also represents where JAAS's dynamic pluggability comes into play, because when you construct a LoginContext, you specify a named configuration to load. The LoginContext typically loads the configuration information from a text file, which in turn tells the LoginContext which LoginModules to use during login.

The three commonly used methods in LoginContext are:

Table 2. LoginContext methods

login() Performs login, a relatively complex step that invokes all LoginModules specified for this configuration. If it succeeds, it creates an authenticated Subject. If it fails, it throws a LoginException.
getSubject() Returns the authenticated Subject.
logout() Logs out the authenticated Subject and removes its Principals and credentials.

We will show how to use these methods later.

Authentication: LoginModule

LoginModule is the interface to specific authentication mechanisms. J2SE 1.4 ships with a set of ready-to-use LoginModules, including:

Table 3. LoginModules in J2SE 1.4

JndiLoginModule Verifies against a directory service configured under JNDI (Java Naming and Directory Interface)
Krb5LoginModule Authenticates using Kerberos protocols
NTLoginModule Uses the current user's NT security information to authenticate
UnixLoginModule Uses the current user's Unix security information to authenticate

Along with these modules comes a set of corresponding concrete Principal implementations in the com.sun.security.auth package, such as NTDomainPrincipal and UnixPrincipal.

The LoginModule interface has five methods:

Table 4. LoginModule methods

initialize() Called after the LoginModule is constructed.
login() Performs the authentication.
commit() Called by the LoginContext after it has accepted the results from all LoginModules defined for this application. We assign Principals and credentials to the Subject here.
abort() Called when any LoginModule for this application fails (even though earlier ones in sequence may have succeeded—thus akin to a 2PC model). No Principals or credentials are assigned to the Subject.
logout() Removes the Principals and credentials associated with the Subject.

The application layer calls none of these methods directly—the LoginContext invokes them as needed. Our example below will elaborate on these methods' implementations.

Authentication: CallbackHandlers and Callbacks

CallbackHandlers dan Callbacks memungkinkan LoginModulemengumpulkan informasi otentikasi yang diperlukan dari pengguna atau sistem, sementara tetap independen dari mekanisme interaksi yang sebenarnya. Kami akan memanfaatkan kemampuan itu dalam desain kami — kami RdbmsLoginModuletidak bergantung pada bagaimana kredensial pengguna (nama pengguna / kata sandi) diperoleh dan dengan demikian dapat digunakan dalam lingkungan aplikasi berbeda yang akan kami gambarkan (baik dari baris perintah atau dari JSP) .