3.4. Autenticação do Assunto

A Autenticação do Assunto requer um login JAAS. O processo de login consiste dos seguintes critérios:
  1. Um aplicativo inicia um LoginContext e passa o nome da configuração do login e um CallbackHandler para popular os assuntos Callback, conforme requerido pela configuração LoginModules.
  2. O LoginContext consulta o Configuration para carregar todos os LoginModules incluídos na configuração de login nomeada. Caso tal nome não existir, a configuração other é usada como default.
  3. O aplicativo invoca o método LoginContext.login.
  4. O método de login invoca todos os LoginModules carregados. Uma vez que cada LoginModule tenta autenticar o assunto, ele invoca o método de manuseio no CallbackHandler associado para obter a informação requerida pelo processo de autenticação. A informação requerida é passada ao método de manuseio na forma de um array dos assuntos Callback. No caso de êxito, os LoginModules associam os principais e credenciais relevantes ao assunto.
  5. O LoginContext retorna o status de autenticação ao aplicativo. O sucesso é representado por um retorno de um método de login. A falha é representada através de um LoginException sendo lançado pelo método de login.
  6. Caso a autenticação suceder, o aplicativo recupera o assunto autenticado usando o método LoginContext.getSubject.
  7. Após o escopo da autenticação do assunto ser concluído, todos os principais e informações relacionadas associadas ao assunto pelo método login podem ser removidas pela invocação do método LoginContext.logout.
A classe LoginContext fornece os métodos básicos para autenticação dos assuntos e oferece uma maneira de desenvolver um aplicativo que é independente da tecnologia de autenticação subjacente. O LoginContext consulta um Configuration para determinar os serviços de autenticação configurados a um aplicativo em particular. As classes LoginModule representam os serviços de autenticação. Portanto, você pode plugar diferentes módulos de login num aplicativo sem a alteração do próprio aplicativo. Os seguintes códigos apresentam as etapas requeridas por um aplicativo para autenticar um assunto.
CallbackHandler handler = new MyHandler();
LoginContext lc = new LoginContext("some-config", handler);

try {
    lc.login();
    Subject subject = lc.getSubject();
} catch(LoginException e) {
    System.out.println("authentication failed");
    e.printStackTrace();
}
                        
// Perform work as authenticated Subject
// ...

// Scope of work complete, logout to remove authentication info
try {
    lc.logout();
} catch(LoginException e) {
    System.out.println("logout failed");
    e.printStackTrace();
}
                        
// A sample MyHandler class
class MyHandler 
    implements CallbackHandler
{
    public void handle(Callback[] callbacks) throws
        IOException, UnsupportedCallbackException
    {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof NameCallback) {
                NameCallback nc = (NameCallback)callbacks[i];
                nc.setName(username);
            } else if (callbacks[i] instanceof PasswordCallback) {
                PasswordCallback pc = (PasswordCallback)callbacks[i];
                pc.setPassword(password);
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                                                       "Unrecognized Callback");
            }
        }
    }
}
Os desenvolvedores integram uma tecnologia de autenticação pela criação de uma implementação da interface LoginModule. Isto permite o administrador a plugar diferentes tecnologias de autenticação num aplicativo. Você pode encadear diversos LoginModules para permitir que mais de uma tecnologia de autenticação participe no processo de autenticação. Por exemplo, um LoginModule pode executar uma autenticação baseada no nome/senha do usuário, enquanto que outro pode realizar a interface aos dispositivos de hardware tais como leituras de cartões smart ou autenticadores biométricos.
O ciclo de vida de um LoginModule é dirigido pelo objeto LoginContext em relação ao cliente que cria e emite o método de login. O processo consiste de duas fases. As etapas do processo são:
  • O LoginContext cria cada configuração LoginModule usando seu construtor sem argumento público.
  • Cada LoginModule é inicializado com uma chamada ao seu método inicializar. O Subject argumento é garantido como não nulo. A assinatura do método inicializar é: public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
  • O método login é chamado para iniciar o processo de autenticação. Por exemplo, a implementação do método pode perguntar ao usuário pelo nome e senha do usuário e então verificar a informação em relação aos dados stored num serviço de nomeação tal como o NIS ou LDAP. As implementações alternativas podem realizar a interface para cartões smart e dispositivo biométricos, ou simplesmente extrair a informação do usuário a partir de um sistema de operação subjacente. A validação da identidade do usuário por cada LoginModule é considerada fase 1 da autenticação JAAS. A assinatura do método login é boolean login() throws LoginException . Um LoginException indica falha. Um valor de retorno verdadeiro indica que o método foi bem sucedido, onde um valor de retorno de falso indica que o módulo de login deve ser ignorado.
  • Caso a autenticação no geral LoginContext suceder, o commit é invocado em cada LoginModule. Caso a fase 1 suceder para o LoginModule, o método de confirmação continua com a fase 2 e associa os principais relevantes, credenciais públicos e/ou credenciais privados com o assunto. Caso a fase 1 falhar para um LoginModule, então o commit remove qualquer estado de autenticação stored anteriormente, tais como nomes e senhas de usuários. A assinatura do método commit é: boolean commit() throws LoginException . A falha em concluir a fase de confirmação é indicada pelo lançamento do LoginException. Um retorno verdadeiro indica que o método sucedeu, onde um retorno falso indica que o módulo de login deve ser ignorado.
  • Caso a autenticação no geral LoginContext, então o método abort é invocado em cada LoginModule. O método abort remove ou destroi qualquer estado de autenticação criado pelos métodos inicializar ou login. A assinatura do método abort é boolean abort() throws LoginException . A falha em completar a fase abort é indicada pelo lançamento de um LoginException. Um retorno verdadeiro indica que o método sucedeu, onde um retorno falso indica que o módulo de login deve ser ignorado.
  • Com o objetivo de remover o estado de autenticação após êxito de login, o aplicativo invoca logout no LoginContext. Isto em troca resulta numa invocação do método logout em cada LoginModule. O método logout remove os principais e credenciais originalmente associados com o assunto durante a operação commit. Os credenciais devem ser destruídos sob remoção. A assinatura do método logout é: boolean logout() throws LoginException . A falha em concluir o processo de saída é indicado pelo lançamento um LoginException. Um retorno verdadeiro indica que o método sucedeu, onde um retorno de falso indica que o módulo de login deve ser ignorado.
Quando um LoginModule precisa comunicar-se com o usuário para obter a informação de autenticação, ele usa um objeto CallbackHandler. Os aplicativos implementam a interface CallbackHandler e passam isto ao LoginContext, que envia a informação de autenticação diretamente aos módulos de login subjacente.
Os módulos de login usam o CallbackHandler para tanto obter a entrada de usuários, tais como uma senha ou PIN do cartão smart e para suprir informação aos usuários, tais como informação de status. Permitir que o aplicativo especifique o CallbackHandler, os LoginModules subjacentes continuam independentes de maneiras diferentes dos aplicativos interagirem com os usuários. Por exemplo: uma implementação CallbackHandler para um aplicativo GUI pode exibir uma janela para solicitar a entrada do usuário. Por outro lado, uma implementação CallbackHandler para um ambiente não GUI, tal como um servidor do aplicativo, pode simplesmente obter a informação do credencial pelo uso de um API do servidor do aplicativo. A interface CallbackHandler possui um método de implementação:
void handle(Callback[] callbacks)
    throws java.io.IOException, 
           UnsupportedCallbackException;
A interface Callback é a última classe de autenticação que vamos ver. Ela é uma interface tagging da qual diversas implementações default são fornecidas, incluindo o NameCallback e PasswordCallback usados num exemplo anterior. O LoginModule usa um Callback para solicitar informação requerida pelo mecanismo de autenticação. O LoginModules passa um array de Callbacks diretamente ao método CallbackHandler.handle durante a fase de login de autenticação. Caso um callbackhandler não entender como usar o objeto Callback passado ao método de manuseio, ele lança um UnsupportedCallbackException para anular a chamada de login.