12.2. Módulos Personalizados
JaasSecurityManager requer um padrão de uso particular do conjunto de principais Subject. Você deve entender os recursos da classe de informação da classe do Sujeito JAAS e o uso esperado desses recursos para gravar um módulo de logon que funciona com o JaasSecurityManager.
LoginModule básicas abstratas que podem ajudá-lo a implantar os módulos de logon personalizados.
Subject pelo uso dos seguintes métodos:
java.util.Set getPrincipals() java.util.Set getPrincipals(java.lang.Class c) java.util.Set getPrivateCredentials() java.util.Set getPrivateCredentials(java.lang.Class c) java.util.Set getPublicCredentials() java.util.Set getPublicCredentials(java.lang.Class c)
getPrincipals() e getPrincipals(java.lang.Class) para as identidades e funções do Subject. Segue abaixo o uso padrão:
- As identidades do usuário (por exemplo: nome do usuário, número de segurança social e ID do empregado) conforme armazenado com os objetos
java.security.Principalno conjuntoSubjectPrincipals. A implementaçãoPrincipalque representa a identidade do usuário deve basear-se nas comparações e igualdade do nome do principal. Uma implantação útil está disponível como a classeorg.jboss.security.SimplePrincipal. Outras instânciasPrincipalpodem ser adicionadas ao conjuntoSubjectPrincipalsconforme seja necessário. - As funções determinadas do usuário estão também armazenadas no conjunto
Principalse estão agrupadas nos conjuntos de função nomeados usando as instânciasjava.security.acl.Group. A interfaceGroupdefine uma coleção dePrincipals e/ouGroups, além de ser uma sub-interface dojava.security.Principal. - Qualquer número de conjuntos de funções podem ser determinados a um
Subject.
- O framework do JBossSX usa dois conjuntos de funções bem conhecidos pelos nomes de
RoleseCallerPrincipal.- O grupo
Rolesé uma coleção dePrincipals para funções nomeadas conforme o domínio do aplicativo pelo qual oSubjecté autenticado. Este conjunto de função é usado por métodos como oEJBContext.isCallerInRole(String), em que os EJBs podem usar para verificar se o chamador atual pertence à função do domínio do aplicativo nomeado. A lógica do interceptor de segurança que executa as checagens de permissão do método usa também este conjunto de função. - O
CallerPrincipalGroupconsiste da identidadePrincipalúnica determinada ao usuário no domínio do aplicativo. O métodoEJBContext.getCallerPrincipal()usa oCallerPrincipalpara permitir que o domínio do aplicativo realize o mapeamento a partir da identidade do ambiente de operação à identidade do usuário adequada ao aplicativo. Caso oSubjectnão possua umCallerPrincipalGroup, a identidade de aplicativo é o mesmo como a identidade de ambiente operacional.
12.2.1. Suporte Padrão de Uso do Assunto
Subject autenticado com o padrão de modelo que reforça o uso do Subject correto, com o objetivo de simplificar a implantação correta do uso padrão descrito na Seção 12.2, “Módulos Personalizados”.
O módulo mais genérico dos dois é a classe org.jboss.security.auth.spi.AbstractServerLoginModule.
javax.security.auth.spi.LoginModule e oferece métodos abstratos para as tarefas chave específicas à infra-estrutura de segurança do ambiente. Os detalhes chave da classe estão descritos no Exemplo 12.9, “Fragmento da Classe AbstractServerLoginModule”. Os comentários do JavaDoc destacam as responsabilidades das sub-classes.
Importante
loginOk é experimental. Ela deve ser configurada para true, caso o logon for bem sucedido ou false por qualquer sub-classes que substituem o método de logon. Caso esta variável for incorretamente usada, o método de confirmação não atualizará corretamente o assunto.
Exemplo 12.9. Fragmento da Classe AbstractServerLoginModule
package org.jboss.security.auth.spi;
/**
* This class implements the common functionality required for a JAAS
* server-side LoginModule and implements the JBossSX standard
* Subject usage pattern of storing identities and roles. Subclass
* this module to create your own custom LoginModule and override the
* login(), getRoleSets(), and getIdentity() methods.
*/
public abstract class AbstractServerLoginModule
implements javax.security.auth.spi.LoginModule
{
protected Subject subject;
protected CallbackHandler callbackHandler;
protected Map sharedState;
protected Map options;
protected Logger log;
/** Flag indicating if the shared credential should be used */
protected boolean useFirstPass;
/**
* Flag indicating if the login phase succeeded. Subclasses that
* override the login method must set this to true on successful
* completion of login
*/
protected boolean loginOk;
// ...
/**
* Initialize the login module. This stores the subject,
* callbackHandler and sharedState and options for the login
* session. Subclasses should override if they need to process
* their own options. A call to super.initialize(...) must be
* made in the case of an override.
*
* <p>
* The options are checked for the <em>password-stacking</em> parameter.
* If this is set to "useFirstPass", the login identity will be taken from the
* <code>javax.security.auth.login.name</code> value of the sharedState map,
* and the proof of identity from the
* <code>javax.security.auth.login.password</code> value of the sharedState map.
*
* @param subject the Subject to update after a successful login.
* @param callbackHandler the CallbackHandler that will be used to obtain the
* the user identity and credentials.
* @param sharedState a Map shared between all configured login module instances
* @param options the parameters passed to the login module.
*/
public void initialize(Subject subject,
CallbackHandler callbackHandler,
Map sharedState,
Map options)
{
// ...
}
/**
* Looks for javax.security.auth.login.name and
* javax.security.auth.login.password values in the sharedState
* map if the useFirstPass option was true and returns true if
* they exist. If they do not or are null this method returns
* false.
* Note that subclasses that override the login method
* must set the loginOk var to true if the login succeeds in
* order for the commit phase to populate the Subject. This
* implementation sets loginOk to true if the login() method
* returns true, otherwise, it sets loginOk to false.
*/
public boolean login()
throws LoginException
{
// ...
}
/**
* Overridden by subclasses to return the Principal that
* corresponds to the user primary identity.
*/
abstract protected Principal getIdentity();
/**
* Overridden by subclasses to return the Groups that correspond
* to the role sets assigned to the user. Subclasses should
* create at least a Group named "Roles" that contains the roles
* assigned to the user. A second common group is
* "CallerPrincipal," which provides the application identity of
* the user rather than the security domain identity.
*
* @return Group[] containing the sets of roles
*/
abstract protected Group[] getRoleSets() throws LoginException;
}
O segundo módulo de logon base abstrato apto para os módulos de logon personalizados é o org.jboss.security.auth.spi.UsernamePasswordLoginModule.
char[] conforme as credenciais de autenticação. Ele suporta também o mapeamento de usuários anônimos (indicados pelo nome do usuário e senha nulos) para um principal sem funções. Os detalhes chave da classe estão destacadas no fragmento da classe seguinte. Os comentários do JavaDoc detalham as responsabilidades das sub-classes.
Exemplo 12.10. Fragmento da Classe UsernamePasswordLoginModule
package org.jboss.security.auth.spi;
/**
* An abstract subclass of AbstractServerLoginModule that imposes a
* an identity == String username, credentials == String password
* view on the login process. Subclasses override the
* getUsersPassword() and getUsersRoles() methods to return the
* expected password and roles for the user.
*/
public abstract class UsernamePasswordLoginModule
extends AbstractServerLoginModule
{
/** The login identity */
private Principal identity;
/** The proof of login identity */
private char[] credential;
/** The principal to use when a null username and password are seen */
private Principal unauthenticatedIdentity;
/**
* The message digest algorithm used to hash passwords. If null then
* plain passwords will be used. */
private String hashAlgorithm = null;
/**
* The name of the charset/encoding to use when converting the
* password String to a byte array. Default is the platform's
* default encoding.
*/
private String hashCharset = null;
/** The string encoding format to use. Defaults to base64. */
private String hashEncoding = null;
// ...
/**
* Override the superclass method to look for an
* unauthenticatedIdentity property. This method first invokes
* the super version.
*
* @param options,
* @option unauthenticatedIdentity: the name of the principal to
* assign and authenticate when a null username and password are
* seen.
*/
public void initialize(Subject subject,
CallbackHandler callbackHandler,
Map sharedState,
Map options)
{
super.initialize(subject, callbackHandler, sharedState,
options);
// Check for unauthenticatedIdentity option.
Object option = options.get("unauthenticatedIdentity");
String name = (String) option;
if (name != null) {
unauthenticatedIdentity = new SimplePrincipal(name);
}
}
// ...
/**
* A hook that allows subclasses to change the validation of the
* input password against the expected password. This version
* checks that neither inputPassword or expectedPassword are null
* and that inputPassword.equals(expectedPassword) is true;
*
* @return true if the inputPassword is valid, false otherwise.
*/
protected boolean validatePassword(String inputPassword,
String expectedPassword)
{
if (inputPassword == null || expectedPassword == null) {
return false;
}
return inputPassword.equals(expectedPassword);
}
/**
* Get the expected password for the current username available
* via the getUsername() method. This is called from within the
* login() method after the CallbackHandler has returned the
* username and candidate password.
*
* @return the valid password String
*/
abstract protected String getUsersPassword()
throws LoginException;
}
A escolha da sub-classificação do AbstractServerLoginModule versus UsernamePasswordLoginModule simplesmente baseia-se no fato do nome do usuário e credenciais baseados na sequência a serem usados ou não pela tecnologia de autenticação que você está gravando para o módulo de logon. Caso a semântica baseada na sequência for válida, o UsernamePasswordLoginModule será sub-classificado. Do contrário, o AbstractServerLoginModule será sub-classificado.
As etapas, pelas quais seu módulo de logon personalizado deve executar, dependem de qual classe de módulo de logon básico você escolher. Quando gravando o módulo de logon personalizado, que integra sua infra-estrutura de segurança, você deve iniciar pela sub-classificação do AbstractServerLoginModule ou UsernamePasswordLoginModule para garantir que seu módulo fornece a informação Principal autenticada pela forma esperada pelo gerenciador de segurança do JBossSX.
AbstractServerLoginModule:
void initialize(Subject, CallbackHandler, Map, Map): caso você possua opções de personalização para análise.boolean login(): para executar a atividade da autenticação. Certifique-se de configurar a variável da instâncialoginOkpara verdadeiro caso o logon for bem sucedido e falso caso ele falhar.Principal getIdentity(): para retornar o objetoPrincipalpara o usuário autenticado pela etapalog().Group[] getRoleSets(): para retornar pelo menos umGroupnomeadoRolesque contém as funções determinadas aoPrincipalautenticado durante ologin(). O segundoGroupcomum é nomeadoCallerPrincipale fornece a identidade do aplicativo do usuário ao invés da identidade do domínio de segurança.
UsernamePasswordLoginModule:
void initialize(Subject, CallbackHandler, Map, Map): caso você possua opções de personalização para análise.Group[] getRoleSets(): para retornar pelo menos umGroupnomeadoRolesque contém as funções determinadas aoPrincipalautenticado durante ologin(). O segundoGroupcomum é nomeadoCallerPrincipale fornece a identidade do aplicativo do usuário ao invés da identidade do domínio de segurança.String getUsersPassword(): para retornar a senha esperada pelo nome de usuário atual disponível através do métodogetUsername(). O métodogetUsersPassword()é chamado a partir dologin()após ocallbackhandlerretornar o nome do usuário e senha do candidato.