Para la autenticación, WebSphere eXtreme Scale proporciona un tiempo de ejecución para enviar la credencial del cliente al servidor y, a continuación, llama al plug-in autenticador para autenticar los usuarios.
WebSphere eXtreme Scale requiere que implemente los siguientes plug-ins para completar la autenticación.
Cuando un cliente de eXtreme Scale se conecta a un servidor que requiere la autenticación, es necesario que el cliente proporcione una credencial de cliente. Una credencial de cliente se representa mediante una interfaz com.ibm.websphere.objectgrid.security.plugins.Credential. Una credencial de cliente puede ser un par de nombre de usuario y contraseña, un ticket Kerberos, un certificado de cliente o datos en cualquier formato que hayan acordado el cliente y el servidor. Esta interfaz define explícitamente los métodos equals(Object) y hashCode. Estos dos métodos son importantes porque los objetos Subject autenticados se almacenan en memoria caché utilizando el objeto Credential como la clave en el lado del servidor. WebSphere eXtreme Scale también proporciona un plug-in para generar una credencial. Este plug-in se representa mediante la interfaz com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator y es práctico si la credencial puede caducar. En este caso, se llama al método getCredential para renovar una credencial.
La interfaz Credential define explícitamente los métodos equals(Object) y hashCode. Estos dos métodos son importantes porque los objetos Subject autenticados se almacenan en memoria caché utilizando el objeto Credential como la clave en el lado del servidor.
También puede utilizar el plug-in proporcionado para generar una credencial. Este plug-in se representa mediante la interfaz com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator, y es práctico si la credencial puede caducar. En este caso, se llama al método getCredential para renovar una credencial. Consulte Interfaz CredentialGenerator si desea más detalles.
Hay tres implementaciones predeterminadas proporcionadas para las interfaces Credential:
WebSphere eXtreme Scale también proporciona un plug-in para generar una credencial. Este plug-in se representa mediante la interfaz com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator.WebSphere eXtreme Scale proporciona dos implementaciones incorporadas predeterminadas:
UserPasswordCredential y UserPasswordCredentialGenerator
Con finalidades de pruebas, WebSphere eXtreme Scale proporciona las siguientes implementaciones de plug-in:
com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredential
com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredentialGenerator
La credencial de contraseña de usuario almacena un ID de usuario y una contraseña. El generador de credenciales de contraseñas de usuarios contendrá este ID de usuario y contraseña.
El siguiente código de ejemplo muestra cómo implementar estos dos plug-ins.
UserPasswordCredential.java
// Este programa de ejemplo se proporciona TAL CUAL y se puede utilizar, ejecutar, copiar y modificar
// sin que el cliente tenga que pagar derechos
// (a) para su propia formación,
// (b) para desarrollar aplicaciones diseñadas para ejecutarse con un producto IBM WebSphere,
// para uso interno propio del cliente o para su redistribución por parte del cliente, como parte de una
// aplicación de ese tipo, en los productos propios del cliente.
// Material bajo licencia - Propiedad de IBM
// 5724-J34 © COPYRIGHT International Business Machines Corp. 2007
package com.ibm.websphere.objectgrid.security.plugins.builtins;
import com.ibm.websphere.objectgrid.security.plugins.Credential;
/**
* Esta clase representa una credencial que contiene un ID de usuario y una contraseña.
*
* @ibm-api
* @since WAS XD 6.0.1
*
* @see Credential
* @see UserPasswordCredentialGenerator#getCredential()
*/
public class UserPasswordCredential implements Credential {
private static final long serialVersionUID = 1409044825541007228L;
private String ivUserName;
private String ivPassword;
/**
* Crea una UserPasswordCredential con el nombre de usuario y contraseña
* específicos.
*
* @param userName el nombre de usuario para esta credencial
* @param password la contraseña para esta credencial
*
* @throws IllegalArgumentException si userName o password es <code>null</code>
*/
public UserPasswordCredential(String userName, String password) {
super();
if (userName == null || password == null) {
throw new IllegalArgumentException("El nombre y la contraseña no pueden ser nulos.");
}
this.ivUserName = userName;
this.ivPassword = password;
}
/**
* Obtiene el nombre de usuario para esta credencial.
*
* @return el argumento del nombre de usuario que se ha pasado al constructor
* o <code>setUserName(String)</code>
* de esta clase
*
* @see #setUserName(String)
*/
public String getUserName() {
return ivUserName;
}
/**
* Establece el nombre de usuario para esta credencial.
*
* @param userName el nombre de usuario a establecer.
*
* @throws IllegalArgumentException si userName es <code>null</code>
*/
public void setUserName(String userName) {
if (userName == null) {
throw new IllegalArgumentException("El nombre de usuario no puede ser nulo.");
}
this.ivUserName = userName;
}
/**
* Obtiene la contraseña para esta credencial.
*
* @return el argumento de contraseña que se ha pasado al constructor
* o el método <code>setPassword(String)</code>
* de esta clase
*
* @see #setPassword(String)
*/
public String getPassword() {
return ivPassword;
}
/**
* Establece la contraseña para esta credencial.
*
* @param password la contraseña a establecer.
*
* @throws IllegalArgumentException si password es <code>null</code>
*/
public void setPassword(String password) {
if (password == null) {
throw new IllegalArgumentException("La contraseña no puede ser nula.");
}
this.ivPassword = password;
}
/**
* Comprueba si dos objetos UserPasswordCredential son iguales.
* <p>
* Dos objetos UserPasswordCredential son iguales si y sólo si sus nombres de usuario
* y contraseñas son iguales.
*
* @param o el objeto que se está comprobando que sea igual que este objeto.
*
* @return <code>true</code> si los dos objetos UserPasswordCredential son equivalentes.
*
* @see Credential#equals(Object)
*/
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof UserPasswordCredential) {
UserPasswordCredential other = (UserPasswordCredential) o;
return other.ivPassword.equals(ivPassword) && other.ivUserName.equals(ivUserName);
}
return false;
}
/**
* Devuelve el código hash del objeto UserPasswordCredential.
*
* @return el código hash de este objeto
*
* @see Credential#hashCode()
*/
public int hashCode() {
return ivUserName.hashCode() + ivPassword.hashCode();
}
}
UserPasswordCredentialGenerator.java
// Este programa de ejemplo se proporciona TAL CUAL y se puede utilizar, ejecutar, copiar y modificar
// sin que el cliente tenga que pagar derechos
// (a) para su propia formación,
// (b) para desarrollar aplicaciones diseñadas para ejecutarse con un producto IBM WebSphere,
// para uso interno propio del cliente o para su redistribución por parte del cliente, como parte de una
// aplicación de ese tipo, en los productos propios del cliente.
// Material bajo licencia - Propiedad de IBM
// 5724-J34 © COPYRIGHT International Business Machines Corp. 2007
package com.ibm.websphere.objectgrid.security.plugins.builtins;
import java.util.StringTokenizer;
import com.ibm.websphere.objectgrid.security.plugins.Credential;
import com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator;
/**
* Este generador de credenciales crea objetos <code>UserPasswordCredential</code>.
* <p>
* UserPasswordCredentialGenerator tiene una relación de uno a uno con
* UserPasswordCredential porque sólo puede crear una UserPasswordCredential
* que represente una identidad.
*
* @since WAS XD 6.0.1
* @ibm-api
*
* @see CredentialGenerator
* @see UserPasswordCredential
*/
public class UserPasswordCredentialGenerator implements CredentialGenerator {
private String ivUser;
private String ivPwd;
/**
* Crea un UserPasswordCredentialGenerator sin nombre de usuario o contraseña.
*
* @see #setProperties(String)
*/
public UserPasswordCredentialGenerator() {
super();
}
/**
* Crea un UserPasswordCredentialGenerator con un nombre de usuario y contraseña
* específicos
*
* @param user el nombre de usuario
* @param pwd la contraseña
*/
public UserPasswordCredentialGenerator(String user, String pwd) {
ivUser = user;
ivPwd = pwd;
}
/**
* Crea un nuevo objeto <code>UserPasswordCredential</code> utilizando el
* nombre de usuario y la contraseña de este objeto.
*
* @return una nueva instancia de <code>UserPasswordCredential</code>
*
* @see CredentialGenerator#getCredential()
* @see UserPasswordCredential
*/
public Credential getCredential() {
return new UserPasswordCredential(ivUser, ivPwd);
}
/**
* Obtiene la contraseña para este generador de credenciales.
*
* @return el argumento de contraseña que se ha pasado al constructor
*/
public String getPassword() {
return ivPwd;
}
/**
* Obtiene el nombre de usuario para esta credencial.
*
* @return el argumento de usuario que se ha pasado al constructor
* de esta clase
*/
public String getUserName() {
return ivUser;
}
/**
* Establece propiedades adicionales, en concreto, un nombre de usuario y una contraseña.
*
* @param properties una serie de propiedades con un nombre de usuario y
* una contraseña separados por un blanco.
*
* @throws IllegalArgumentException si el formato no es válido
*/
public void setProperties(String properties) {
StringTokenizer token = new StringTokenizer(properties, " ");
if (token.countTokens() != 2) {
throw new IllegalArgumentException(
"Las propiedades deben tener un nombre de usuario y una contraseña separados por un blanco.");
}
ivUser = token.nextToken();
ivPwd = token.nextToken();
}
/**
* Comprueba si dos objetos UserPasswordCredentialGenerator son iguales.
* <p>
* Dos objetos UserPasswordCredentialGenerator son iguales si y sólo si
* sus nombres de usuario y contraseñas son iguales.
*
* @param obj el objeto que se está comprobando que sea igual que este objeto.
*
* @return <code>true</code> si ambos objetos UserPasswordCredentialGenerator
* son equivalentes.
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj != null && obj instanceof UserPasswordCredentialGenerator) {
UserPasswordCredentialGenerator other = (UserPasswordCredentialGenerator) obj;
boolean bothUserNull = false;
boolean bothPwdNull = false;
if (ivUser == null) {
if (other.ivUser == null) {
bothUserNull = true;
} else {
return false;
}
}
if (ivPwd == null) {
if (other.ivPwd == null) {
bothPwdNull = true;
} else {
return false;
}
}
return (bothUserNull || ivUser.equals(other.ivUser)) && (bothPwdNull || ivPwd.equals(other.ivPwd));
}
return false;
}
/**
* Devuelve el código hash del objeto UserPasswordCredentialGenerator.
*
* @return el código hash de este objeto
*/
public int hashCode() {
return ivUser.hashCode() + ivPwd.hashCode();
}
}
La clase UserPasswordCredential contiene dos atributos: nombre de usuario y contraseña. UserPasswordCredentialGenerator actúa como una fábrica que contiene los objetos UserPasswordCredential.
WSTokenCredential y WSTokenCredentialGenerator
Cuando los clientes y los servidores de WebSphere eXtreme Scale están desplegados en WebSphere Application Server, la aplicación cliente puede utilizar estas dos implementaciones incorporadas cuando se cumplen las siguientes condiciones:
En esta situación, el cliente puede utilizar la clase com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredentialGenerator para generar una credencial. El servidor utiliza la clase de implementación WSAuthenticator para autenticar la credencial.
Este escenario se aprovecha del hecho de que el cliente eXtreme Scale ya se ha autenticado. Puesto que los servidores de aplicaciones que tienen los servidores en el mismo dominio de seguridad que los servidores de aplicaciones que alojan los clientes, las señales de seguridad se pueden propagar del cliente al servidor, de forma que no es necesario que se vuelva a autenticar el mismo registro de usuarios.
Después de que el cliente de eXtreme Scale recupere el objeto Credential mediante el objeto CredentialGenerator, el objeto Credential de este cliente se envía junto con la solicitud del cliente al servidor de eXtreme Scale. El servidor autentica el objeto Credential antes de procesar la solicitud. Si el objeto Credential se autentica correctamente, se devuelve un objeto Subject para representar este cliente.
A continuación, el objeto Subject se almacena en memoria caché y caduca después de que su vida útil alcance el valor de tiempo de espera de la sesión. El valor de tiempo de espera del inicio de sesión puede establecerse mediante la propiedad loginSessionExpirationTime del archivo XML del clúster. Por ejemplo, establecer loginSessionExpirationTime="300" hace que el objeto Subject caduque en 300 segundos.
Este objeto Subject se utilizará para autorizar la solicitud que se muestra más adelante. Un servidor de eXtreme Scale utiliza el plug-in Authenticator para autenticar el objeto Credential. Consulte Autenticador si desea más detalles.
El plug-in Authenticator es donde el tiempo de ejecución de eXtreme Scale autentica el objeto Credential del registro de usuarios del cliente, por ejemplo, un servidor LDAP (Lightweight Directory Access Protocol).
WebSphere eXtreme Scale no proporciona una configuración de registro de usuarios disponible inmediatamente. La configuración y la gestión del registro de usuarios se deja fuera de WebSphere eXtreme Scale con fines de simplicidad y flexibilidad. Este plug-in implementa la conexión y la autenticación al registro de usuarios. Por ejemplo, una implementación de autenticador extrae el ID de usuario y la contraseña de la credencial, los utiliza para conectarse a un servidor LDAP y validarlo, y crea un objeto Subject como resultado de la autenticación. La implementación podría utilizar los módulos de inicio de sesión JAAS. Como resultado de la autenticación, se devuelve un objeto Subject.
Tenga en cuenta que este método crea dos excepciones: InvalidCredentialException y ExpiredCredentialException. La excepción InvalidCredentialException indica que la credencial no es válida. La excepción ExpiredCredentialException indica que la credencial ha caducado. Si se genera una de estas dos excepciones del método de autenticación, las excepciones se envían de vuelta al cliente. Sin embargo, el tiempo de ejecución del cliente maneja estas dos excepciones de forma distinta:
La interfaz Authenticator proporciona una gran flexibilidad. Puede implementar la interfaz Authenticator de su propia manera específica. Por ejemplo, puede implementar esta interfaz para soportar dos registros de usuarios distintos.
WebSphere eXtreme Scale proporciona implementaciones de plug-in de autenticador de ejemplo. Excepto para el plug-in de autenticador de WebSphere Application Server, las otras implementaciones sólo son ejemplos con finalidades de prueba.
KeyStoreLoginAuthenticator
Este ejemplo utiliza una implementación incorporada de eXtreme Scale: KeyStoreLoginAuthenticator, que tiene finalidades de pruebas y de ejemplo (un almacén de claves es un registro de usuarios sencillo y no se debe utilizar para un entorno de producción). De nuevo, la clase se visualiza para demostrar de forma adicional cómo implementar un autenticador.
KeyStoreLoginAuthenticator.java
// Este programa de ejemplo se proporciona TAL CUAL y se puede utilizar, ejecutar, copiar y modificar
// sin que el cliente tenga que pagar derechos
// (a) para su propia formación,
// (b) para desarrollar aplicaciones diseñadas para ejecutarse con un producto IBM WebSphere,
// para uso interno propio del cliente o para su redistribución por parte del cliente, como parte de una
// aplicación de ese tipo, en los productos propios del cliente.
// Material bajo licencia - Propiedad de IBM
// 5724-J34 © COPYRIGHT International Business Machines Corp. 2007
package com.ibm.websphere.objectgrid.security.plugins.builtins;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import com.ibm.websphere.objectgrid.security.plugins.Authenticator;
import com.ibm.websphere.objectgrid.security.plugins.Credential;
import com.ibm.websphere.objectgrid.security.plugins.ExpiredCredentialException;
import com.ibm.websphere.objectgrid.security.plugins.InvalidCredentialException;
import com.ibm.ws.objectgrid.Constants;
import com.ibm.ws.objectgrid.ObjectGridManagerImpl;
import com.ibm.ws.objectgrid.security.auth.callback.UserPasswordCallbackHandlerImpl;
/**
* Esta clase es una implementación de la interfaz <code>Authenticator</code>
* cuando un nombre de usuario y una contraseña se utilizan como credencial.
* <p>
* Cuando se utiliza la autenticación de ID de usuario y contraseña, la credencial pasada al
* método <code>authenticate(Credential)</code> es un objeto UserPasswordCredential.
* <p>
* Esta implementación utilizará un <code>KeyStoreLoginModule</code> para autenticar
* al usuario en el almacén de claves utilizando el módulo de inicio de sesión JAAS "KeyStoreLogin". El
* almacén de claves se puede configurar como una opción para la clase
* <code>KeyStoreLoginModule</code>. Consulte la clase
* <code>KeyStoreLoginModule</code> para obtener más detalles sobre cómo configurar
* el archivo de configuración de inicio de sesión JAAS.
* <p>
* Esta clase sólo sirve de ejemplo y de comprobación rápida. Los usuarios deben
* crear su propia implementación de Authenticator que puede adaptarse mejor al
* entorno.
*
* @ibm-api
* @since WAS XD 6.0.1
*
* @see Authenticator
* @see KeyStoreLoginModule
* @see UserPasswordCredential
*/
public class KeyStoreLoginAuthenticator implements Authenticator {
/**
* Crea un nuevo KeyStoreLoginAuthenticator.
*/
public KeyStoreLoginAuthenticator() {
super();
}
/**
* Autentica un <code>UserPasswordCredential</code>.
* <p>
* Utiliza el nombre de usuario y la contraseña de la UserPasswordCredential especificada
* para iniciar la sesión en el KeyStoreLoginModule llamado "KeyStoreLogin".
*
* @throws InvalidCredentialException si la credencial no es una
* UserPasswordCredential o se produce un error durante el proceso
* de la UserPasswordCredential proporcionada
*
* @throws ExpiredCredentialException si la credencial ha caducado. Esta excepción
* no la utiliza esta implementación
*
* @see Authenticator#authenticate(Credential)
* @see KeyStoreLoginModule
*/
public Subject authenticate(Credential credential) throws InvalidCredentialException,
ExpiredCredentialException {
if (credential == null) {
throw new InvalidCredentialException("Supplied credential is null");
}
if (! (credential instanceof UserPasswordCredential) ) {
throw new InvalidCredentialException("Supplied credential is not a UserPasswordCredential");
}
UserPasswordCredential cred = (UserPasswordCredential) credential;
LoginContext lc = null;
try {
lc = new LoginContext("KeyStoreLogin",
new UserPasswordCallbackHandlerImpl(cred.getUserName(), cred.getPassword().toCharArray()));
lc.login();
Subject subject = lc.getSubject();
return subject;
}
catch (LoginException le) {
throw new InvalidCredentialException(le);
}
catch (IllegalArgumentException ile) {
throw new InvalidCredentialException(ile);
}
}
}
KeyStoreLoginModule.java
// Este programa de ejemplo se proporciona TAL CUAL y se puede utilizar, ejecutar, copiar y modificar
// sin que el cliente tenga que pagar derechos
// (a) para su propia formación,
// (b) para desarrollar aplicaciones diseñadas para ejecutarse con un producto IBM WebSphere,
// para uso interno propio del cliente o para su redistribución por parte del cliente, como parte de una
// aplicación de ese tipo, en los productos propios del cliente.
// Material bajo licencia - Propiedad de IBM
// 5724-J34 © COPYRIGHT International Business Machines Corp. 2007
package com.ibm.websphere.objectgrid.security.plugins.builtins;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.security.auth.x500.X500Principal;
import javax.security.auth.x500.X500PrivateCredential;
import com.ibm.websphere.objectgrid.ObjectGridRuntimeException;
import com.ibm.ws.objectgrid.Constants;
import com.ibm.ws.objectgrid.ObjectGridManagerImpl;
import com.ibm.ws.objectgrid.util.ObjectGridUtil;
/**
* Un KeyStoreLoginModule es un módulo de inicio de sesión de autenticación de almacén de claves
* basado en la autenticación JAAS.
* <p>
* Una configuración de inicio de sesión debe proporcionar una opción
* "<code>keyStoreFile</code>" para indicar donde está ubicado el archivo de almacén
* de claves. Si el valor <code>keyStoreFile</code> contiene una propiedad del sistema
* en el formato <code>${system.property}</code>, se expandirá hasta el valor de
* la propiedad del sistema.
* <p>
* Si no se proporciona una opción "<code>keyStoreFile</code>", el nombre de archivo
* del almacén de claves predeterminado es <code>"${java.home}${/}.keystore"</code>.
* <p>
* A continuación se muestra un ejemplo de configuración del módulo Login:
* <pre><code>
* KeyStoreLogin {
* com.ibm.websphere.objectgrid.security.plugins.builtins.KeystoreLoginModule required
* keyStoreFile="${user.dir}${/}security${/}.keystore";
* };
* </code></pre>
*
* @ibm-api
* @since WAS XD 6.0.1
*
* @see LoginModule
*/
public class KeyStoreLoginModule implements LoginModule {
private static final String CLASS_NAME = KeyStoreLoginModule.class.getName();
/**
* Nombre de propiedad del archivo de almacén de claves
*/
public static final String KEY_STORE_FILE_PROPERTY_NAME = "keyStoreFile";
/**
* Tipo del almacén de claves. Sólo se da soporte a JKS
*/
public static final String KEYSTORE_TYPE = "JKS";
/**
* El nombre de archivo de almacén de claves predeterminado
*/
public static final String DEFAULT_KEY_STORE_FILE = "${java.home}${/}.keystore";
private CallbackHandler handler;
private Subject subject;
private boolean debug = false;
private Set principals = new HashSet();
private Set publicCreds = new HashSet();
private Set privateCreds = new HashSet();
protected KeyStore keyStore;
/**
* Crea un nuevo KeyStoreLoginModule.
*/
public KeyStoreLoginModule() {
}
/**
* Inicializa el módulo de inicio de sesión.
*
* @see LoginModule#initialize(Subject, CallbackHandler, Map, Map)
*/
public void initialize(Subject sub, CallbackHandler callbackHandler,
Map mapSharedState, Map mapOptions) {
// inicializar todas las opciones configuradas
debug = "true".equalsIgnoreCase((String) mapOptions.get("debug"));
if (sub == null)
throw new IllegalArgumentException("Subject is not specified");
if (callbackHandler == null)
throw new IllegalArgumentException(
"CallbackHander no especificado");
// Obtener la vía de acceso del almacén de claves
String sKeyStorePath = (String) mapOptions
.get(KEY_STORE_FILE_PROPERTY_NAME);
// Si no hay ninguna vía de acceso de almacén de claves, el valor predeterminado es
// el archivo .keystore en el directorio inicial de java
if (sKeyStorePath == null) {
sKeyStorePath = DEFAULT_KEY_STORE_FILE;
}
// Sustituir la variable de entorno del sistema
sKeyStorePath = ObjectGridUtil.replaceVar(sKeyStorePath);
File fileKeyStore = new File(sKeyStorePath);
try {
KeyStore store = KeyStore.getInstance("JKS");
store.load(new FileInputStream(fileKeyStore), null);
// Guardar el almacén de claves
keyStore = store;
if (debug) {
System.out.println("Inicializar [KeyStoreLoginModule]: almacén de claves cargado satisfactoriamente");
}
}
catch (Exception e) {
ObjectGridRuntimeException re = new ObjectGridRuntimeException(
"Failed to load keystore: " + fileKeyStore.getAbsolutePath());
re.initCause(e);
if (debug) {
System.out.println("[KeyStoreLoginModule] initialize: Key store loading failed with exception "
+ e.getMessage());
}
}
this.subject = sub;
this.handler = callbackHandler;
}
/**
* Autentica un usuario basándose en el archivo de almacén de claves.
*
* @see LoginModule#login()
*/
public boolean login() throws LoginException {
if (debug) {
System.out.println("[KeyStoreLoginModule] login: entry");
}
String name = null;
char pwd[] = null;
if (keyStore == null || subject == null || handler == null) {
throw new LoginException("Module initialization failed");
}
NameCallback nameCallback = new NameCallback("Username:");
PasswordCallback pwdCallback = new PasswordCallback("Password:", false);
try {
handler.handle(new Callback[] { nameCallback, pwdCallback });
}
catch (Exception e) {
throw new LoginException("Callback failed: " + e);
}
name = nameCallback.getName();
char[] tempPwd = pwdCallback.getPassword();
if (tempPwd == null) {
// tratar una contraseña NULL como una contraseña vacía
tempPwd = new char[0];
}
pwd = new char[tempPwd.length];
System.arraycopy(tempPwd, 0, pwd, 0, tempPwd.length);
pwdCallback.clearPassword();
if (debug) {
System.out.println("[KeyStoreLoginModule] login: "
+ "user entered user name: " + name);
}
// Validar el nombre de usuario y la contraseña
try {
validate(name, pwd);
}
catch (SecurityException se) {
principals.clear();
publicCreds.clear();
privateCreds.clear();
LoginException le = new LoginException(
"Exception encountered during login");
le.initCause(se);
throw le;
}
if (debug) {
System.out.println("[KeyStoreLoginModule] login: exit");
}
return true;
}
/**
* Indica si el usuario se acepta.
* <p>
* Este método sólo se invoca si el usuario es autenticado por todos los módulos del archivo
* de configuración de inicio de sesión. Los objetos principales se añadirán al asunto
* almacenado.
*
* @return false si por alguna razón los principales no se pueden añadir; de lo contrario,
* true
*
* @exception LoginException
* Se genera una LoginException si el asunto es de sólo lectura o si se
* encuentran excepciones no recuperables.
*
* @see LoginModule#commit()
*/
public boolean commit() throws LoginException {
if (debug) {
System.out.println("[KeyStoreLoginModule] commit: entry");
}
if (principals.isEmpty()) {
throw new IllegalStateException("Commit is called out of sequence");
}
if (subject.isReadOnly()) {
throw new LoginException("Subject is Readonly");
}
subject.getPrincipals().addAll(principals);
subject.getPublicCredentials().addAll(publicCreds);
subject.getPrivateCredentials().addAll(privateCreds);
principals.clear();
publicCreds.clear();
privateCreds.clear();
if (debug) {
System.out.println("[KeyStoreLoginModule] commit: exit");
}
return true;
}
/**
* Indica que el usuario no se acepta
*
* @see LoginModule#abort()
*/
public boolean abort() throws LoginException {
boolean b = logout();
return b;
}
/**
* Cierra la sesión de usuario. Borrar todas las correlaciones.
*
* @see LoginModule#logout()
*/
public boolean logout() throws LoginException {
// Borrar las variables de instancia
principals.clear();
publicCreds.clear();
privateCreds.clear();
// borrar correlaciones en el asunto
if (!subject.isReadOnly()) {
if (subject.getPrincipals() != null) {
subject.getPrincipals().clear();
}
if (subject.getPublicCredentials() != null) {
subject.getPublicCredentials().clear();
}
if (subject.getPrivateCredentials() != null) {
subject.getPrivateCredentials().clear();
}
}
return true;
}
/**
* Valida el nombre de usuario y la contraseña basándose en el almacén de claves.
*
* @param userName nombre de usuario
* @param password contraseña
* @throws SecurityException si se encuentran excepciones
*/
private void validate(String userName, char password[])
throws SecurityException {
PrivateKey privateKey = null;
// Obtener la clave privada del almacén de claves
try {
privateKey = (PrivateKey) keyStore.getKey(userName, password);
}
catch (NoSuchAlgorithmException nsae) {
SecurityException se = new SecurityException();
se.initCause(nsae);
throw se;
}
catch (KeyStoreException kse) {
SecurityException se = new SecurityException();
se.initCause(kse);
throw se;
}
catch (UnrecoverableKeyException uke) {
SecurityException se = new SecurityException();
se.initCause(uke);
throw se;
}
if (privateKey == null) {
throw new SecurityException("Invalid name: " + userName);
}
// Comprobar certificados
Certificate certs[] = null;
try {
certs = keyStore.getCertificateChain(userName);
}
catch (KeyStoreException kse) {
SecurityException se = new SecurityException();
se.initCause(kse);
throw se;
}
if (debug) {
System.out.println(" Print out the certificates:");
for (int i = 0; i < certs.length; i++) {
System.out.println(" certificate " + i);
System.out.println(" " + certs[i]);
}
}
if (certs != null && certs.length > 0) {
// Si el primer certificado es un X509Certificate
if (certs[0] instanceof X509Certificate) {
try {
// Obtener el primer certificado que representa el usuario
X509Certificate certX509 = (X509Certificate) certs[0];
// Crear un principal
X500Principal principal = new X500Principal(certX509
.getIssuerDN()
.getName());
principals.add(principal);
if (debug) {
System.out.println(" Principal added: " + principal);
}
// Crear un objeto de vía de acceso de certificación y añadirlo al
// conjunto de credenciales públicas
CertificateFactory factory = CertificateFactory
.getInstance("X.509");
java.security.cert.CertPath certPath = factory
.generateCertPath(Arrays.asList(certs));
publicCreds.add(certPath);
// Añadir la credencial privada al conjunto de credenciales privadas
privateCreds.add(new X500PrivateCredential(certX509,
privateKey, userName));
}
catch (CertificateException ce) {
SecurityException se = new SecurityException();
se.initCause(ce);
throw se;
}
}
else {
// El primer certificado no es un X509Certificate
// Sólo añadimos el certificado al conjunto de credenciales públicas
// y la clave privada al conjunto de credenciales privadas.
publicCreds.add(certs[0]);
privateCreds.add(privateKey);
}
}
}
}
Utilización del plug-in de autenticador LDAP
Se le proporciona la implementación predeterminada com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPAuthenticator para manejar la autenticación de nombre de usuario y contraseña en un servidor LDAP. Esta implementación utiliza el módulo de inicio de sesión LDAPLogin para conectar al usuario a un servidor LDAP (Lightweight Directory Access Protocol). El siguiente fragmento de código demuestra cómo se implementa el método authenticate:
/**
* @see com.ibm.ws.objectgrid.security.plugins.Authenticator#
* authenticate(LDAPLogin)
*/
public Subject authenticate(Credential credential) throws
InvalidCredentialException, ExpiredCredentialException {
UserPasswordCredential cred = (UserPasswordCredential) credential;
LoginContext lc = null;
try {
lc = new LoginContext("LDAPLogin",
new UserPasswordCallbackHandlerImpl(cred.getUserName(),
cred.getPassword().toCharArray()));
lc.login();
Subject subject = lc.getSubject();
return subject;
}
catch (LoginException le) {
throw new InvalidCredentialException(le);
}
catch (IllegalArgumentException ile) {
throw new InvalidCredentialException(ile);
}
}
Asimismo, eXtreme Scale se entrega con un módulo de inicio de sesión com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPLoginModule con esta finalidad. Debe proporcionar las siguientes dos opciones en el archivo de configuración del inicio de sesión JAAS.
El módulo LDAPLoginModule llama al método com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPAuthentcationHelper.authenticate. El siguiente fragmento de código muestra cómo implementar el método authenticate de LDAPAuthenticationHelper.
/**
* Autentica el usuario en el directorio LDAP.
* @param user El ID de usuario, por ejemplo uid=xxxxxx,c=us,ou=bluepages,o=ibm.com
* @param pwd la contraseña
*
* @throws NamingException
*/
public String[] authenticate(String user, String pwd)
throws NamingException {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, factoryClass);
env.put(Context.PROVIDER_URL, providerURL);
env.put(Context.SECURITY_PRINCIPAL, user);
env.put(Context.SECURITY_CREDENTIALS, pwd);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
InitialContext initialContext = new InitialContext(env);
// Buscar el usuario
DirContext dirCtx = (DirContext) initialContext.lookup(user);
String uid = null;
int iComma = user.indexOf(",");
int iEqual = user.indexOf("=");
if (iComma > 0 && iComma > 0) {
uid = user.substring(iEqual + 1, iComma);
}
else {
uid = user;
}
Attributes attributes = dirCtx.getAttributes("");
// Comprobar el UID
String thisUID = (String) (attributes.get(UID).get());
String thisDept = (String) (attributes.get(HR_DEPT).get());
if (thisUID.equals(uid)) {
return new String[] { thisUID, thisDept };
}
else {
return null;
}
}
Si la autenticación es correcta, el ID de usuario y la contraseña se consideran válidos. El módulo de inicio de sesión obtiene la información de ID y de departamento a partir de este método authenticate. El módulo de inicio de sesión crea dos principales: SimpleUserPrincipal y SimpleDeptPrincipal. Puede usar el sujeto autenticado para autorización de grupos (en este caso, el departamento es un grupo) y para autorización individual.
El ejemplo siguiente muestra una configuración del módulo de inicio de sesión que se utiliza para iniciar sesión en el servidor LDAP:
LDAPLogin { com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPLoginModule required
providerURL="ldap://directory.acme.com:389/"
factoryClass="com.sun.jndi.ldap.LdapCtxFactory";
};
En la configuración anterior, el servidor LDAP apunta al ldap://directory.acme.com:389/server. Cambie este valor por el de su servidor LDAP. Este módulo de inicio de sesión utiliza el ID y la contraseña proporcionados para conectarse al servidor LDAP. Esta implementación es sólo para realizar pruebas.
Uso del plug-in de autenticador de WebSphere Application Server
Además, eXtreme Scale proporciona la implementación incorporada com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenAuthenticator para utilizar la infraestructura de seguridad de WebSphere Application Server. Esta implementación incorporada se puede utilizar cuando las siguientes condiciones son verdaderas.
El cliente puede utilizar la clase com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredentialGenerator para generar una credencial. El servidor utiliza esta clase de implementación Authenticator para autenticar la credencial. Si la señal se autentica correctamente, se devuelve un objeto Subject.
Este escenario saca partido del hecho que el cliente ya ha sido autenticado. Puesto que los servidores de aplicaciones que tienen los servidores en el mismo dominio de seguridad que los servidores de aplicaciones que alojan los clientes, las señales de seguridad se pueden propagar del cliente al servidor, de forma que no es necesario que se vuelva a autenticar el mismo registro de usuarios.
Uso del plug-in de autenticador de Tivoli Access Manager
Tivoli Access Manager se utiliza ampliamente como un servidor de seguridad. También puede implementar el autenticador utilizando los módulos de inicio de sesión proporcionados de Tivoli Access Manager.
Para autenticar un usuario para Tivoli Access Manager, aplique el módulo de inicio de sesión com.tivoli.mts.PDLoginModule, que requiere que la aplicación que llama proporcione la siguiente información:
El módulo de inicio de sesión autentica el principal y devuelve la credencial de Tivoli Access Manager. El módulo de inicio de sesión espera que la aplicación que llama proporcione la información siguiente:
Cuando la credencial de Tivoli Access Manager se recupera correctamente, el módulo JAAS LoginModule crea un objeto Subject y PDPrincipal. No se proporciona ningún objeto incorporado para la autenticación de Tivoli Access Manager, porque sólo se proporciona con el módulo PDLoginModule. Consulte la publicación IBM® Tivoli Access Manager Authorization Java Classes Developer Reference si desea más detalles.
Para conectar de forma segura un cliente de eXtreme Scale con un servidor, puede utilizar cualquier método connect en la interfaz ObjectGridManager que toma un objeto ClientSecurityConfiguration. A continuación, aparece un breve ejemplo:
public ClientClusterContext connect(String catalogServerEndpoints,
ClientSecurityConfiguration securityProps,
URL overRideObjectGridXml) lanza ConnectException;
Este método toma un parámetro del tipo ClientSecurityConfiguration, que es una interfaz que representa una configuración de seguridad de cliente. Puede utilizar la API pública com.ibm.websphere.objectgrid.security.config.ClientSecurityConfigurationFactory para crear una instancia con valores predeterminados, o puede crear una instancia pasando el archivo de propiedades de cliente de WebSphere eXtreme Scale. Este archivo contiene las siguientes propiedades relacionadas con la autenticación. El valor marcado con un signo más (+) es el valor predeterminado.
Después de crear un objeto com.ibm.websphere.objectgrid.security.config.ClientSecurityConfiguration, establezca el objeto credentialGenerator en el cliente mediante el método siguiente:
/**
* Establezca el objeto {@link CredentialGenerator} para este cliente.
* @param generator El objeto CredentialGenerator asociado con este cliente
*/
void setCredentialGenerator(CredentialGenerator generator);
En el ejemplo siguiente se crea una instancia de ClientSecurityConfiguration, que se utiliza para conectar con el servidor.
/**
* Obtiene un ClientClusterContext seguro
* @return un objeto ClientClusterContext seguro
*/
protected ClientClusterContext connect() throws ConnectException {
ClientSecurityConfiguration csConfig = ClientSecurityConfigurationFactory
.getClientSecurityConfiguration("/properties/security.ogclient.props");
UserPasswordCredentialGenerator gen= new
UserPasswordCredentialGenerator("manager", "manager1");
csConfig.setCredentialGenerator(gen);
return objectGridManager.connect(csConfig, null);
}
Cuando se llama a la conexión, el cliente de WebSphere eXtreme Scale llama al método CredentialGenerator.getCredential para obtener la credencial del cliente. Esta credencial de autenticación se envía al servidor con la solicitud de conexión.
En algunos casos, un cliente de WebSphere eXtreme Scale representa sólo una identidad de cliente, pero en otros, podría representar varias identidades. Aquí, aparece un escenario del último caso: un cliente de WebSphere eXtreme Scale se crea y comparte en un servidor web. Todos los servlets de este servidor web utilizan este cliente de WebSphere eXtreme Scale. Puesto que cada uno de los servlets representa un cliente web diferente, utilice distintas credenciales al enviar solicitudes a servidores WebSphere eXtreme Scale.
WebSphere eXtreme Scale puede cambiar la credencial en el nivel de la sesión. Cada sesión puede utilizar un objeto CredentialGenerator diferente. Por lo tanto, los escenarios anteriores se pueden implementar dejando al servlet obtener una sesión con un objeto CredentialGenerator distinto. El ejemplo siguiente ilustra el método ObjectGrid.getSession(CredentialGenerator) en la interfaz ObjectGridManager.
/**
* Obtener una sesión utilizando <code>CredentialGenerator</code>.
* <p>
* Este método sólo puede llamarlo el cliente ObjectGrid en un entorno de
* cliente-servidor de ObjectGrid. Si se utiliza ObjectGrid en un modelo local, es decir,
* dentro de la misma JVM donde no existe ningún cliente ni servidor, se debe utilizar el
* plug-in <code>getSession(Subject)</code>
* o <code>SubjectSource</code> para proteger el ObjectGrid.
*
* <p>Si el método <code>initialize()</code> no ha sido invocado antes de la
* primera invocación de <code>getSession</code>, se producirá una inicialización
* implícita. Esto garantiza que toda la configuración se completa
* antes de que sea necesario cualquier uso del tiempo de ejecución.</p>
*
* @param credGen <code>CredentialGenerator</code> para generar una credencial
* para la sesión devuelta.
*
* @return Una instancia de <code>Session</code>
*
* @throws ObjectGridException si se produce un error durante el proceso
* @throws TransactionCallbackException si <code>TransactionCallback</code>
* emite una excepción
* @throws IllegalStateException si se llama a este método después de
* que se llame al método <code>destroy()</code>.
*
* @see #destroy()
* @see #initialize()
* @see CredentialGenerator
* @see Session
* @since WAS XD 6.0.1
*/
Session getSession(CredentialGenerator credGen) throws
ObjectGridException, TransactionCallbackException;
A continuación se muestra un ejemplo:
ObjectGridManager ogManager = ObjectGridManagerFactory.getObjectGridManager();
CredentialGenerator credGenManager = new UserPasswordCredentialGenerator("manager", "xxxxxx");
CredentialGenerator credGenEmployee = new UserPasswordCredentialGenerator("employee", "xxxxxx");
ObjectGrid og = ogManager.getObjectGrid(ctx, "accounting");
// Obtiene una sesión con CredentialGenerator;
Session session = og.getSession(credGenManager );
// Obtiene la correlación de empleados
ObjectMap om = session.getMap("employee");
// inicia una transacción.
session.begin();
Object rec1 = map.get("xxxxxx");
session.commit();
// Obtiene otra sesión con otro CredentialGenerator;
session = og.getSession(credGenEmployee );
// Obtiene la correlación de empleados
om = session.getMap("employee");
// inicia una transacción.
session.begin();
Object rec2 = map.get("xxxxx");
session.commit();
Si utiliza el método ObjectGird.getSession para obtener un objeto Session, la sesión utiliza el objeto CredentialGenerator establecido en el objeto ClientConfigurationSecurity. El método ObjectGrid.getSession(CredentialGenerator) sustituye al objeto CredentialGenerator establecido en el objeto ClientSecurityConfiguration.
Si puede volver a utilizar el objeto Session, se favorece el rendimiento. Sin embargo, llamar al método ObjectGrid.getSession(CredentialGenerator) no es muy caro. La principal sobrecarga es el aumento del tiempo de recogida de basura del objeto. Asegúrese de que libera las referencias después de terminar con los objetos Session. Por lo general, si el objeto Session puede compartir la identidad, intente reutilizarlo. En caso contrario, utilice el método ObjectGrid.getSession(CredentialGenerator).