Configuração JAAS

Como forçar o usuário a realizar a autenticação em um sistema em dois passos:

Por Exemplo:
1º O usuário deve auenticar através de login e senha.
2º O usuário deverá autenticar informando uma senha cruzada de um cartão especifico para cada usuário, onde cada cartão possuirá 50 chaves, cada uma com um valor espeficico de 3 digitos.

Obs: A primeira e a segunda autenticação já estão implementadas, mas não estou sabendo forçar o usuário a realizar a segunda autenticação. O usuário autentica com login e senha e já tem acesso a aplicação. Ele é obrigado a realizar outra autenticação para obter acesso.

O que devo configurar para forçar o usuário a autenticar nesses dois passos?
Ou como devo configurar?

Desde já agradeço.

Não sei se JAAS suporta login em múltiplas fases.
O que você pode fazer é implementar um Servlet Filter que verifica se o segundo login foi feito.

Daniel, você tem algum material que possa me indicar, de como implementar este ServletFilter.
Não tenho nem idéia de como fazer essa verificação, como configurar no web.xml, etc…

http://www.developer.com/java/ent/article.php/3467801
http://www.javafree.org/content/view.jf?idContent=115

Muito obrigado, a todos…
Estava querendo achar uma solução para este meu problema.
Acho que isto vai me ajudar, vou olhar estes materiais e ver como implementar este recurso.

Só de curiosidade, quando o usuário vai fazer o login ele já possui toda as informações (conta, senha, contra senha) ou 1o. ele informa conta&senha e depois ele informa a contra senha, tipo challenge/response ?

para o 1a. caso o jaas funciona suave, para o 2o., forçando o jaas, é possível, mas é meio bacalhau (pode ser um handler só mas eu mostrar com 2 pq fica um pouco menos feio): um handler cuida da conta&senha tradicional e o outro da contra senha:

1 ) 1o. acesso, o usuário é redirecionado para o jsp (jsf, velocity, *) do logon
2 ) ele entra conta e senha e submit
3 ) o jaas invoca o 1o. handler que testa a conta&senha, coloca os dados ou o resultado na sessão e vota ok.
4 ) o jaas invoca o 2o. handler que cria o desafio, taca na sessão e vota contra.
5 ) como o jaas negou, a view de login é mostrada novamente
6 ) esta view é smart e sabe (pela sessão) que está na 2a. fase, pega o desafio e mostra
7 ) o usuário informa a contra senha e submit
8 ) o jaas faz a dança de novo, mas agora o 1o. handler recupera os dados da sessão e vota ok.
9 ) o 2o. handler pega a contra-senha, o desafio, testa e vota ok
10 ) o logon é aprovado e o cara entra na aplicação

Porém, contudo, todavia:
Para o trampo da sessão funcionar, o seu callback precisa expor a mesma, mas normalmente ele é hardcoded pelo app server (a classe é dele, e ele só cria as que ele sabe). Isso é um fatores que limitam o “uso criativo” do jaas num container.
Para vc fazer o “uso criativo” do jaas, com os seus callbacks, vc teria que invocar o jaas “manualmente”, e talvez o security manager do container não fique empolgado com isso…

Dado isso, talvez a parada do servlet filter seja um saco de gatos menor.

Primeiramente o usuário deverá informar (username e senha), após conseguir atenticar com sucesso nesse passo, ele deve realizar outra autenticação.
Quando eu submeto a segunda autenticação(Tela do Cartão) com as informações de username, número da chave do cartão(senha cruzada), gostaria que o JAAS interpretasse isso como uma nova autenticação e usa-se um LoginModule que implementei para realizar este processo.

Como eu posso dizer para o JAAS, que quando o usuário autenticar a primeira vez com sucesso, não dar acesso a aplicação ainda, direcionar ele para a segunda tela de autenticação para obriga-lo a passar por esta nova autenticação para poder ter acesso total.

  1. Cada tentativa de login é uma nova tentativa para o jaas (ele não guarda estado), se o seu módulo guarda e como ele guarda, é problema do seu módulo (Threadlocal, http session, cookie, hidden field, etc).
  2. Recomendo vc usar 2 módulos, pq os requisitos para eles são diferentes.
  3. Veja a documentação do Configuration p/ se familiarizar c/ os conceitos de required, requisite, etc: (http://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/login/Configuration.html)
    e reveja tb o lance do callback/callback handler (http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.html#CallbackHandler)
  4. O grande truque (já reparou que todo kludge sujo é chamado de truque ?) do que te falei é reter estado (seja no cliente, seja no servidor) de forma que na 2a. invocação o jaas tenha toda a informação necessária para fazer a autenticação.

IndyanaJones.

Implementei um filter para realizar a autenticação da segunda fase(usuario, cartão e senha cruzada).

Mas agora quero poder capturar as informações da requisição da primeira fase(login e senha).

No filter pego o request, e vejo que existe um PrincipalGeneric com as informações que submeti(Via JAAS), mas não consigo captura-las para jogar na seção e buscar na segunda fase da autenticação.

Preciso dessas informações, poque quando submeto, com um usuario e senha, na segunda autenticação é necessário verificar se o usuario informado é igual ao primeiro usuário.

[b]Por exemplo autenticação na 1º fase:
usuário: heider / senha: 123

Por exemplo na 2º autenticação:
usuário: carlos / chaveCartão: 526[/b]

Se nesta 2º fase o usuário autentica corretamente, terá acesso a aplicação.

Os usuário são diferentes, então quando o login passar pela mimha classe SecurityFilter na 1º autenticação, preciso guardar essas informações.

Estrutura do projeto:
CiospLoginModule --> Autentica o Login
CiospCallbackHandler --> Responsável por capturar usuário e senha.
UsuarioPrincipal --> Representa a conta do usuário.
RolePrincipal --> Representa as permissões do usuário

No método public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) da minha classe SecurityFilter, capturo o request e vejo que lá existe um objeto chamado userPrincipal com o usuário informado e suas permissões, mas não consigo captura-las.

Tento captuara com o código request.getParameter(“j_password”);
mas me retonar null.

Você saberia com captura-las?

me explica de novo pq eu sou surfista :slight_smile:

O seu filtro invoca o jaas nos 2 momentos ou o container invoca a 1a e o filtro a 2a. ?
Qual container web vc está usando tomcat ?

Pelo que eu entendi do seu problema, vc teria 2 CallbackHandler, um para o tradicional conta&senha e outro para a contra-senha.

imagine algo assim (nada como zero get’s e set’s :slight_smile: ):

class ContaSenhaCallback implements Callback {
 public String conta;
 public String senha;
}

class ContrasenhaCallback implements Callback {
 public String desafio
 public String respostaDesafio
}

class CbHandler implements CallbackHandler{
 public String userName, password, contraSenha, respContraSenha;
 public void handle(Callback[] callbacks){
  for(int i=0; i<callbacks.length; i++){
   Callback cb = callbacks[i];
   if(cb instanceof ContaSenhaCallback ){
     /* set conta e senha */
   }
   if(cb instanceof ContrasenhaCallback ){
     if(contraSenha == null) { //1a. fase
       contraSenha = ((ContrasenhaCallback)cb).desafio;
       throw new AlgumaRuntimeXceptMinha();
     } else {
       ((ContrasenhaCallback)cb).desafio = contraSenha;
       ((ContrasenhaCallback)cb).respostaDesafio = respContraSenha;
     }
   }
  }
 }
}

class JaasLoginModule {
 public boolean login() ... {
  loginPassword =  new ContaSenhaCallback();
  Callback[] callbacks = new Callback[]{loginPassword};
  callbackHandler.handle(callbacks);
  /* autoriza conta&senha */

  contraSenha = new ContrasenhaCallback();
  contraSenha.desafio = /*cria desafio*/
  callbacks = new Callback[]{contraSenha};
  callbackHandler.handle(callbacks);
  /* autoriza contra senha*/
 }
}
}

class MeuFilter {
 public void doFilter(request, response, chain) {
  public HttpSession session = request.getSession(true);
  Principal user = session.getAttr('user');
  if( user == null )
    /* forward to loginConta&Senha.jsp que faz post para LoginServlet */
 }
 else{
  /* crie um HttpServletRequestWrapper e coloque o seu principal nele */
  meurequest.setPrincipal(user);
 chain.doFilter(....)
 }
}

class LoginServlet { /*que não é interceptada pelo filter*/
  private getValue(String value, request, session){
   /*se value não está na sessão, veja se está no request*/
  }

  public doPost(request, response){
   public HttpSession session = request.getSession(true);
   try{
    CbHandler cbh = new CbHandler();
    cbh.userName = getValue('username', request, session);
    cbh.password = getValue('pwd', request, session);
    cbh.contraSenha = getValue('Desafio, request, session);
    cbh.respContraSenha = getValue('respDesafio', request, session);
    LoginContext lc = new LoginContext( "<jaas ctx>", cbh );
    lc.login();
    Subject subj = lc.getSubject();
    Principal user = /* extraia do subj o principal que representa o seu usuário (os meus principals são quase um outro subject, por exemplo)*/
    session.setAttr('user', user);
   /*limpa da sessão os outros valores (conta, password, desafio, rep. desafio)*/
   }catch(AlgumaRuntimeXceptMinha arxm){
     session.setAttr('username', ...);
     session.setAttr('pwd', ...);
     session.setAttr('desafio', ...);
     /* forward para  loginComContraSenha.jsp que posta para LoginServlet */
   }
   }catch(...){
   }
   
  }
}
  1. O usuário acessa um bookmark, seu filtro entra e pela sessão sabe que ele não está autenticado, e faz um forward para 1a. tela de login (conta e senha)
  2. Quando o user fizer o post, a servlet entra extrai os valores do requet/session cria o callbackHandler, coloca as informações nele e submete ao jaas, se ocorrer uma exception sua que sinaliza o fim da 1a. fase vc exibe outro jsp que mostra o desafio (que está na sessão) e captura a resposta do mesmo.
  3. No 2o. post, todos os dados estão presentes e o jaas pode autenticar

Ps- não garanto muito (leia-se: nada) esse pseudo-código-bacalhau

qualquer coisa grite :slight_smile:

[quote]O seu filtro invoca o jaas nos 2 momentos ou o container invoca a 1a e o filtro a 2a. ?
Qual container web vc está usando tomcat ?[/quote]

Uso o tomcat 5.0.xxxx

O servidor autentica com o JAAS corretamente, se a autenticação for realizada com sucesso, ai a requisição chega ao filtro, onde testo se o usuario realizou a 2º autenticação.

A 1º fase da autenticação, é realizada através do JAAS. Criei uma classe que implementa a interface LoginModule, cria a minha classe CallbackHandler, e a classe UsuarioPrincipale RolePrincipal(Representa os papéis do usuário).
Fiz as configurações necessárias para o JAAS no web.xml, defini a jsp que deverá utilizar para autenticação do login e senha e a a jsp de erro caso a autenticação falhe.

Configurei o server.xml, criei um arquivo de configuiração e adicionei na pasta conf do tomcat, alterei um arquivo de segurança do jsk 1.5 instalado.

Até aqui beleza fuiciona que é uma beleza.

Na 2º fase da autenticação, utilizo um servlet que realiza todo processo de auetenticação, nesta fase toda requição passa pelo filtro, onde verifico se o usuario autenticou corretamente, se sim redireciono ele para a tela principal do sistema senão obrigo ele autenticar na segunda página com os dados do cartão gerado para ele, enquanto não realizar a segunda autenticação não terá acesso a aplicação.

Implementei desta forma, a minha autenticação.

VOCÊ ME SUGERE UMA OUTRA FORMA DE REALIZAR TODO ESSE PROCESSO!

CASO POSSA ME AJUDAR, FICAREI MUITO AGRADECIDO.

Até, fuiiiiiiii.

[quote] VOCÊ ME SUGERE UMA OUTRA FORMA DE REALIZAR TODO ESSE PROCESSO!
[/quote]
Se está funcionando e vc está satisfeito, deixa rolar… :slight_smile: Certamente deve mais um milhão de coisas adicionais no teu projeto para fazer e a ampulheta não vai parar.
Caso vc tenha tempo (e interesse) depois tente colocar tudo dentro do jaas, embora não exista nenhum grande motivo para isso (se muito, é pq ele é que deveria gerir essa parte e deixar a sua aplicação isolada do “como”)

Qualquer coisa grita… 8)

Digitei Servlet Filter no google, ele me falou:

http://java.sun.com/products/servlet/Filters.html