sexta-feira, 31 de janeiro de 2014

JBoss JAAS LDAP Tutorial

Pessoal.. tive que configurar um ambiente JBoss EAP6/AS7 + JAAS + LDAP/AD e apanhei bastante pra conseguir, então resolvi fazer um artigo aqui no blog em formato de tutorial pra documentar o passo-a-passo e ajudar quem tiver que fazer o mesmo.

Primeiro eu segui um tutorial e não deu certo: http://middlewaremagic.com/jboss/?p=378

Não sei o motivo ainda, mas não foi de jeito nenhum.

Depois segui o tutorial do Mauricio Magnani e deu tudo certo! http://jbossdivers.wordpress.com/2012/02/12/utilizando-ldap-login-module-no-jboss-as-7-1/

No tutorial do Mauricio ele usou o openldap no linux, eu utilizei o Apache Directory Studio no Windows (tem pra linux e mac também) para criar meu servidor de LDAP/AD. Esse software é baseado no eclipse e falicita muito o trabalho com LDAP/AD, permite criar servidores, criar usuários, adicionar atributos, tudo pela interface gráfica. É lindo : ) Muito fácil de usar!

Na sua empresa/cliente talvez você já tenha um servidor de LDAP/AD, então você teria que usar ele, mas sugiro criar o server na sua máquina para testar, e depois que estiver tudo funcionando, é só apontar para o LDAP/AD da sua empresa/cliente.

* Instale o Apache Directory Studio
Baixe o Apache Directory Studio, instale, e inicie ele.
http://directory.apache.org/studio/downloads.html

* Crie Server LDAP local
Entre na aba "LDAP Servers" (Caso ela não aparece: Window > Show View > LDAP Servers)
Botão direito > New > New Server
Escolha "ApacheDS 2.0.0
Clique em "Finish"
Inicie o servidor

* Conecte-se no server criado
Entre na aba "Connections"
Botão direito > New Connection
Em "Connection Name" coloque "localhost"
Em "Hostname" coloque "localhost"
Em "Port" coloque "10389"
Clique em next
Em "Bind DN ou user" coloque "uid=admin,ou=system"
Em "Bind password" coloque "secret"
Clique em "Check Authentication", tem que funcionar : )
Clique em "Finish"

*Crie um usuário
Entre na aba "LDAP Browser"
DIT > Root DSE > ou=system" > ou=users
Botão direito em "ou=users" > New > New Entry
Clique em "Create entry from strach"
Clique em "Next"
Em "Available object classes" escolha "inetOrgPerson"
Clique em "Next"
Em "RDN", no primeiro campo, coloque "uid"
Em "RDN", no segundo campo, coloque "user1"
Clique em "Next"
Em "cn" coloque "user1"
Em "sn" coloque "user1"
Botão direito > New Attribute
Em "Attribute type" coloque "userPassword"
Clique em "Finish"
Em "Enter New Password" coloque "secret"
Clique em "OK"
Clique em "Finish"

* Crie uma role
Entre na aba "LDAP Browser"
DIT > Root DSE > ou=system" > ou=groups
Botão direito em "ou=groups" > New > New Entry
Clique em "Create entry from strach"
Clique em "Next"
Em "Available object classes" escolha "groupOfNames"
Clique em "Next"
Em "RDN", no primeiro campo, coloque "cn"
Em "RDN", no segundo campo, coloque "General"
Clique em "Next"
No campo que vai aparecer coloque "uid=user1,ou=users,ou=system"
Clique em "OK"
Clique em "Finish"



* Instale o JBoss AS 7.1.1 ou o JBoss EAP 6.2 (Testei nestas duas versões e funcionou, nas demais versão do AS7 e EAP6 deve funcionar também)
Basta baixar o zip e descompactar
A JDK precisa estar configurada no JAVA_HOME e isso precisa estar no PATH
Rode o standalone.bat ou o standalone.sh do JBoss para verificar se está funcionando.

* Configure o standalone.xml
No subsystem de security adicione as seguintes linhas dentro da tag <security-domains>

<security-domain name="ldap_security_domain">
    <authentication>
        <login-module code="LdapExtended" flag="required">
            <!-- Nao alterar -->
            <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>

            <!-- Deve ser colocado o IP e porta do LDAP -->
            <module-option name="java.naming.provider.url" value="ldap://localhost:10389"/>

            <!-- Nao alterar -->
            <module-option name="java.naming.security.authentication" value="simple"/>

            <!-- Deve ser colocado o usuário admin e senha -->
            <module-option name="bindDN" value="uid=admin,ou=system"/>
            <module-option name="bindCredential" value="secret"/>

            <!-- Deve ser colocado o diretorio onde estarao os usuarios -->
            <module-option name="baseCtxDN" value="ou=system"/>

            <!-- Deve ser colocado o atributo que representa o login do usuario -->
            <module-option name="baseFilter" value="(uid={0})"/>

            <!-- Deve ser colocado o diretorio onde estara o grupo com todos os usuarios -->
            <module-option name="rolesCtxDN" value="ou=groups,ou=system"/>

            <!-- Deve ser colocado o atributo do grupo que indica quais usuarios pertencem ao grupo -->
            <module-option name="roleFilter" value="(member={1})"/>

            <!-- Nao alterar -->
            <module-option name="roleAttributeID" value="cn"/>
            <module-option name="roleRecursion" value="-1"/>
            <module-option name="throwValidateError" value="true"/>
            <module-option name="searchScope" value="ONELEVEL_SCOPE"/>
        </login-module>
    </authentication>
</security-domain>


No subsystem de logging adicione as seguintes linhas junto com os demais loggers:

<logger category="org.jboss.security">
  <level name="TRACE"/>
</logger>

Isso serve para sair mais logs no server.log para ajudar a identificar problemas, depois que estiver tudo funcionando, altere de TRACE para WARN.

* Configure o seu projeto
No seu projeto em src/main/webapp/WEB-INF crie um arquivo chamado jboss-web.xml com o seguinte conteúdo:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <security-domain>java:/jaas/ldap_security_domain</security-domain>
</jboss-web>


No seu projeto em src/main/webapp/WEB-INF crie um arquivo chamado web.xml com o seguinte conteúdo:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
 <display-name>NomeDoProjeto</display-name>

 <!-- JSF -->
 <servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.jsf</url-pattern>
 </servlet-mapping>
 <welcome-file-list>
  <welcome-file>index.jsf</welcome-file>
 </welcome-file-list>

 <!-- Security -->
 <!-- Aqui voce mexe para dar permissoes para diferentes pastas para roles diferentes -->
 <!-- Nesse exemplo eu permito que apenas usuario da role "General" possam acessar /protected/* -->
 <security-constraint>
  <web-resource-collection>
   <web-resource-name>Protected</web-resource-name>
   <url-pattern>/protected/*</url-pattern>
   <http-method>GET</http-method>
   <http-method>POST</http-method>
  </web-resource-collection>
  <auth-constraint>
   <role-name>General</role-name>
  </auth-constraint>
 </security-constraint>

 <login-config>
  <auth-method>FORM</auth-method>
  <realm-name>LDAP</realm-name>
  <form-login-config>
   <form-login-page>/Login.jsf</form-login-page>
   <form-error-page>/Login.jsf?invalidLogin=true</form-error-page>
  </form-login-config>
 </login-config>

 <security-role>
  <role-name>General</role-name>
 </security-role>

</web-app>


No seu projeto em src/main/webapp crie um arquivo chamado index.xhtml com o seguinte conteúdo:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">

 <h:body>
  <h:outputText value="Ola mundo" />
 </h:body>
</html>


No seu projeto em src/main/webapp crie um arquivo chamado Login.xhtml com o seguinte conteúdo:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">

<h:body>
 <form id="formLogin" action="j_security_check" method="post">

  <h:outputText value="LOGIN"/>

  <br/><br/>

  <h:panelGroup rendered="#{param['invalidLogin'] == 'true'}">
   <h:outputText value="Por favor utilize credenciais autorizadas." />
   <br/><br/>
  </h:panelGroup>

  <h:outputText value="Usuario: "/>
  <h:inputText id="j_username" required="true" />

  <br/><br/>
  
  <h:outputText value="Senha: "/>
  <h:inputSecret id="j_password" feedback="false" required="true"/>

  <br/><br/>

  <h:commandButton id="access_button" type="submit" value="Entrar"/>
 </form>
</h:body>
</html>


No seu projeto em src/main/webapp crie uma pasta chamada protected.
No seu projeto em src/main/webapp/protected crie um arquivo chamado ProtectedFile.xhtml com o seguinte conteúdo:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">

 <h:body>
  <h:outputText value="Arquivo protegido." />
 </h:body>
</html>

* Teste
Reinicie o JBoss e faça deploy da sua aplicação.

Acesse http://localhost:8080/nomeDoProjeto/index.jsf e você vai conseguir acessar normalmente.
Acesse http://localhost:8080/nomeDoProjeto/protected/ProtectedFile.jsf e você vai ser redirecionado para a tela Login.jsf
Entre com o usuário user1 com a senha secret e você vai ser direcionado para tela ProtectedFile.jsf


Pronto :D
Funciona que é uma beleza!!
E mais uma vez quero agradecer ao Mauricio Magnani pelo seu blog http://jbossdivers.wordpress.com/ que me ajudou nessa atividade.

Abraços!!
Adriano Schmidt

quinta-feira, 30 de janeiro de 2014

LDAP - Failed to parse: null, disabling recursion: java.lang.NumberFormatException: null

Configurando um Ambiente JBoss 7.1.1-Final com JAAS e LDAP/AD eu tive o erro abaixo:

14:46:42,273 TRACE [org.jboss.security.auth.spi.LdapExtLoginModule] (http-localhost-127.0.0.1-8080-1) Failed to parse: null, disabling recursion: java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:454) [rt.jar:1.7.0_51]
at java.lang.Integer.parseInt(Integer.java:527) [rt.jar:1.7.0_51]
at org.jboss.security.auth.spi.LdapExtLoginModule.createLdapInitContext(LdapExtLoginModule.java:395) [picketbox-4.0.7.Final.jar:4.0.7.Final]
[...]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_51]

Para resolver, bastou adicionar a linha abaixo no login-module do subsystem security no standalone.xml

<module-option name="roleRecursion" value="-1"/>

Isso resolveu o problema!!!

Abraços!!
Adriano Schmidt