quinta-feira, 17 de julho de 2008

Usando o Spring para trabalhar com LDAP

Olá amiguinhos,

Estou construindo uma aplicação com GWT e Spring, para me ajudar na hora de administrar usuários do Squid, pelo LDAP. O LDAP é muito bom para centralizar contas de usuários e em breve minha aplicação funcionará também para PDC no Samba, contas de e-mails e tudo que usa o LDAP. Eu vou disponibilizar para a comunidade assim que terminado.

Bom, vamos lá. Não vou entrar em muitos detalhes para a configuração do LDAP, mas deixe a base principal como dc=teste,dc=com,dc=br e o usuário administrador como cn=admin,dc=teste,dc=com,dc=br e a senha como teste.

Crie um projeto no Eclipse, se você está usando Maven, melhor ainda, adicione as dependências do spring-ldap lá, senão, acesse o site www.springframework.org/ldap e faça o download da biblioteca e suas dependências, e adicione no projeto.

Crie um arquivo applicationContext.xml e adicione o seguinte:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<bean id="contextSource"
class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://localhost:389" />
<property name="base" value="dc=teste,dc=com,dc=br" />
<property name="userDn" value="cn=admin,dc=teste,dc=com,dc=br" />
<property name="password" value="teste" />
</bean>

<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>

<bean id="userDao" class="br.org.teste.server.UserLdapDao">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>

</beans>


Beleza, a parte do Spring já está configurada, agora só fazermos um DAO e um POJO para trabalharmos.

Bom, se você for trabalhar com o objeto do LDAP inetOrgPerson, você pode fazer a seguinte estrutura na classe POJO:

public class UserLdap {

private String fullName;
private String lastName;
private String uid;
private String givenName;
private String userPassword;
private String description;
private String mail;

public String getFullName() {
return fullName;
}

public void setFullName(String fullName) {
this.fullName = fullName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getUserId() {
return uid;
}

public void setUserId(String userId) {
this.uid = userId;
}

public void setGivenName(String givenName) {
this.givenName = givenName;
}

public String getGivenName() {
return givenName;
}

public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}

public Object getUserPassword() {
return userPassword;
}

public void setDescription(String description) {
this.description = description;
}

public String getDescription() {
return description;
}

public void setMail(String mail) {
this.mail = mail;
}

public String getMail() {
return mail;
}
}


Agora vamos fazer a classe DAO. Vou mostrar a classe que eu fiz para as minhas necessidades, se você quiser se aprofundar mais, acesse o site http://static.springframework.org/spring-ldap/docs/1.2.1/reference/

O difícil é entender o Spring, depois que você entende como funciona, a documentação no site se torna muito mais fácil.

Então vamos lá, crie a classe DAO com o seguinte conteúdo:

public class UserLdapDao {


private LdapTemplate ldapTemplate;


/**
* Define um LdapTemplate do Spring
* @param ldapTemplate Define um objeto LdapTemplate
* @author anderson
* @version 1.0
*/
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}


/**
* Metodo que compila um DN
* @param user Define um objeto UserLdap
* @return Retorna um objeto Name
*/
public Name buildDn(UserLdap user) {
DistinguishedName dn = new DistinguishedName();
dn.add("cn", user.getFullName());

return dn;
}


/**
* Metodo que insere uma nova entrada no Ldap
* @param user Define um objeto UserLdap
* @author anderson
* @version 1.0
*/
public void create(UserLdap user) {
Name dn = buildDn(user);
ldapTemplate.bind(dn, null, buildAttributes(user));
}


/**
* Metodo que remove uma entrada no Ldap
* @param user Define um objeto UserLdap
* @author anderson
* @version 1.0
*/
public void delete(UserLdap user) {
Name dn = buildDn(user);
ldapTemplate.unbind(dn);
}


/**
* Metodo que atualiza um registro no Ldap
* @param user Define um objeto UserLdap
* @author anderson
* @version 1.0
*/
public void update(UserLdap user) {
Name dn = buildDn(user);
ldapTemplate.rebind(dn, null, buildAttributes(user));
}


/**
* Metodo que compila os atributos para ser inserido, removido ou atualizado
* @param user Define um objeto UserLdap
* @return Retorna um objeto Attributes
* @author anderson
* @version 1.0
*/
private Attributes buildAttributes(UserLdap user) {
Attributes attrs = new BasicAttributes();
BasicAttribute ocattr = new BasicAttribute("objectclass");

ocattr.add("top");
ocattr.add("inetOrgPerson");

attrs.put(ocattr);
attrs.put("sn", user.getLastName());
attrs.put("givenName", user.getGivenName());
attrs.put("uid", user.getUserId());
attrs.put("userPassword", user.getUserPassword());
attrs.put("description", user.getDescription());
attrs.put("mail", user.getMail());

return attrs;
}


/**
* Pega todo os registros do Ldap da classe inetOrgPerson
* @return Retorna uma lista de resultados
* @author anderson
* @version 1.0
*/
@SuppressWarnings("unchecked")
public List getAll() {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass","inetOrgPerson"));
filter.and(new EqualsFilter("objectclass","person"));

return ldapTemplate.search("",
filter.encode(), new PersonAttributesMapper());
}


/**
* Pesquisa injetando os resultados no objeto UserLdao
* @param uid Define um uid para a consulta (Ex.: uid=teste)
* @return Retorna um objeto UserLdap
* @author anderson
* @version 1.0
*/
@SuppressWarnings("unchecked")
public List find(String uid) {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass","inetOrgPerson"));
filter.and(new WhitespaceWildcardsFilter("uid",uid));

return ldapTemplate.search("",
filter.encode(), new PersonAttributesMapper());
}


/**
* Classe interna para atribuir os valores para um pojo UserLdap
* @author anderson
* @version 1.0
*/
private class PersonAttributesMapper implements AttributesMapper {

public Object mapFromAttributes(Attributes attributes)
throws NamingException {

byte[] senha = (byte[])attributes.get("userPassword").get();

UserLdap user = new UserLdap();
user.setFullName((String)attributes.get("cn").get());
user.setLastName((String)attributes.get("sn").get());
user.setUserId((String)attributes.get("uid").get());
user.setGivenName((String)attributes.get("givenName").get());
user.setMail((String)attributes.get("mail").get());
user.setUserPassword(new String(senha));
user.setDescription((String)attributes.get("description").get());

return user;
}

}
}


O método buildAttributes e a classe interna PersonAttributesMapper são os mais importantes e que fazem o negócio funcionar. O método buildAttributes compila os atributos do objeto inetOrgPerson para a base LDAP, você pode definir o objectclass e seus atributos, quais você quiser. A classe interna PersonAttributesMapper retorna no seu POJO, os valores da pesquisa que você solicitou.

E para chamar o DAO, é simples. Na classe que você precisar, basta fazer o seguinte:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" });
UserLdapDao userDao = (UserLdapDao) ctx.getBean("userDao");
List resultado = userDao.find("uid=teste");


O Spring é mil e uma utilidades, dá para trabalhar só com ele tranquilamente em seu projeto. Estou gostando de usar ele e a cada dia aprendo alguma coisa nova.

Enjoy...

1 comentários:

Anônimo disse...

Muito bom seu mini tutorial :) sou estudante de desenvolvimento e analise, em medianeira, e estou trabalhando com ldap no momento, e seu tutorial foi de grande ajuda :D
boa sorte nos seus trabalhos