Como usar JAAS com Tomcat 6.0 1) Passos para criar o módulo de autenticação e autorização a) Crie novo “Java Project”; Ex.: AppLoginModuleJAAS b) Nele, crie 2 pacotes; Ex.: br.pro.passos.security br.pro.passos.security.principal c) No primeiro pacote, crie uma classe, digamos “LoginModuleJAASImpl”, que implemente a interface “LoginModule”; d) No segundo pacote, crie as classes “UsuarioImplPrincipal” e “PapelImplPrincipal”, que, como o nome sugere, implementem a interface “Principal”; e) Compile o projeto para um arquivo de nome “LoginModuleJAAS.jar”; f) Coloque o arquivo “LoginModuleJAAS.jar”, criado em “e”, no diretório “lib” do Tomcat; g) Crie um arquivo “jaas.config” com o conteúdo abaixo: ModuloLoginJAAS { br.pro.passos.security.LoginModuleJAASImpl required; }; h) Coloque o arquivo “jaas.config”, criado em “g”, no diretório “conf” do Tomcat; i) Insira no arquivo “catalina.bat”, presente no diretório “bin” do Tomcat, antes da linha comentada “Execute The Requested Command”, a linha abaixo: set JAVA_OPTS=%JAVA_OPTS% -Djava.security.auth.login.config="%CATALINA_BASE%\conf\jaas.config" @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 1 Como usar JAAS com Tomcat 6.0 2) Passos para criar aplicativo web escrito em Java para testar o módulo de autenticação e autorização a) Crie novo “Dynamic Web Project”. Ex.: AppWebTestaJAAS b) No diretório “WebContent”, crie as páginas JSP: index.jsp login.jsp erroLogin.jsp erro403.jsp logout.jsp cadastros.jsp relatorios.jsp Os códigos-fonte dessas páginas encontram-se no fim deste documento. Vamos comentar apenas alguns poucos trechos. Na página “login.jsp”, deve-se notar o valor do atributo “action” (j_security_check) e dos atributos “name” dos campos type (j_username)e password (j_password). <form method="POST" action="j_security_check"> <table> <tr> <td>Usuário</td> <td><input type="text" name="j_username" /></td> </tr> <tr> <td>Senha</td> <td><input type="password" name="j_password" /></td> </tr> <tr> <td colspan="2"><input type="submit" value="Login" /></td> </tr> </table> Na página “logout.jsp”, código-abaixo, observe que a sessão é finalizada e o usuário é redirecionado para a página “index.jsp”, o que, por sua vez, levará o usuário para a página de login novamente. <% session.invalidate(); response.sendRedirect("index.jsp"); %> Nas páginas “index.jsp”, “cadastros.jsp”, “relatórios.jsp” e “erro403.jsp”, a linha abaixo é responsável por exibir uma saudação personalizada para o usuário autenticado. @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 2 Como usar JAAS com Tomcat 6.0 <h3>Olá, <%= request.getRemoteUser() %>!!!</h3> c) No diretório “META-INF”, crie um arquivo “context.xml” com o seguinte conteúdo: <?xml version="1.0" encoding="UTF-8"?> <Context auth="Container"> <Realm className="org.apache.catalina.realm.JAASRealm" appName="ModuloLoginJAAS" userClassNames="br.pro.passos.security.principal.UsuarioImplPrincipal" roleClassNames="br.pro.passos.security.principal.PapelImplPrincipal" /> </Context> Observe que atribuímos a “appName” o nome dado ao módulo de autenticação e autorização no arquivo “jaas.config”. Observe também que usamos o nome totalmente qualificado das classes que representam os usuários e os papéis. d) No arquivo “web.xml”, inclua as linhas: <login-config> <auth-method>FORM</auth-method> <realm-name>default</realm-name> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page>/erroLogin.jsp</form-error-page> </form-login-config> </login-config> <security-constraint> <display-name>Política de segurança do sistema</display-name> <web-resource-collection> <web-resource-name>Protege todo o site</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>AUTENTICADO</role-name> </auth-constraint> </security-constraint> <security-role> <description>Papel requerido para acessar quaisquer recursos do aplicativo</description> <role-name>AUTENTICADO</role-name> </security-role> <error-page> <error-code>403</error-code> <location>/erro403.jsp</location> </error-page> @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 3 Como usar JAAS com Tomcat 6.0 Em <security-constraint>, definimos a política de acesso ou as restrições de segurança. No exemplo, estabelecemos que apenas usuários com status, perfil, papel ou função “AUTENTICADO” poderão acessar o aplicativo. Aos papéis, <role-name>, de <security-constraint> devem corresponder <role-name> em <security-role>. Em <login-config>,estabelecemos a forma de autenticação. Neste exemplo, FORM. Também mapeamos as páginas de login e erro de login. Ou seja, informamos a página em que o usuário informará seu nome de usuário (username) e senha (password), e a página que será exibida se a autenticação falhar (usuário e senha não conferem). Se o usuário for autenticado, mas não tiver permissão, autorização, para acessar um recurso, ocorrerá o erro 403, e a página erro403.jsp será exibida. e) A organização das páginas JSP e dos arquivos XML do aplicativo deve ser com abaixo: @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 4 Como usar JAAS com Tomcat 6.0 3) Códigos-fonte das classes do módulo de autenticação e autorização Classe UsuarioImplPrincipal.java package br.pro.passos.security.principal; import java.security.Principal; public class UsuarioImplPrincipal implements Principal{ private String name = null; public UsuarioImplPrincipal(String name) { super(); this.name = name; } public String getName() { return name; } } Classe PapelImplPrincipal.java package br.pro.passos.security.principal; import java.security.Principal; public class PapelImplPrincipal implements Principal { private String name = null; public PapelImplPrincipal(String name){ this.name= name; } public String getName() { return this.name; } } @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 5 Como usar JAAS com Tomcat 6.0 Classe LoginModuleJAASImpl.java package br.pro.passos.security; import java.io.IOException; import java.util.HashMap; 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.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import br.pro.passos.security.principal.PapelImplPrincipal; import br.pro.passos.security.principal.UsuarioImplPrincipal; public class LoginModuleJAASImpl implements LoginModule { protected Subject subject = null; protected CallbackHandler callbackHandler = null; protected Map sharedState = null; protected Map options = null; protected Callback[] callbacks = null; protected Set principals = null; UsuarioImplPrincipal usuario = null; PapelImplPrincipal papel = null; String username = null; String password = null; private boolean loginComSucesso = false; private boolean commitComSucesso = false; Map senhas = new HashMap(); public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { this.subject = subject; this.callbackHandler = callbackHandler; this.sharedState = sharedState; this.options = options; @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 6 Como usar JAAS com Tomcat 6.0 this.senhas.put("fulano", "a"); this.senhas.put("beltrano", "b"); this.senhas.put("cicrano", "c"); } public boolean login() throws LoginException { this.tratarCallback(); this.username = this.getUsername(); this.password = this.getPassword(); if (this.username!=null && this.password!=null){ String senha = (String)this.senhas.get(username); if (senha!=null && senha.equals(this.password)){ this.loginComSucesso = true; } } return this.loginComSucesso; } public boolean commit() throws LoginException { if ( this.loginComSucesso == true ) { this.adicionaPrincipals(); //sharedState.put("javax.security.auth.principal", this.usuarioPrincipal); //sharedState.put("javax.security.auth.roles", this.perfilPrincipal); this.commitComSucesso = true; } return this.commitComSucesso; } public boolean abort() throws LoginException { if( loginComSucesso == false ) { return false; } else if( loginComSucesso == true && commitComSucesso == false ) { loginComSucesso = false; username = null; password = null; usuario = null; papel = null; } else { logout(); } return true; } @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 7 Como usar JAAS com Tomcat 6.0 public boolean logout() throws LoginException { subject.getPrincipals().remove(usuario); subject.getPrincipals().remove(papel); loginComSucesso = false; commitComSucesso = false; username = null; password = null; usuario = null; papel = null; return true; } private void tratarCallback() throws LoginException { this.callbacks = new Callback[2]; this.callbacks[0] = new NameCallback("Usuario: "); this.callbacks[1] = new PasswordCallback("Senha: ", false); try { this.callbackHandler.handle(this.callbacks); } catch(IOException ie) { throw new LoginException("Capturada IOException lançada pelo método tratarCallbacks()"); } catch(UnsupportedCallbackException uce) { throw new LoginException("Capturada UnsupportedCallbackException lançada pelo método executarCallback()"); } } private String getUsername() { String j_username = null; for (int i = 0; i < this.callbacks.length; i++) { if (this.callbacks[i] instanceof NameCallback) { j_username = ((NameCallback)this.callbacks[i]).getName(); break; } } return j_username; } private String getPassword() { String j_password = null; for ( int i = 0; i < this.callbacks.length; i++){ if ( this.callbacks[i] instanceof PasswordCallback) { j_password = new String(((PasswordCallback)this.callbacks[i]).getPassword()); break; } @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 8 Como usar JAAS com Tomcat 6.0 } return j_password; } protected void adicionaPrincipals() { this.usuario = new UsuarioImplPrincipal(this.username); this.papel = new PapelImplPrincipal("AUTENTICADO"); if (!subject.getPrincipals().contains(usuario)) { subject.getPrincipals().add(this.usuario); } if (!subject.getPrincipals().contains(papel)) { subject.getPrincipals().add(this.papel); } } } @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 9 Como usar JAAS com Tomcat 6.0 4) Códigos-fonte do aplicativo web de teste Página login.jsp <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>AppWebDemoJAAS - index.jsp</title> </head> <body> <form method="POST" action="j_security_check"> <table> <tr> <td>Usuário</td> <td><input type="text" name="j_username" /></td> </tr> <tr> <td>Senha</td> <td><input type="password" name="j_password" /></td> </tr> <tr> <td colspan="2"><input type="submit" value="Login" /></td> </tr> </table> </form> </body> </html> Página erroLogin.jsp <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <%session.invalidate();%> <h3>Usuário ou senha inválida!!!</h3> <input type="button" value="Voltar" onclick="javascript:document.location='index.jsp'" /> </body> </html> @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 10 Como usar JAAS com Tomcat 6.0 Página logout.jsp <% session.invalidate(); response.sendRedirect("index.jsp"); %> Página erro403.jsp <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <h3>Olá, <%= request.getRemoteUser() %>!!!</h3> <% if (!request.isUserInRole("AUTENTICADO")) { %> <p>Somente usuários <b>AUTENTICADOS</b> podem acessar este recurso.</p> <% } %> <%session.invalidate();%> <input type="button" value="Home" onclick="javascript:document.location='index.jsp'" /> </body> </html> Página index.jsp <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <h3>Olá, <%= request.getRemoteUser() %>!!!</h3> <p>Escolha uma opção:</p> <input type="button" value="Cadastros" onclick="javascript:document.location='cadastros.jsp'"/> <input type="button" value="Relatórios" onclick="javascript:document.location='relatorios.jsp'"/> <input type="button" value="Logout" onclick="javascript:document.location='logout.jsp'"/> </body> </html> @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 11 Como usar JAAS com Tomcat 6.0 Página cadastros.jsp <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <h3>Olá, <%= request.getRemoteUser() %>!!!</h3> <p>Escolha uma opção:</p> <input type="button" value="Home" onclick="javascript:document.location='index.jsp'"/> <input type="button" value="Relatórios" onclick="javascript:document.location='relatorios.jsp'"/> <input type="button" value="Logout" onclick="javascript:document.location='logout.jsp'"/> </body> </html> Página relatorio.jsp <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <h3>Olá, <%= request.getRemoteUser() %>!!!</h3> <p>Escolha uma opção:</p> <input type="button" value="Home" onclick="javascript:document.location='index.jsp'"/> <input type="button" value="Cadastros" onclick="javascript:document.location='cadastros.jsp'"/> <input type="button" value="Logout" onclick="javascript:document.location='logout.jsp'"/> </body> </html> @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 12 Como usar JAAS com Tomcat 6.0 5) Arquivos XML context.xml <?xml version="1.0" encoding="UTF-8"?> <Context auth="Container"> <Realm className="org.apache.catalina.realm.JAASRealm" appName="ModuloLoginJAAS" userClassNames="br.pro.passos.security.principal.UsuarioImplPrincipal" roleClassNames="br.pro.passos.security.principal.PapelImplPrincipal" /> </Context> web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>AppWebTestaJAAS</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <login-config> <auth-method>FORM</auth-method> <realm-name>default</realm-name> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page>/erroLogin.jsp</form-error-page> </form-login-config> </login-config> <security-constraint> <display-name>Política de segurança do sistema</display-name> <web-resource-collection> <web-resource-name>Protege todo o site</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>AUTENTICADO</role-name> </auth-constraint> </security-constraint> <security-role> <description>Papel requerido para acessar quaisquer recursos do aplicativo</description> <role-name>AUTENTICADO</role-name> </security-role> <error-page> <error-code>403</error-code> <location>/erro403.jsp</location> </error-page> </web-app> @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 13 Como usar JAAS com Tomcat 6.0 6) Referências consultadas Create an anonymous authentication module http://www.javaworld.com/javaworld/jw-03-2005/jw-0307-captcha.html JAAS Book http://www.jaasbook.com/ JAAS Security in Action http://www.devx.com/getHelpOn/Article/9915/1954?pf=true Java Authentication and Authorization Service (JAAS) http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASLMDevGuide.html Java Authentication and Authorization Service (JAAS) in Java 2, Standard Edition (J2SE) 1.4 http://java.sun.com/developer/technicalArticles/Security/jaasv2/ Java SE Security http://java.sun.com/javase/technologies/security/ Java security, Part 2: Authentication and authorization https://www6.software.ibm.com/developerworks/education/j-sec2/index.html Realm Configuration HOW-TO http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html Tutorial do JAAS http://guj.com.br/java.tutorial.artigo.184.1.guj @ 2008 Prof. Antonio Passos (http://blog.antoniopassos.pro.br) Página 14