Todo eso JAAS

¿Alguna vez ha necesitado crear un mecanismo de autenticación de inicio de sesión para una aplicación? Las probabilidades son, y probablemente más de una vez, con cada nueva implementación cercana, pero no idéntica, a la anterior. Por ejemplo, una implementación podría usar una base de datos Oracle, otra podría usar una autenticación NT y otra, un directorio LDAP (protocolo de directorio de acceso ligero). ¿No sería bueno admitir todos estos mecanismos de seguridad sin cambiar ningún código a nivel de aplicación?

Ahora, en el mundo de Java, puede hacerlo con el Servicio de autenticación y autorización de Java (JAAS). Esta API relativamente nueva era una extensión en J2SE (Java 2 Platform, Standard Edition) 1.3, es una API central en J2SE 1.4 y también es parte de la especificación J2EE (Java 2 Platform, Enterprise Edition) 1.3. En este artículo, le enseñaremos los conceptos básicos de JAAS y le mostraremos cómo aplicar JAAS de manera efectiva a aplicaciones del mundo real. Basamos la aplicación de este artículo en nuestras propias experiencias al integrar JAAS en un sistema Java existente basado en la Web que usaba un RDBMS (sistema de administración de bases de datos relacionales) para almacenar la información de inicio de sesión del usuario. Con JAAS, diseñamos mecanismos de autenticación e inicio de sesión más sólidos, flexibles y consistentes.

Puede descargar un conjunto completo de ejemplos de trabajo de los recursos a continuación (incluye fuentes Java, JSP (JavaServer Pages), configuración JAAS, con base de datos y scripts de compilación). Probamos estos ejemplos usando el servidor Resin con JDBC (Java Database Connectivity) y la base de datos MySQL.

Autenticación y autorización de Java: el panorama general

Antes de JAAS, el modelo de seguridad de Java estaba formado principalmente por su origen como un lenguaje independiente de la plataforma para aplicaciones distribuidas en red. En sus inicios, Java aparecía a menudo como código móvil, como los subprogramas basados ​​en navegador y, por lo tanto, el modelo de seguridad inicial se centró en proteger a los usuarios en función de dónde se originó el código y quién lo creó. Los primeros mecanismos de seguridad de Java, como SecurityManagers, el concepto de espacio aislado, la firma de código y los archivos de políticas, estaban destinados a proteger a los usuarios del sistema.

La invención de JAAS refleja la evolución de Java hacia un lenguaje de programación de propósito general, utilizado para implementar aplicaciones tradicionales de cliente y servidor que requieren inicio de sesión y control de acceso. JAAS protege el sistema de los usuarios al permitir o denegar el acceso según quién o qué ejecuta el programa. Si bien JAAS puede realizar tanto la autenticación como la autorización, en este artículo nos centramos principalmente en la autenticación.

JAAS puede simplificar su desarrollo de seguridad Java al colocar una capa de abstracción entre su aplicación y los distintos mecanismos de autenticación y autorización subyacentes. Esta independencia de plataformas y algoritmos le permite utilizar diferentes mecanismos de seguridad sin modificar su código a nivel de aplicación. Como ocurre con la mayoría de las API de seguridad de Java, JAAS logra esta independencia de implementación a través de un marco extensible de interfaces de proveedores de servicios conectables (SPI): un conjunto de clases e interfaces abstractas para las que se desarrollan implementaciones específicas.

La Figura 1 a continuación ofrece una descripción general de alto nivel de cómo JAAS logra esta capacidad de conexión. El código de la capa de aplicación se ocupa principalmente de un LoginContext. Debajo LoginContexthay un conjunto de uno o más mensajes de correo electrónico configurados dinámicamente LoginModule, que manejan la autenticación real utilizando la infraestructura de seguridad adecuada.

JAAS proporciona algunas LoginModuleimplementaciones de referencia , como JndiLoginModule; también puede desarrollar el suyo propio, como haremos aquí con el RdbmsLoginModule. También mostraremos cómo puede configurar rápidamente una aplicación con una variedad de implementaciones utilizando un archivo de configuración simple.

Además de ser conectable, JAAS es apilable: en el contexto de un único inicio de sesión, un conjunto de módulos de seguridad se pueden apilar uno encima del otro, cada uno llamado en orden e interactuando con una infraestructura de seguridad diferente.

Los aspectos de JAAS se basan en algunos patrones arquitectónicos de seguridad familiares y marcos existentes. La función apilable, por ejemplo, se parece deliberadamente al marco del módulo de autenticación conectable de Unix (PAM). Desde un punto de vista transaccional, JAAS adopta comportamientos similares a los protocolos de confirmación de dos fases (2PC). Los conceptos de configuración de seguridad de JAAS, incluidos los Policyarchivos y Permissions, provienen de los paquetes de seguridad J2SE 1.2. JAAS también toma prestadas ideas de otros marcos de seguridad establecidos, como los certificados X.509, de los cuales Subjectse deriva el nombre (aprenderá más sobre esto más Subjectadelante).

Nota: JAAS es solo una de varias API de seguridad Java nuevas. Para obtener más información sobre la seguridad de Java, consulte la barra lateral "El rompecabezas de seguridad de Java" y los recursos a continuación.

JAAS del lado del cliente y del servidor

Puede aplicar JAAS tanto en el cliente como en el servidor. Usarlo en el lado del cliente es sencillo, como demostraremos en breve. En el lado del servidor, las cosas se vuelven un poco más complejas. Actualmente, JAAS en el mercado de servidores de aplicaciones es un poco inconsistente; Los servidores de aplicaciones J2EE usan JAAS de manera ligeramente diferente, dependiendo de cuál use. Por ejemplo, JBossSX, utilizando su propia arquitectura, integra muy bien JAAS en su marco de seguridad general (que se detalla en el excelente artículo JavaWorld de Scott Stark "Integrate Security Infrastructures with JBossSX" (agosto de 2001)). Sin embargo, aunque WebLogic 6.x admite JAAS, los detalles difieren.

Para que pueda comprender JAAS desde la perspectiva del lado del servidor y del cliente, mostraremos ejemplos de ambos en este artículo. Y por motivos de simplicidad en el servidor, usaremos el servidor de aplicaciones Resin para que podamos comenzar con una pizarra más limpia (Resin tiene un esquema de autenticación conectable propio, pero no es estándar, por lo que usar JAAS nos brinda más portabilidad opciones más tarde).

JAAS principal

Para comenzar con JAAS, primero debe asegurarse de que esté instalado. J2SE 1.4 ya incluye JAAS; J2SE 1.3 no lo hace. Si desea seguir utilizando J2SE 1.3, descargue JAAS de Sun Microsystems. Una vez que descargue e instale JAAS en un directorio determinado, verá un subdirectorio llamado lib, que contiene un archivo llamado jaas.jar. Deberá agregar este archivo a su classpath o copiarlo a su directorio de extensiones JRE (Java Runtime Environment) (en \lib\ext, donde está la ubicación de su JRE). Entonces estará listo para JAAS. Nota: Si utiliza un servidor de aplicaciones, es posible que ya incluya JAAS. Consulte la documentación de su servidor para obtener más detalles.

Con cualquiera de estos enfoques, tenga en cuenta que puede cambiar algunos de los valores de propiedades del sistema relacionados con JAAS (así como muchos otros valores de seguridad de Java) en el archivo de propiedades de seguridad de Java. Este archivo, java.securityse encuentra en el /lib/securitydirectorio y está escrito en el formato de archivo de propiedades estándar de Java.

El uso de la autenticación JAAS desde su aplicación generalmente implica los siguientes pasos:

  1. Crear un LoginContext
  2. Opcionalmente, pase un CallbackHandleral LoginContextpara recopilar o procesar datos de autenticación
  3. Realice la autenticación llamando al método LoginContext'slogin()
  4. Realice acciones privilegiadas utilizando lo devuelto Subject(suponiendo que el inicio de sesión se realice correctamente)

Aquí tienes un ejemplo mínimo:

LoginContext lc = new LoginContext ("MiEjemplo"); intente {lc.login (); } catch (LoginException) {// Error de autenticación. } // Autenticación exitosa, ahora podemos continuar. // Podemos usar el Asunto devuelto si queremos. Asunto sub = lc.getSubject (); Subject.doAs (sub, nueva MyPrivilegedAction ());

Debajo de las sábanas, ocurren algunas otras cosas:

  1. Durante la inicialización, LoginContextbusca la entrada de configuración "MyExample"en un archivo de configuración JAAS (que usted configuró) para determinar qué LoginModules cargar (ver Figura 2)
  2. Durante la conexión, la LoginContextllama a cada uno LoginModule's login()método
  3. Cada login()método realiza la autenticación o alista unCallbackHandler
  4. Los CallbackHandlerusos de uno o más Callbacks para interactuar con el usuario y se reúnen de entrada
  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

CallbackHandlersys Callbackpermiten LoginModulerecopilar la información de autenticación necesaria de un usuario o sistema, sin dejar de ser independiente del mecanismo de interacción real. Aprovecharemos esa capacidad en nuestro diseño; RdbmsLoginModuleno depende de cómo se obtengan las credenciales de usuario (nombre de usuario / contraseña) y, por lo tanto, se pueden usar en los diferentes entornos de aplicación que ilustraremos (ya sea desde la línea de comandos o desde una JSP) .