Capítulo 2. Introdução ao JAAS
O framework JBossSX é baseado no JAAS API. Você deve entender os elementos básicos do JAAS API antes de você poder entender os detalhes de implantação do JBossSX. As seguintes seções fornecem uma introdução ao JAAS para prepará-lo à discussão sobre a arquitetura JBossSX descrita adiante neste guia.
O JAAS 1.0 API consiste de um conjunto de pacotes Java designados para autenticação e autorização do usuário. O API implementa a versão Java do framework de Módulos de Autenticação Pugláveis - Pluggable Authentication Modules (PAM) e extende a arquitetura de controle de acesso à Plataforma Java 2 para suportar autorização baseada no usuário.
O JAAS foi liberado primeiramente como um pacote de extensão para o JDK 1.3 e vinculado com o JDK 1.5. Esta introdução baseia-se na autenticação de capacidades do JAAS para implantar o modelo de segurança J2EE baseado na função declarativa, uma vez que o framework do JBossSX apenas utiliza este procedimento.
A autenticação do JAAS é executada de modo puglável. Isto permite que os aplicativos Java mantenham-se independentes das tecnologias de autenticação e permite que o gerenciador de segurança JBossSX trabalhe em diferentes infra-estruturas de segurança. A integração com a infra-estrutura de segurança é alcançada sem a alteração da implantação do gerenciador de segurança JBossSX. Você precisa apenas alterar a configuração da autenticação que a pilha JAAS usa.
2.1. Classes Principais do JAAS
As classes principais JAAS podem ser divididas em três categorias: comum, autenticação e autorização. A seguinte lista apresenta as classes de autenticação e comum uma vez que as classes específicas costumavam a implantar a funcionalidade do JBossSX descrita neste capítulo.
Segue abaixo as classes comuns:
Subject
(javax.security.auth.Subject
)Principal
(java.security.Principal
)
Elas são as classes de autenticação:
Callback
(javax.security.auth.callback.Callback
)CallbackHandler
(javax.security.auth.callback.CallbackHandler
)\n\t\nConfiguration
(javax.security.auth.login.Configuration
)LoginContext
(javax.security.auth.login.LoginContext
)LoginModule
(javax.security.auth.spi.LoginModule
)
2.1.1. Classes do Assunto e Principal
Os aplicativos devem ser primeiramente autenticados na fonte do solicitante com o objetivo de autorizar o acesso aos recursos. O framework JAAS define o termo assunto para representar uma fonte do solicitante. A classe
Subject
é a classe central no JAAS. O Subject
representa a informação para a entidade única, tal como uma pessoa ou serviço. Ele abrange os principais da entidade, credenciais públicos e credenciais privados. Os JAAS APIs usam a interface java.security.Principal
do Java 2 existente para representar um principal, que é basicamente um nome digitado.
Um assunto é populado com as identidades ou principais durante o processo de autenticação. Um assunto pode possuir diversos principais. Por exemplo, uma pessoa pode possuir o principal de nome (John Doe), um principal de número de segurança social (123-45-6789) e um principal de nome de usuário (johnd), sendo que todos ajudam a distinguir o assunto de outros assuntos. Segue abaixo dois métodos disponíveis para restauração dos principais associados com um assunto.
public Set getPrincipals() {...} public Set getPrincipals(Class c) {...}
O
getPrincipals()
retorna todos os principais contidos no assunto. O getPrincipals(Class c)
retorna apenas os principais que são instâncias de classe c
ou uma se suas sub-classes. Um conjunto vazio é retornado caso o assunto não possua principais de combinação.
Perceba que a interface
java.security.acl.Group
é uma sub-interface do java.security.Principal
, portanto uma instância no conjunto dos principais pode representar o agrupamento lógico de outros principais ou grupos de principais.
2.1.2. Autenticação do Assunto
A Autenticação do Assunto requer um logon JAAS. O procedimento de logon consiste das seguintes etapas:
- O aplicativo instancia um
LoginContext
e passa o nome da configuração de logon, além de umCallbackHandler
para popular os objetosCallback
, conforme solicitado pelosLoginModule
s da configuração. - O
LoginContext
consulta umConfiguration
para carregar todos osLoginModules
incluídos na configuração de logon nomeada. Caso tal configuração nomeada não existir, a configuraçãoother
será usada como padrão. - O aplicativo invoca o método
LoginContext.login
. - O método de logon invoca todos os
LoginModule
s carregados. Uma vez que cadaLoginModule
tenta autenticar o assunto, ele invoca o método de manuseio noCallbackHandler
associado para obter informações solicitadas para o processo de autenticação. A informação requerida é passada para manuseio do método na forma de um array de objetosCallback
. Caso bem sucedido, osLoginModule
s associam principais e credenciais relevantes com o assunto. - O
LoginContext
retorna o status de autenticação para o aplicativo. O sucesso da operação é representado pelo retorno do método de logon. A falha é representada através de um LoginException sendo lançado através do método de logon. - Caso a autenticação seja bem sucedida, o aplicativo restaura o assunto autenticado usando o método
LoginContext.getSubject
. - Após o escopo da autenticação do assunto ser completado, todos os principais e informações relacionadas associadas com o assunto pelo método de logon podem ser removidos pela invocação do método
LoginContext.logout
.
A classe
LoginContext
fornece os métodos básicos de 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 para um aplicativo em particular. As classes LoginModule
representam os serviços de autenticação. Portanto, você pode conectar-se a diferentes módulos de logon em um aplicativo sem alterar o próprio aplicativo. O seguinte código apresenta as etapas solicitadas por um aplicativo para autenticar o 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 implantação da interface
LoginModule
. Isto permite que um administrador conecte-se a diferentes tecnologias de autenticação em um aplicativo. Você pode formar uma cadeia de múltiplos LoginModule
s para permitir que mais de uma tecnologia de autenticação participe no processo de autenticação. Por exemplo, um LoginModule
pode executar a autenticação baseada no nome/senha do usuário, enquanto outro pode ser a interface para dispositivos de hardware tais como leituras de cartões e autenticadores biométricos.
O ciclo de vida de um
LoginModule
é dirigido pelo objeto LoginContext
pelo qual o cliente crie e imprime o método de logon. O processo consiste em duas fases. Segue abaixo as etapas do processo:
- O
LoginContext
cria cadaLoginModule
configurado usando o construtor não-arg. - Cada
LoginModule
é inicializado por uma chamada para inicializar cada método. Garante-se que o argumentoSubject
seja não-nulo. A assinatura do método inicializar é a seguinte: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 implantação do método pode pedir a um usuário pelo nome e senha do usuário e verificar a informação sobre os dados armazenados no serviço de nomeação, tais como o NIS ou LDAP. Implantações alternativas podem servir como interface para cartões smart e dispositivos biométricos, ou simplesmente extrair a informação do usuário a partir do sistema de operação subjacente. A validação da identidade do usuário por cadaLoginModule
é considerada fase 1 da autenticação do JAAS. A assinatura do método delogin
é oboolean login() throws LoginException
. OLoginException
indica falha. O valor de retorno verdadeiro indica que o método é bem sucedido, onde o valor de retorno negativo indica que o módulo de logon deve ser ignorado. - Caso a autenticação de visão geral do
LoginContext
seja bem sucedida, ocommit
é invocado em cadaLoginModule
. Caso a fase 1 suceda para umLoginModule
, o método de confirmação continua na fase 2 e associa os principais relevantes, credenciais públicos e/ou credenciais privados com o assunto. Caso a fase 1 falhar para oLoginModule
, ocommit
removerá qualquer estado de autenticação armazenado anteriormente, tal como nomes e senhas de usuário. A assinatura do métodocommit
é a seguinte:boolean commit() throws LoginException
. A falha em completar a fase de confirmação é indicada pelo lançamento de umLoginException
. O retorno como verdadeiro indica que o método é bem sucedido, onde o retorno como falso indica que o módulo de logon deve ser ignorado. - Caso a autenticação da visão geral do
LoginContext
falhar, o métodoabort
será invocado em cadaLoginModule
. O métodoabort
remove ou destrói qualquer estado de autenticação criado pelos métodos de logon ou inicialização. A assinatura do métodoabort
é oboolean abort() throws LoginException
. A falha em completar a faseabort
é indicada pelo lançamento de umLoginException
. O retorno como verdadeiro indica que o método foi bem sucedido, onde o retorno como falso indica que o módulo de logon deve ser ignorado. - Para remover o estado de autenticação após o logon com êxito, o aplicativo invoca o
logout
noLoginContext
. Este, por sua vez resulta numa invocação de métodologout
em cadaLoginModule
. O métodologout
remove os principais e credenciais originalmente associados com o assunto durante a operaçãocommit
. Os credenciais devem ser destruídos na remoção. A assinatura do métodologout
é a seguinte:boolean logout() throws LoginException
. A falha em completar o processo de saída é indicada pelo lançamento de umLoginException
. O retorno como verdadeiro indica que o método foi bem sucedido, onde o retorno como falso indica que o módulo de logon deve ser ignorado.
Quando o
LoginModule
necessitar comunicar-se com o usuário para obtenção de informação da autenticação, ele usará um objeto CallbackHandler
. Os aplicativos implementam a interface CallbackHandler e passam-as ao LoginContext
, que envia a informação de autenticação diretamente aos módulos de logon subjacentes.
Os módulos de logon usam ambos
CallbackHandler
para obterem entradas dos usuários, tais como uma senha ou PIN de cartão smart, além de fornecerem informação aos usuários tais como informação de status. Quando permitindo que o aplicativo especifique o CallbackHandler
, os LoginModule
s subjacentes continuam independentes das diversas maneiras em que os aplicativos interagem com os usuários. Por exemplo, uma implantação do CallbackHandler
para um aplicativo GUI pode exibir uma janela para solicitar a entrada do usuário. Por outro lado, uma implantação CallbackHandler
para um ambiente sem GUI, tal como o servidor do aplicativo, pode simplesmente obter informação do credencial pelo uso de um API do servidor do aplicativo. A interface callbackhandler possui um método para implantação:
void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException;
A interface
Callback
é a última classe de autenticação que iremos observar. Ela é uma interface de marcação pela qual diversas implantações padrões são fornecidas, incluindo o NameCallback
e PasswordCallback
usado numa amostra anterior. O LoginModule
usa um Callback
para obter informação solicitada pelo mecanismo de autenticação. Os LoginModule
s passam um array dos Callback
s diretamente ao método CallbackHandler.handle
durante a fase de logon da autenticação. Caso um callbackhandler
não entender como usar um objeto Callback
passado a um método de manuseio, ele lança um UnsupportedCallbackException
para abortar a chamada de logon.