Técnico

Alterando a senha de um usuário do Active Directory usando Java

Quem já manipulou o Active Directory usando Java sabe que é muito fácil e que encontrarmos diversos tutoriais e posts na Internet sobre este assunto. Agora, se quisermos alterar a senha de um usuário do AD, as referências já não são muito boas. Os grandes problemas para se alterar a senha de um usuário do AD são as restrições de segurança e as configurações que temos que fazer nele para que tudo funcione.

Toda a conexão feita com o AD é via o protocolo ldap, ou seja, para acessarmos o AD temos que acessar ldap://x.x.x.x:389, onde x.x.x.x é o IP e 389 a porta padrão de acesso. No entanto, para se alterar a senha, é necessário usar uma conexão segura usando um certificado de segurança gerado no servidor do AD. Dessa forma, teremos que acessar ldap://x.x.x.x:636.

Primeiramente, temos que gerar o certificado de segurança e posteriormente temos que importar este certificado para nossa VM. Neste link temos os passos para se fazer isso. Veja que para importar o certificado temos que usar um comando parecido com sudo keytool -import -keystore ./jre/lib/security/cacerts -file server-certificate.crt, dependendo do seu sistema operacional e onde está o seu certificado (.crt).

Nas pesquisas que fizemos, usamos alguns softwares que nos auxiliaram. Usamos o Portcle (aplicação Java para gerenciar certificados) para ter certeza que o certificado estava importado no meu “cacerts” e uma outra aplicação Java para fazer browse no AD, o JXplorer. O JXplorer é importante para acharmos o DN (Distinguished Name) de um usuário para podermos fazer os testes.

Por fim, o que tínhamos que fazer era permitir que um usuário ou um grupo de usuários tivesse o privilégio de trocar a senha de qualquer usuário. Basta seguir este artigo para conseguir isso.

Abaixo temos um exemplo de uma classe simples que possui um método para trocar a senha e outro método para dar “unlock” do usuário.

Classe de teste:
[cc_java]
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.naming.NamingException;
import javax.naming.ldap.LdapContext;

import br.com..utils.ad.ADUtil;

public class test {

/**
* @param args
* @throws NamingException
* @throws IOException
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws NamingException, UnsupportedEncodingException, IOException {
// TODO Auto-generated method stub

ADUtil adUtil = new ADUtil();

LdapContext context = adUtil.createUserContext(
“CN=modifyad, OU=domain, DC=com, DC=com, DC=br”,
“senha”,
“/Library/Java/Home/lib/security/cacerts”,
“ldap://x.x.x.x:636”);

adUtil.unlockAccount(context,
“CN=usuario, OU=redspark, DC=domain, DC=com, DC=br”);
adUtil.changePassword(context,
“CN=usuario, OU=redspark, DC=domain, DC=com, DC=br”,
“nova-senha”);

}

}
[/cc_java]

Classe Java:

[cc_java]
package br.com..utils.ad;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

/**
* @author rafael.martinelli (rafael.martinelli@redspark.io)
*
*/
public class ADUtil {

/**
* Método que retorna o contexto de conexão do usuário
* com poder de troca de senha. Deve-se registrar o certificado
* do AD na VM Java
*
* @param adminCN Ex: “CN=modifyad, OU=domain, DC=com, DC=com, DC=br”
* @param adminPassword
* @param keystore Ex: “/Library/Java/Home/lib/security/cacerts”
* @param ldapUrl Ex: “ldap://x.x.x.x:636”
* @return javax.naming.ldap.LdapContext
* @throws NamingException
*/
public LdapContext createUserContext(String adminDN,

String adminPassword, String keystore,
String ldapUrl) throws NamingException {

Hashtable env = new Hashtable();

System.setProperty(“javax.net.ssl.trustStore”, keystore);

env.put(Context.INITIAL_CONTEXT_FACTORY, “com.sun.jndi.ldap.LdapCtxFactory”);
env.put(Context.SECURITY_AUTHENTICATION, “simple”);
env.put(Context.SECURITY_PRINCIPAL, adminDN);
env.put(Context.SECURITY_CREDENTIALS, adminPassword);
env.put(Context.SECURITY_PROTOCOL, “ssl”); // para poder modificar password y grupos del usuario.
env.put(Context.PROVIDER_URL, ldapUrl);
env.put(Context.REFERRAL, “ignore”);

return new InitialLdapContext(env, null);

}

/**
* Troca a senha de um usuário no AD
*
* @param ldapContext
* @param userCN Ex: “CN=usuario, OU=redspark, DC=domain, DC=com, DC=br”
* @param newPassword
* @throws NamingException
* @throws UnsupportedEncodingException
* @throws IOException
*/
public void changePassword(LdapContext ldapContext, String userCN, String newPassword) throws NamingException, UnsupportedEncodingException, IOException {

modifyAdAttribute(ldapContext, userCN, “unicodePwd”, getPassword(newPassword));
System.out.println(“Password changed for ” + userCN);
}

/**
* Destrava um usuário do AD
*
* @param ldapContext
* @param userDN Ex: “CN=usuario, OU=redspark, DC=domain, DC=com, DC=br”
* @param newPassword
* @throws NamingException
* @throws UnsupportedEncodingException
* @throws IOException
*/
public void unlockAccount(LdapContext ldapContext, String userDN) throws NamingException, UnsupportedEncodingException, IOException {

modifyAdAttribute(ldapContext, userDN, “lockoutTime”, “0”);
System.out.println(“Account ” + userDN + ” unlocked”);

}

/**
* Modifica um atributo de um usuário/group no AD
*
* @param ldapContext
* @param userCN Ex: “CN=usuario, OU=redspark, DC=domain, DC=com, DC=br”
* @param attribute Ex: “unicodePwd”
* @param value Valor do attributo
* @throws NamingException
*/
private void modifyAdAttribute(LdapContext ldapContext, String userCN, String attribute, Object value) throws NamingException{
ModificationItem[] modificationItem = new ModificationItem[1];
modificationItem[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
new BasicAttribute(attribute, value));
ldapContext.modifyAttributes(userCN, modificationItem);
}

/**
* Gera o password no formato binário e com aspas, respeitando
* o que o AD precisa
*
* @param password
* @return
* @throws UnsupportedEncodingException
*/
private static byte[] getPassword(String password) throws UnsupportedEncodingException{
String newQuotedPassword = “”” + password + “””;
return newQuotedPassword.getBytes(“UTF-16LE”);
}

}
[/cc_java]

4 Comments

  • Warley disse:

    Amigo em:

    Hashtable env = new Hashtable();

    Tá dando erro.
    Vc sabe o que pode ser?

    Obrigado.

  • Tiafo disse:

    Warley, veja se você importou corretamente:

    import java.util.Hashtable;

  • Fabio Kaz disse:

    E como se faz para alterar o grupo de um usuário?

    Por exemplo: Existem os seguintes grupos Assistente e Gerente. Como se faz para tirar um usuário do grupo Assistente e colocá-lo no grupo Gerente e vice-versa?

    Parabéns pelo post sobre a senha. Fiz e deu certo. 😉

    Obrigado,

  • Wallison Oliveira disse:

    Já na hora da importação está dando erro:

    C:Program FilesJavajdk1.7.0_03>keytool -import -keystore .jrelibsecurityc
    acerts -file server-certificate.crt
    Informe a senha da ßrea de armazenamento de chaves:
    erro de keytool: java.io.FileNotFoundException: server-certificate.crt (O sistem
    a nÒo pode encontrar o arquivo especificado)

    Sabe me dizer o que pode ser?

    Obrigado.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Compartilhe isso: