LDAP addUser com Java

4 respostas
H

Olá caros,

Estou tentando desenvolver um sistema Java para controle do LDAP da instituição onde trabalho.
Os códigos para alteração de senha, exclusão de usuários, verificação de autenticidade eu já tenho todos prontos e funcionando corretamente.

Meu problema está na inserção de usuários. Tirando um ldiff do LDAP, eu vi que são criadas várias informações automaticamente, por exemplo, se eu crio o usuário convidado.02 com o seguinte código no meu server:

ldapadduser convidado.02 aluno 4302

O LDAP já cria o homeDirectory do usuário e depois de cadastrado a senha, ele me gera no ldiff as seguintes informações do usuário:

dn: uid=convidado.02,ou=Users,dc=nodomain
objectClass: account
objectClass: posixAccount
cn: convidado.02
uid: convidado.02
uidNumber: 4302
gidNumber: 10000
homeDirectory: /home/users/convidado.02
loginShell: /bin/bash
gecos: convidado.02
description: User account
userPassword:: e01ENX05RWNzV2doSi9UbTR3eG00SjVVWW1BPT0=

Pra fazer o cadastro em java, eu tive de criar todas as linhas do ldiff como atributos para inserção, e ainda assim, não foi possível criar o homeDirectory.
Segue o código de teste q eu utilizei:

import java.util.Hashtable;
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

public class AddUserLdap {

    public static void main(String args[]) {

        //Autenticação para alteração de senha precisa ser feita com o Admin do LDAP
        String username = "admin";
        String password = "senha";
        String atributosConexao = "cn=" + username + ",dc=nodomain";

        Hashtable authEnv = new Hashtable(11);

        authEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        authEnv.put(Context.PROVIDER_URL, "ldap://192.168.100.10:389");
        authEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
        authEnv.put(Context.SECURITY_PRINCIPAL, atributosConexao);
        authEnv.put(Context.SECURITY_CREDENTIALS, password);

        try {
            DirContext authContext = new InitialDirContext(authEnv);
            System.out.println("Autenticado!");


            Attribute objectClass = new BasicAttribute("objectClass"); //Adding Object Classes    
            objectClass.add("account");
            objectClass.add("posixAccount");

            String userAdd = "teste.java";
            String uidNumber = "6000";
            String gidNumber = "10000";
            String homeDirectory = "/home/users/" + userAdd;
            String loginShell = "/bin/bash";
            String description = "User account";
            String userPassword = "1234";

            BasicAttributes myAttrs = new BasicAttributes(true);
            myAttrs.put(objectClass);

            myAttrs.put("cn", userAdd);
            myAttrs.put("uid", userAdd);
            myAttrs.put("uidNumber", uidNumber);
            myAttrs.put("gidNumber", gidNumber);
            myAttrs.put("homeDirectory", homeDirectory);
            myAttrs.put("loginShell", loginShell);
            myAttrs.put("gecos", userAdd);
            myAttrs.put("description", description);
            myAttrs.put("userPassword", userPassword);

            InitialDirContext iniDirContext = (InitialDirContext) authContext;
            String groupDN = "ou=Users,dc=nodomain";
            authContext.bind("uid=" + userAdd + "," + groupDN, iniDirContext, myAttrs);
            System.out.println("Adicionado com êxito! ");
            authContext.close();

        } catch (AuthenticationException authEx) {
            System.out.println("Erro na autenticação! ");
            System.out.println(authEx.getMessage());
        } catch (NamingException namEx) {
            System.out.println("Problemas na conexão! ");
            System.out.println(namEx.getMessage());
        }
    }
}

Creio que para fazer a inserção de um novo usuário, não deveria ser necessário passar todas essas informações, o comando ldapadduser já cria tudo pra mim (então pq o bind não cria?), acho que a única coisa que eu deveria passar é a árvore do meu LDAP (cn,ou), nome de usuário e senha criptografada.
Alguém sabe como resolver isso, ou como ao menos fazer com que o LDAP crie pra mim o HomeDirectory do usuário recém criado?

Fico no aguardo e agradeço qualquer ajuda.

4 Respostas

E

Ora pois pois, você reescreveu o comando ldapadduser :slight_smile: - mas deve faltar alguma coisinha para ele não conseguir criar o home directory, como você percebeu :slight_smile:

Um exemplo de ldapadduser que achei na Internet:

#!/usr/bin/perl -w
# ------------------------------------------------------------
# script:  ldapadduser.pl
# Author:  Brad Marshall ([email removido])
# Date:    20000203
#
# Purpose: Adds a user to LDAP
#
# Copyright (c) 2000 Plugged In Software Pty Ltd.  All rights reserved.

# TODO
# x Check username ( >= 8 chars, all alpha)
# x Check uid number (not negative, less than 65536, etc)
# x Handle ^C's etc gracefully
# x Check automatically generated userid / groupid
# x Check username / uid not already used
#   Get manager's password & bind as manager
#   Display information, ask if ok before adding

# Modules
use strict;
use Net::LDAP;
use Getopt::Std;
use Term::ReadKey;

use vars qw($opt_c $opt_d $opt_g $opt_G $opt_s $opt_u);

# Variables
my($username);
my($homedirectory);
my($gid);
my($gidnumber);
my($gidname);
my($groups);
my($loginshell);
my($uidnumber);
my($uid);
my($cn);
my($gecos);
my($dn);
my($result);
my($gidref);

my($root) = "dc=pisoftware,dc=com";
my($host) = "ldap.staff.plugged.com.au";
my(@objectclass) = [ 'account', 'posixAccount', 'top' ];
my($manager) = "cn=Manager,$root";
my $exception = 0;

# Signal handlers
$SIG{'INT'} = $SIG{'QUIT'} = $SIG{'HUP'} = sub { $exception=1; };

# useradd [-c comment] [-d home_dir]
#              [-e expire_date] [-f inactive_time]
#              [-g initial_group] [-G group[,...]]
#              [-m [-k skeleton_dir] | -M] [-p passwd]
#              [-s shell] [-u uid [ -o]] [-n] [-r] login

# Handle the command line options
getopts('c:d:g:G:s:u:');

if (! $ARGV[0]) {
	print "$0: $0 [-c comment] [-d directory] [-g default group] [-G groups, ..]\n\t[-s shell] [-u uid] username\n";
	exit 1;
}

if ($ARGV[0]) {
	$uid = $ARGV[0];
} else {
	die "Sorry, you must specify a login";
}
if ($opt_c) {
	$cn = $opt_c;
} else {
	$cn = "Plugged In Linux User";
}
$gecos = $cn;
if ($opt_d) {
	$homedirectory = $opt_d;
} else {
	$homedirectory = "/mnt/home/" . $uid;
}
if ($opt_g) {
	$gid = $opt_g;
	$gidref = &findgid($gid);

	$gidnumber = $gidref->[0];
	$gidname = $gidref->[1];

	print "number = $gidnumber, name = $gidname\n";
} else {
	die "Sorry, you must specify a default group for this user";
}
if ($opt_G) {
	$groups = $opt_G;
	print "\$groups = $groups\n";
}
if ($opt_s) {
	$loginshell = $opt_s;
} else {
	$loginshell = "/bin/bash";
}
if ($opt_u) {
	$uidnumber = $opt_u;
} else {
	# find next available uid
	$uidnumber = &finduid;

	print "uid = $uidnumber\n";
}

# Check the uid is valid
&checkuid;

print "Please enter LDAP Managers password: ";

ReadMode 'noecho';
my $password = ReadLine 0;
chomp $password;
ReadMode 'normal';
print "\n";

print "cn $cn\n";
print "uid $uid\n";
print "objectClass @objectclass\n";
print "uidNumber $uidnumber\n";
print "gidNumber $gidnumber\n";
print "loginShell $loginshell\n";
print "homeDirectory $homedirectory\n";
print "gecos $gecos\n";

# Add the user to all the groups in $groups
&addgroups;
#exit 0;

#dn: uid=bmarshal,ou=People,dc=pisoftware,dc=com
#uid: bmarshal
#cn: Brad Marshall
#objectClass: account
#objectClass: posixAccount
#objectClass: top
#userPassword: {crypt}j26bYFB8xQYLE
#loginShell: /bin/bash
#uidNumber: 500
#gidNumber: 120
#homeDirectory: /mnt/home/bmarshal
#gecos: Brad Marshall,,,,

$dn = "cn=".$uid.",ou=People,". $root;
#print "\$dn = $dn\n";

my($ldap) = Net::LDAP->new($host) or die "Can't bind to ldap: $!\n";

# Bind to ldap as manager
$ldap->bind(
			dn       => $manager,
			password => $password,
		);

if ($exception) {
	die "Caught a signal";
} else {
	#print "\$dn = $dn\n";
	# Actually add the ldap entry
	$result = $ldap->add (
       dn   => $dn,
       attr => [ 'cn'            => $cn,
				 'uid'           => $uid,
                 'objectClass'   => @objectclass,
				 'uidNumber'     => $uidnumber,
				 'gidNumber'     => $gidnumber,
				 'loginShell'    => $loginshell,
				 'homeDirectory' => $homedirectory,
#				 'gecos'         => $gecos,
			   ]
	);
	$result->code && warn "failed to add entry: ", $result->error;
}

# Subroutines

my(%results);

sub finduid {
	# Find the last uid

	my($entry);
	my(@uids);
	my($lastuid);

	my($ldap) = Net::LDAP->new($host) or die "Can't bind to ldap: $!\n";

	$ldap->bind;

	# Search for all accounts
	my($mesg) = $ldap->search( base => $root,
                               filter => '(objectclass=account)'
                             );

	$mesg->code && die $mesg->error;

	# loop thru all the accounts
	foreach $entry ($mesg->entries) {
		# Grab the uid name and number
        my($tmpcn) = $entry->get('uid');
        my($tmpnum) = $entry->get('uidnumber');
		# .. then stuff it into a hash
        $results{$tmpcn} = $tmpnum;
    }

	# Sort all the uids
	@uids = sort bygroup keys %results;
	# Get the last uid number and add one
	$lastuid = $results{$uids[$#uids]} + 1;

	return $lastuid;
}

sub bygroup {
        $results{$a} <=> $results{$b}
}

sub findgid {
	# Find the gid number and gid name

	my($gid) = shift;
	my($gidname, $gidnumber);
	my($entry);
	my($gidsref);
	my(@gids);

	my($ldap) = Net::LDAP->new($host) or die "Can't bind to ldap: $!\n";

	$ldap->bind;

	# Search for all the groups
	my($mesg) = $ldap->search( base => $root,
                               filter => '(objectclass=posixGroup)'
                             );

	$mesg->code && die $mesg->error;

	# Loop thru all the groups
	foreach $entry ($mesg->entries) {
		# If the gid is a number..
		if ($gid =~ /\d{1,3}/) {
			#print "\$gid is a number\n";
			# If the gid is the same as this group's number..
			if ($gid == $entry->get('gidnumber')->[0]) {
				# Get the gid number and cn
				$gidnumber = $entry->get('gidnumber')->[0];
				$gidname = $entry->get('cn')->[0];
				@gids = ($gidnumber, $gidname);
				$gidsref = \@gids;
				# and return it
				return $gidsref;
			}
		} else {
		#	print "\$gid is not a number\n";
			#print $gid, $entry->get('cn'),"\n";
			# if the gid is the same as this group's name
			if ($gid eq $entry->get('cn')->[0]) {
				# Get the gid number and cn
				$gidnumber = $entry->get('gidnumber')->[0];
				$gidname = $entry->get('cn')->[0];
				@gids = ($gidnumber, $gidname);
				$gidsref = \@gids;
				# and return it
				return $gidsref;
			}
		}
	}
	#print "no match\n";
}

sub addgroups {
	my(@group);
	my($gidsref);
	my($groupdn);
	my($grouplist);

	if ($groups) {
		$grouplist = $groups . " " . $gidname;
	} else {
		$grouplist = $gidname;
	}

	if ($grouplist) {
		my($groupldap) = Net::LDAP->new($host) or die "Can't bind to ldap: $!\n";

		print "\$manager = $manager, \$password = $password\n";

		$groupldap->bind(
			dn       => $manager,
			password => $password,
		);

		print "groups = $grouplist\n";
		@group = split(/ /, $grouplist);
		my($group);
		foreach $group (@group) {
			$gidsref = &findgid($group);
			#print $gidsref->[1],"\n";
			my($tmp) = $gidsref->[1];
			$groupdn = "cn=$tmp,ou=Group,$root";
			print "\$groupdn = $groupdn, \$uid = $uid\n";
			$groupldap->modify( $groupdn, add => { memberuid => $uid } );
		}
	}
}

sub checkuid {
	if ($uid !~ /[a-z]{3,8}/) {
		die "Sorry, username must consist solely of letters and be between 3 and 8 characters.";
	}
	if (($uidnumber > 65535) || ($uidnumber < 0)) {
		die "Sorry, uid number must be less than 65535 and greater than 0";
	}

	my($ldap) = Net::LDAP->new($host) or die "Can't bind to ldap: $!\n";

	$ldap->bind;

	my($mesg) = $ldap->search( base => $root,
                               filter => '(objectclass=account)'
                             );

	$mesg->code && die $mesg->error;

	my($entry);
	foreach $entry ($mesg->entries) {
		my($tmpcn) = $entry->get('uid')->[0];
		my($tmpuidnumber) = $entry->get('uidnumber')->[0];
		if ($tmpcn eq $uid) {
			die "Sorry, username $uid already exists";
		}
		if ($tmpuidnumber == $uidnumber) {
			die "Sorry, userid $uidnumber already exists";
		}
	}
}
H

Olá entanglement, obrigado pela resposta.

Então, viu só como tive de reescrever todo o ldap?
Só que se eu adiciono somente o usuário, grupo e senha, o ldiff não cria todos os outros atributos.
Dó código que vc postou, dei uma passada rápida por ele e está bem semelhante a ideia do que eu postei criando o homeDirectory na mão, só que ainda assim não funciona.

De acordo com um amigo meu, quando eu faço o comando ldapadduser, este chama um outro script responsável pela criação do diretório (mkdir) e alteração de permissões (chmod).
No meu código e nesse que vc me passou eu acho que o problema vai ser o mesmo, apesar de estar mapeado o homeDirectory como visto no ldiff, o diretório mesmo não foi criado.

Aqui as máquinas fazem login com o usuário do ldap com área de trabalho remota. O acesso a web, é feito com o proxy autenticado no ldap. Depois de criar o usuário com esse código, a autenticação pra navegar na web funciona, só que o login nas máquinas é barrado pelo fato de não existir o homeDirectory.

Agradeço a ajuda!

E

A criação do diretório vai requerer “sudo” já que é necessário ter poderes administrativos para criar um diretório e mudar as suas permissões.
É por isso que ele tem de chamar um script que faz isso :slight_smile:

H

Isso mesmo, estava pensando aqui que o jeito vai ser eu criar um serviço pra rodar via System.exec o próprio ldapaddUser no servidor, aí o processo de criação vai ser automático e eu não preciso me preocupar em como vc mesmo disse, reescrever todo ldap a cada alteração que venha ocorrer na base.
Muito obrigado :stuck_out_tongue:

Criado 31 de janeiro de 2013
Ultima resposta 31 de jan. de 2013
Respostas 4
Participantes 2