Para autenticação, o WebSphere eXtreme Scale fornece um tempo de execução para enviar a credencial do cliente para o lado do servidor e, em seguida, chama o plug-in do autenticador para autenticar os usuários.
O WebSphere eXtreme Scale exige que você implemente os plug-ins a seguir para completar a autenticação.
Quando um cliente do eXtreme Scale se conecta a um servidor que exige autenticação, o cliente é obrigado a fornecer uma credencial do cliente. Uma credencial do cliente é representado por uma interface com.ibm.websphere.objectgrid.security.plugins.Credential. Uma credencial de cliente pode ser um par de nome de usuário e senha, um registro do Kerberos, um certificado cliente ou dados em qualquer formato concordado entre o cliente e o servidor. Esta interface explicitamente define os métodos equals(Object) e hashCode. Estes métodos são importantes porque os objetos Subject autenticados são armazenados em cache utilizando o objeto Credential como a chave no lado do servidor. O WebSphere eXtreme Scale também fornece um plug-in para gerar uma credencial. Este plug-in é representado pela interface com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator e será útil quando a credencial puder expirar. Neste caso, o método getCredential é chamado para renovar uma credencial.
A interface Credential explicitamente define os métodos equals(Object) e hashCode. Estes métodos são importantes porque os objetos Subject autenticados são armazenados em cache utilizando o objeto Credential como a chave no lado do servidor.
Você também pode usar o plug-in fornecido para gerar uma credencial. Este plug-in é representado pela interface com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator e é útil quando a credencial pode expirar. Neste caso, o método getCredential é chamado para renovar uma credencial. Consulte Interface CredentialGenerator para obter mais detalhes.
Há três implementações padrão fornecidas para as interfaces da Credencial:
O WebSphere eXtreme Scale também fornece um plug-in para gerar uma credencial. Este plug-in é representado pela interface com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator. O WebSphere eXtreme Scale fornece duas implementações integradas padrão:
UserPasswordCredential e UserPasswordCredentialGenerator
Para propósitos de teste, o WebSphere eXtreme Scale fornece as seguintes implementações de plug-in:
com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredential
com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredentialGenerator
A credencial de senha do usuário armazena um ID de usuário e uma senha. O gerador de credenciais de senha de usuário contém este ID de usuário e senha.
O código de exemplo a seguir mostra como implementar estes dois plug-ins.
UserPasswordCredential.java
// This sample program is provided AS IS and may be used, executed, copied and modified
// without royalty payment by customer
// (a) for its own instruction and study,
// (b) in order to develop applications designed to run with an IBM WebSphere product,
// either for customer's own internal use or for redistribution by customer, as part of such an
// application, in customer's own products.
// Licensed Materials - Property of 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;
/**
* This class represents a credential containing a user ID and password.
*
* @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;
/**
* Creates a UserPasswordCredential with the specified user name and
* password.
*
* @param userName the user name for this credential
* @param password the password for this credential
*
* @throws IllegalArgumentException if userName or password is <code>null</code>
*/
public UserPasswordCredential(String userName, String password) {
super();
if (userName == null || password == null) {
throw new IllegalArgumentException("User name and password cannot be null.");
}
this.ivUserName = userName;
this.ivPassword = password;
}
/**
* Gets the user name for this credential.
*
* @return the user name argument that was passed to the constructor
* or the <code>setUserName(String)</code>
* method of this class
*
* @see #setUserName(String)
*/
public String getUserName() {
return ivUserName;
}
/**
* Sets the user name for this credential.
*
* @param userName the user name to set.
*
* @throws IllegalArgumentException if userName is <code>null</code>
*/
public void setUserName(String userName) {
if (userName == null) {
throw new IllegalArgumentException("User name cannot be null.");
}
this.ivUserName = userName;
}
/**
* Gets the password for this credential.
*
* @return the password argument that was passed to the constructor
* or the <code>setPassword(String)</code>
* method of this class
*
* @see #setPassword(String)
*/
public String getPassword() {
return ivPassword;
}
/**
* Sets the password for this credential.
*
* @param password the password to set.
*
* @throws IllegalArgumentException if password is <code>null</code>
*/
public void setPassword(String password) {
if (password == null) {
throw new IllegalArgumentException("Password cannot be null.");
}
this.ivPassword = password;
}
/**
* Checks two UserPasswordCredential objects for equality.
* <p>
* Two UserPasswordCredential objects are equal if and only if their user names
* and passwords are equal.
*
* @param o the object we are testing for equality with this object.
*
* @return <code>true</code> if both UserPasswordCredential objects are equivalent.
*
* @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;
}
/**
* Returns the hashcode of the UserPasswordCredential object.
*
* @return the hash code of this object
*
* @see Credential#hashCode()
*/
public int hashCode () {
return ivUserName.hashCode() + ivPassword.hashCode();
}
}
UserPasswordCredentialGenerator.java
// This sample program is provided AS IS and may be used, executed, copied and modified
// without royalty payment by customer
// (a) for its own instruction and study,
// (b) in order to develop applications designed to run with an IBM WebSphere product,
// either for customer's own internal use or for redistribution by customer, as part of such an
// application, in customer's own products.
// Licensed Materials - Property of 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;
/**
* This credential generator creates <code>UserPasswordCredential</code> objects.
* <p>
* UserPasswordCredentialGenerator has a one to one relationship with
* UserPasswordCredential because it can only create a UserPasswordCredential
* representing one identity.
*
* @since WAS XD 6.0.1
* @ibm-api
*
* @see CredentialGenerator
* @see UserPasswordCredential
*/
public class UserPasswordCredentialGenerator implements CredentialGenerator {
private String ivUser;
private String ivPwd;
/**
* Creates a UserPasswordCredentialGenerator with no user name or password.
*
* @see #setProperties(String)
*/
public UserPasswordCredentialGenerator() {
super();
}
/**
* Creates a UserPasswordCredentialGenerator with a specified user name and
* password
*
* @param user the user name
* @param pwd the password
*/
public UserPasswordCredentialGenerator(String user, String pwd) {
ivUser = user;
ivPwd = pwd;
}
/**
* Creates a new <code>UserPasswordCredential</code> object using this
* object's user name and password.
*
* @return a new <code>UserPasswordCredential</code> instance
*
* @see CredentialGenerator#getCredential()
* @see UserPasswordCredential
*/
public Credential getCredential() {
return new UserPasswordCredential(ivUser, ivPwd);
}
/**
* Gets the password for this credential generator.
*
* @return the password argument that was passed to the constructor
*/
public String getPassword() {
return ivPwd;
}
/**
* Gets the user name for this credential.
*
* @return the user argument that was passed to the constructor
* of this class
*/
public String getUserName() {
return ivUser;
}
/**
* Sets additional properties namely a user name and password.
*
* @param properties a properties string with a user name and
* a password separated by a blank.
*
* @throws IllegalArgumentException if the format is not valid
*/
public void setProperties(String properties) {
StringTokenizer token = new StringTokenizer(properties, " ");
if (token.countTokens() != 2) {
throw new IllegalArgumentException(
"The properties should have a user name and password and separated by a blank.");
}
ivUser = token.nextToken();
ivPwd = token.nextToken();
}
/**
* Checks two UserPasswordCredentialGenerator objects for equality.
* <p>
* Two UserPasswordCredentialGenerator objects are equal if and only if
* their user names and passwords are equal.
*
* @param obj the object we are testing for equality with this object.
*
* @return <code>true</code> if both UserPasswordCredentialGenerator objects
* are equivalent.
*/
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;
}
/**
* Returns the hashcode of the UserPasswordCredentialGenerator object.
*
* @return the hash code of this object
*/
public int hashCode () {
return ivUser.hashCode() + ivPwd.hashCode();
}
}
A classe UserPasswordCredential contém dois atributos: nome de usuário e senha. O UserPasswordCredentialGenerator serve como uma factory que contém os objetos UserPasswordCredential.
WSTokenCredential e WSTokenCredentialGenerator
Quando os clientes e servidores do WebSphere eXtreme Scale são todos implementados no WebSphere Application Server, o aplicativo cliente pode usar estas duas implementações integradas quando as seguintes condições forem satisfeitas:
Nesta situação, o cliente pode usar a classe com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredentialGenerator para gerenciar uma credencial. O servidor usa a classe de implementação WSAuthenticator para autenticar a credencial.
Este cenário aproveita as vantagens do fato de que o cliente do eXtreme Scale já ter sido autenticado. Como os servidores de aplicativos que possuem servidores estão no mesmo domínio de segurança que os servidores de aplicativos que hospedam os clientes, os tokens de segurança podem ser propagados do cliente para o servidor para que o mesmo registro de usuário não precise ser autenticado novamente.
Após o cliente do eXtreme Scale recuperar o objeto Credential utilizando o objeto CredentialGenerator, este objeto Credential do cliente é enviado junto o pedido do cliente para o servidor eXtreme Scale. O servidor autentica o objeto de Credencial antes de processar a solicitação. Se o objeto Credential for autenticado com êxito, um objeto Subject será retornado para representar este cliente.
Este objeto Subject é então armazenado em cache e expira após seu tempo de vida alcançar o valor de tempo limite da sessão. O valor de tempo limite da sessão de login pode ser configurado utilizando a propriedade loginSessionExpirationTime no arquivo XML do cluster. Por exemplo, configurar loginSessionExpirationTime="300" fará com que o objeto Subject expire em 300 segundos.
Esse objeto Subject é, então, utilizado para autorizar o pedido, que é mostrado posteriormente. Um servidor eXtreme Scale utiliza o plug-in do Autenticador para autenticar o objeto Credential. Consulte Authenticator para obter mais detalhes.
O plug-in Autenticador é onde o tempo de execução do eXtreme Scale autentica o objeto Credential a partir do registro do usuário do cliente como, por exemplo, um servidor protocolo LDAP (Lightweight Directory Access Protocol).
O WebSphere eXtreme Scale não fornece uma configuração de registro do usuário disponível imediatamente. A configuração e o gerenciamento do registro do usuário são deixados fora do WebSphere eXtreme Scale para simplificação e flexibilidade. Este plug-in implementa a conexão e a autenticação com o registro do usuário. Por exemplo, uma implementação do Autenticador extrai o ID do usuário e a senha da credencial, utiliza-os para conectar-se e validar em um servidor LDAP e cria um objeto Subject como resultado da autenticação. A implementação pode usar módulos de login JAAS. Um objeto Subject é retornado como resultado de autenticação.
Observe que este método cria duas exceções: InvalidCredentialException e ExpiredCredentialException. A exceção InvalidCredentialException indica que a credencial não é válida. A exceção ExpiredCredentialException indica que a credencial expirou. Se uma destas duas exceções resultar do método authenticate, as exceções serão enviadas de volta para o cliente. Porém, o tempo de execução do cliente manipula estas duas exceções diferentemente:
A interface Authenticator oferece grande flexibilidade. É possível implementar a interface Authenticator de sua própria maneira específica. Por exemplo, é possível implementar essa interface para suportar dois registros do usuário diferentes.
O WebSphere eXtreme Scale oferece amostra de implementações de plug-in do autenticador. Exceto para o plug-in do autenticador do WebSphere Application Server, as outras implementações são apenas amostras para fins de teste.
KeyStoreLoginAuthenticator
Este exemplo usa uma implementação integrada do eXtreme Scale: KeyStoreLoginAuthenticator, que é para fins de teste e amostra (uma armazenamento de chave é um registro de usuário simples e não deve ser usado para um ambiente de produção). Novamente, a classe é exibida para demonstrar melhor como implementar um autenticador.
KeyStoreLoginAuthenticator.java
// This sample program is provided AS IS and may be used, executed, copied and modified
// without royalty payment by customer
// (a) for its own instruction and study,
// (b) in order to develop applications designed to run with an IBM WebSphere product,
// either for customer's own internal use or for redistribution by customer, as part of such an
// application, in customer's own products.
// Licensed Materials - Property of 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;
/**
* This class is an implementation of the <code>Authenticator</code> interface
* when a user name and password are used as a credential.
* <p>
* When user ID and password authentication is used, the credential passed to the
* <code>authenticate(Credential)</code> method is a UserPasswordCredential object.
* <p>
* This implementation will use a <code>KeyStoreLoginModule</code> to authenticate
* the user into the key store using the JAAS login module "KeyStoreLogin". The key
* store can be configured as an option to the <code>KeyStoreLoginModule</code>
* class. Please see the <code>KeyStoreLoginModule</code> class for more details
* about how to set up the JAAS login configuration file.
* <p>
* This class is only for sample and quick testing purpose. Users should
* write your own Authenticator implementation which can fit better into
* the environment.
*
* @ibm-api
* @since WAS XD 6.0.1
*
* @see Authenticator
* @see KeyStoreLoginModule
* @see UserPasswordCredential
*/
public class KeyStoreLoginAuthenticator implements Authenticator {
/**
* Creates a new KeyStoreLoginAuthenticator.
*/
public KeyStoreLoginAuthenticator() {
super();
}
/**
* Authenticates a <code>UserPasswordCredential</code>.
* <p>
* Uses the user name and password from the specified UserPasswordCredential
* to login to the KeyStoreLoginModule named "KeyStoreLogin".
*
* @throws InvalidCredentialException if credential isn't a
* UserPasswordCredential or some error occurs during processing
* of the supplied UserPasswordCredential
*
* @throws ExpiredCredentialException if credential is expired. This exception
* is not used by this implementation
*
* @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
// This sample program is provided AS IS and may be used, executed, copied and modified
// without royalty payment by customer
// (a) for its own instruction and study,
// (b) in order to develop applications designed to run with an IBM WebSphere product,
// either for customer's own internal use or for redistribution by customer, as part of such an
// application, in customer's own products.
// Licensed Materials - Property of 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;
/**
* A KeyStoreLoginModule is keystore authentication login module based on
* JAAS authentication.
* <p>
* A login configuration should provide an option "<code>keyStoreFile</code>" to
* indicate where the keystore file is located. If the <code>keyStoreFile</code>
* value contains a system property in the form, <code>${system.property}</code>,
* it will be expanded to the value of the system property.
* <p>
* If an option "<code>keyStoreFile</code>" is not provided, the default keystore
* file name is <code>"${java.home}${/}.keystore"</code>.
* <p>
* Here is a Login module configuration example:
* <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();
/**
* Key store file property name
*/
public static final String KEY_STORE_FILE_PROPERTY_NAME = "keyStoreFile";
/**
* Key store type. Only JKS is supported
*/
public static final String KEYSTORE_TYPE = "JKS";
/**
* The default key store file name
*/
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;
/**
* Creates a new KeyStoreLoginModule.
*/
public KeyStoreLoginModule() {
}
/**
* Initializes the login module.
*
* @see LoginModule#initialize(Subject, CallbackHandler, Map, Map)
*/
public void initialize(Subject sub, CallbackHandler callbackHandler,
Map mapSharedState, Map mapOptions) {
// initialize any configured options
debug = "true".equalsIgnoreCase((String) mapOptions.get("debug"));
if (sub == null)
throw new IllegalArgumentException("Subject is not specified");
if (callbackHandler == null)
throw new IllegalArgumentException(
"CallbackHander is not specified");
// Get the key store path
String sKeyStorePath = (String) mapOptions
.get(KEY_STORE_FILE_PROPERTY_NAME);
// If there is no key store path, the default one is the .keystore
// file in the java home directory
if (sKeyStorePath == null) {
sKeyStorePath = DEFAULT_KEY_STORE_FILE;
}
// Replace the system enviroment variable
sKeyStorePath = ObjectGridUtil.replaceVar(sKeyStorePath);
File fileKeyStore = new File(sKeyStorePath);
try {
KeyStore store = KeyStore.getInstance("JKS");
store.load(new FileInputStream(fileKeyStore), null);
// Save the key store
keyStore = store;
if (debug) {
System.out.println("[KeyStoreLoginModule] initialize: Successfully loaded key store");
}
}
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;
}
/**
* Authenticates a user based on the keystore file.
*
* @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) {
// treat a NULL password as an empty password
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);
}
// Validate the user name and password
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;
}
/**
* Indicates the user is accepted.
* <p>
* This method is called only if the user is authenticated by all modules in
* the login configuration file. The principal objects will be added to the
* stored subject.
*
* @return false if for some reason the principals cannot be added; true
* otherwise
*
* @exception LoginException
* LoginException is thrown if the subject is readonly or if
* any unrecoverable exceptions is encountered.
*
* @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;
}
/**
* Indicates the user is not accepted
*
* @see LoginModule#abort()
*/
public boolean abort() throws LoginException {
boolean b = logout();
return b;
}
/**
* Logs the user out. Clear all the maps.
*
* @see LoginModule#logout()
*/
public boolean logout() throws LoginException {
// Clear the instance variables
principals.clear();
publicCreds.clear();
privateCreds.clear();
// clear maps in the subject
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;
}
/**
* Validates the user name and password based on the keystore.
*
* @param userName user name
* @param password password
* @throws SecurityException if any exceptions encountered
*/
private void validate(String userName, char password[])
throws SecurityException {
PrivateKey privateKey = null;
// Get the private key from the keystore
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);
}
// Check the certificats
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) {
// If the first certificate is an X509Certificate
if (certs[0] instanceof X509Certificate) {
try {
// Get the first certificate which represents the user
X509Certificate certX509 = (X509Certificate) certs[0];
// Create a principal
X500Principal principal = new X500Principal(certX509
.getIssuerDN()
.getName());
principals.add(principal);
if (debug) {
System.out.println(" Principal added: " + principal);
}
// Create the certification path object and add it to the
// public credential set
CertificateFactory factory = CertificateFactory
.getInstance("X.509");
java.security.cert.CertPath certPath = factory
.generateCertPath(Arrays.asList(certs));
publicCreds.add(certPath);
// Add the private credential to the private credential set
privateCreds.add(new X500PrivateCredential(certX509,
privateKey, userName));
}
catch (CertificateException ce) {
SecurityException se = new SecurityException();
se.initCause(ce);
throw se;
}
}
else {
// The first certificate is not an X509Certificate
// We just add the certificate to the public credential set
// and the private key to the private credential set.
publicCreds.add(certs[0]);
privateCreds.add(privateKey);
}
}
}
}
Uso do Plug-in do Autenticador LDAP
Você recebe a implementação padrão do com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPAuthenticator para manipular a autenticação de nome do usuário e senha para um servidor LDAP. Esta implementação usa o módulo de login LDAPLogin para efetuar login do usuário em um servidor LDAP (Lightweight Directory Access Protocol). O fragmento a seguir demonstra como o método authenticate é implementado:
/**
* @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);
}
}
Além disso, o eXtreme Scale envia um módulo de login com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPLoginModule para esta finalidade. Você deve fornecer as duas opções a seguir no arquivo de configuração de login JAAS.
O módulo LDAPLoginModule chama o método com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPAuthentcationHelper.authenticate. O trecho de código a seguir mostra como é possível implementar o método authenticate do LDAPAuthenticationHelper.
/**
* Authenticate the user to the LDAP directory.
* @param user the user ID, e.g., uid=xxxxxx,c=us,ou=bluepages,o=ibm.com
* @param pwd the password
*
* @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);
// Look up for the user
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("");
// Check the 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;
}
}
Se a autenticação for bem-sucedida, o ID e a senha serão considerados válidos. Então o módulo de login obtém as informações de ID e informações do departamento a partir deste método authenticate. O módulo de login cria dois proprietários: SimpleUserPrincipal e SimpleDeptPrincipal. É possível utilizar o subject autenticado para autorização de grupo (neste caso, o departamento é um grupo) e para autorização individual.
O exemplo a seguir mostra uma configuração de módulo de login utilizado para efetuar login no servidor LDAP:
LDAPLogin { com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPLoginModule required
providerURL="ldap://directory.acme.com:389/"
factoryClass="com.sun.jndi.ldap.LdapCtxFactory";
};
Na configuração anterior, o servidor LDAP aponta para ldap://directory.acme.com:389/server. Altere esta configuração para seu servidor LDAP. Este módulo de login usa o ID e a senha fornecidos para se conectar ao servidor LDAP. Esta implementação serve apenas para fins de teste.
Utilização do Plug-in Autenticador do WebSphere Application Server
Além disso, o eXtreme Scale fornece a implementação integrada do com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenAuthenticator para usar a infraestrutura de segurança do WebSphere Application Server. Esta implementação integrada pode ser usada quando as seguintes condições forem verdadeiras.
O cliente pode usar a classe com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredentialGenerator para gerar uma credencial. O servidor usa esta classe de implementação Authenticator para autenticar a credencial. Se o token for autenticado com êxito, será retornado um objeto Subject.
Este cenário tira vantagens do fato de o cliente já ter sido autenticado. Como os servidores de aplicativos que possuem servidores estão no mesmo domínio de segurança que os servidores de aplicativos que hospedam os clientes, os tokens de segurança podem ser propagados do cliente para o servidor para que o mesmo registro de usuário não precise ser autenticado novamente.
Utilização do Plug-in Autenticador do Tivoli Access Manager
O Tivoli Access Manager é amplamente utilizado como um servidor de segurança. Também é possível implementar o Authenticator usando os módulos de login fornecidos pelo Tivoli Access Manager.
Para autenticar um usuário para o Tivoli Access Manager, aplique o módulo de login com.tivoli.mts.PDLoginModule, o que exige que o aplicativo que efetua a chamada forneça as seguintes informações:
O módulo de login autentica o shard primário e retorna a credencial do Tivoli Access Manager. O módulo espera que o aplicativo de chamada forneça as seguintes informações:
Quando a credencial do Tivoli Access Manager é recuperada com êxito, o JAAS LoginModule cria um Subject e um PDPrincipal. Nenhum módulo integrado para autenticação do Tivoli Access Manager é fornecido pois ele está apenas com o módulo PDLoginModule. Consulte a Autorização do IBM® Tivoli Access Manager Java Classes Developer Reference para obter mais detalhes.
Para se conectar um cliente do eXtreme Scale seguramente a um servidor, é possível usar qualquer método de conexão na interface ObjectGridManager que usa um objeto do ClientSecurityConfiguration. A seguir a um breve exemplo.
public ClientClusterContext connect(String catalogServerEndpoints,
ClientSecurityConfiguration securityProps,
URL overRideObjectGridXml) throws ConnectException;
Este método usa um parâmetro do tipo ClientSecurityConfiguration, que é uma interface representando uma configuração de segurança do cliente. É possível usar a API pública do com.ibm.websphere.objectgrid.security.config.ClientSecurityConfigurationFactory para criar uma instância com valores padrão, ou é possível criar uma instância por meio da transmissão do arquivo de propriedades do cliente do WebSphere eXtreme Scale. Este arquivo contém as seguintes propriedades que estão relacionadas à autenticação. O valor marcado com um sinal de mais (+) é o padrão.
Após criar um objeto com.ibm.websphere.objectgrid.security.config.ClientSecurityConfiguration, configure o objeto credentialGenerator no cliente utilizando o seguinte método:
/**
* Configure o objeto {@link CredentialGenerator} para este cliente.
* @param generator o objeto CredentialGenerator associado a este cliente
*/
void setCredentialGenerator(CredentialGenerator generator);
A seguir está uma amostra para instanciar um a ClientSecurityConfiguration e, em seguida, utilizá-lo para conectar-se ao servidor.
/**
* Obter um ClientClusterContext seguro
* @return um 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);
}
Quando connect é chamado, o cliente do WebSphere eXtreme Scale chama o método CredentialGenerator.getCredential para obter a credencial do cliente. Esta credencial é enviada junto com o pedido de conexão com o servidor para autenticação.
Em alguns casos, um cliente do WebSphere eXtreme Scale representa apenas uma identidade do cliente mas, em outros, ele pode representar múltiplas identidades. Aqui há um cenário para o caso mais recente: Um cliente do WebSphere eXtreme Scale é criado e compartilhado em um servidor da web. Todos os servlets neste servidor da web usam este cliente do WebSphere eXtreme Scale. Como cada servlet representa um web client diferente, use credenciais diferentes ao enviar solicitações aos servidores do WebSphere eXtreme Scale.
O WebSphere eXtreme Scale permite a mudança da credencial no nível de sessão. Cada sessão pode usar um objeto CredentialGenerator diferente. Assim, os cenários anteriores podem ser implementados deixando o servlet obter uma sessão com um objeto CredentialGenerator diferente. O exemplo a seguir ilustra o ObjectGrid.getSession(CredentialGenerator)method na interface ObjectGridManager.
/**
* Get a session using a <code>CredentialGenerator</code>.
* <p>
* This method can only be called by the ObjectGrid client in an ObjectGrid
* client server environment. If ObjectGrid is used in a local model, that is,
* within the same JVM with no client or server existing, <code>getSession(Subject)</code>
* or the <code>SubjectSource</code> plugin should be used to secure the ObjectGrid.
*
* <p>If the <code>initialize()</code> method has not been invoked prior to
* the first <code>getSession</code> invocation, an implicit initialization
* will occur. This ensures that all of the configuration is complete
* before any runtime usage is required.</p>
*
* @param credGen A <code>CredentialGenerator</code> for generating a credential
* for the session returned.
*
* @return An instance of <code>Session</code>
*
* @throws ObjectGridException if an error occurs during processing
* @throws TransactionCallbackException if the <code>TransactionCallback</code>
* throws an exception
* @throws IllegalStateException if this method is called after the
* <code>destroy()</code> method is called.
*
* @see #destroy()
* @see #initialize()
* @see CredentialGenerator
* @see Session
* @since WAS XD 6.0.1
*/
Session getSession(CredentialGenerator credGen) throws
ObjectGridException, TransactionCallbackException;
A seguir está um exemplo:
ObjectGridManager ogManager = ObjectGridManagerFactory.getObjectGridManager();
CredentialGenerator credGenManager = new UserPasswordCredentialGenerator("manager", "xxxxxx");
CredentialGenerator credGenEmployee = new UserPasswordCredentialGenerator("employee", "xxxxxx");
ObjectGrid og = ogManager.getObjectGrid(ctx, "accounting");
// Get a session with CredentialGenerator;
Session session = og.getSession(credGenManager );
// Get the employee map
ObjectMap om = session.getMap("employee");
// start a transaction.
session.begin();
Object rec1 = map.get("xxxxxx");
session.commit();
// Get another session with a different CredentialGenerator;
session = og.getSession(credGenEmployee );
// Get the employee map
om = session.getMap("employee");
// start a transaction.
session.begin();
Object rec2 = map.get("xxxxx");
session.commit();
Se você usar o método ObjectGird.getSession para obter um objeto de Sessão, a sessão usa o conjunto de objetos CredentialGenerator no objeto ClientConfigurationSecurity. O método ObjectGrid.getSession(CredentialGenerator) substitui a configuração CredentialGenerator no objeto ClientSecurityConfiguration.
Se for possível reutilizar o objeto de Sessão, isto resulta em ganho de desempenho. Porém, a chamada do método ObjectGrid.getSession(CredentialGenerator) não é muito cara. A principal sobrecarga é o tempo maior de coleta de lixo do objeto. Certifique-se de liberar as referências quando tiver concluído os objetos Session. Geralmente, se o seu objeto de Sessão puder compartilhar a identidade, tente reutilizar o objeto de Sessão. Se não, utilize o método ObjectGrid.getSession(CredentialGenerator).