Archived
1
0
This repository has been archived on 2021-10-08. You can view files and clone it, but cannot push or open issues or pull requests.
ACU/ACU/LDAP.pm

382 lines
7.6 KiB
Perl
Raw Permalink Normal View History

2013-09-02 17:13:12 +00:00
#! /usr/bin/env perl
package LDAP;
use v5.10.1;
use strict;
use warnings;
2013-09-28 21:11:46 +00:00
use Carp;
2013-09-02 17:13:12 +00:00
use Net::LDAPS;
2013-10-28 14:11:04 +00:00
use Net::LDAP::Filter;
2013-09-02 17:13:12 +00:00
use Net::LDAP::Util qw(ldap_error_text);
use ACU::Password;
use ACU::Right;
2013-09-03 05:20:58 +00:00
use ACU::Log;
2013-09-02 17:13:12 +00:00
2013-10-28 14:11:04 +00:00
use constant {
BASE_DN => "dc=acu,dc=epita,dc=fr",
YEAR_DN => "cn=year,dc=acu,dc=epita,dc=fr",
};
2013-09-02 18:43:18 +00:00
## Connection functions
our $ldaphost = "ldap.acu.epita.fr";
2013-10-28 14:11:04 +00:00
our $binddn = "cn=intra," . BASE_DN;
2013-09-02 18:43:18 +00:00
my $bindsecret = "";
sub ldap_get_password
{
2013-09-16 17:00:37 +00:00
if (`hostname` eq "apl") {
return Password::get_password "/home/2014/mercie_d/.secret_ldap";
} else {
return Password::get_password "/home/intradmin/.secret_ldap";
}
2013-09-02 18:43:18 +00:00
}
our $secret_search = \&ldap_get_password;
2013-09-02 17:13:12 +00:00
sub ldap_connect()
{
2013-09-03 05:20:58 +00:00
if (!$bindsecret) {
2013-09-02 18:43:18 +00:00
$bindsecret = $secret_search->();
}
2013-09-02 17:13:12 +00:00
my $ldap = Net::LDAPS->new($ldaphost) or die ("$@");
my $mesg = $ldap->bind($binddn, password => $bindsecret) or die ("$@");
2013-09-04 00:56:29 +00:00
log(DEBUG, "Connect to LDAP with $binddn");
2013-09-03 05:20:58 +00:00
2013-10-28 14:11:04 +00:00
croak ldap_error_text($mesg->code) if ($mesg->code);
2013-09-02 17:13:12 +00:00
return $ldap;
}
sub ldap_connect_anon()
{
my $ldap = Net::LDAPS->new($ldaphost) or die ("$@");
my $mesg = $ldap->bind or die ("$@");
2013-09-04 00:56:29 +00:00
log(DEBUG, "Connect to LDAP anonymously");
2013-09-03 05:20:58 +00:00
2013-10-28 14:11:04 +00:00
croak ldap_error_text($mesg->code) if ($mesg->code);
2013-09-02 17:13:12 +00:00
return $ldap;
}
2013-09-02 18:43:18 +00:00
## High end functions
2013-09-02 17:13:12 +00:00
sub add_group($$$;$)
2013-09-02 17:13:12 +00:00
{
my $ldap = shift // ldap_connect();
2013-09-02 17:13:12 +00:00
my $cn = shift;
my $year = shift // get_year();
2013-09-02 17:13:12 +00:00
my $ou = shift // "intra"; # expected roles or intra
2013-10-28 14:11:04 +00:00
my $dn = "cn=$cn,ou=$year,ou=$ou,ou=groups," . BASE_DN;
2013-09-02 17:13:12 +00:00
2013-09-04 00:56:29 +00:00
log(DEBUG, "Add group $dn");
2013-09-03 05:20:58 +00:00
2013-09-02 17:13:12 +00:00
my $mesg = $ldap->add( $dn,
attrs => [
2013-09-02 18:43:18 +00:00
objectclass => "intraGroup",
2013-09-02 17:13:12 +00:00
cn => $cn,
]
);
2013-09-04 00:56:29 +00:00
if ($mesg->code != 0) { log(WARN, $mesg->error); return 0; }
2013-09-02 17:13:12 +00:00
return $dn;
}
2013-09-28 16:52:38 +00:00
sub get_year(;$)
2013-09-02 17:13:12 +00:00
{
2013-09-28 16:52:38 +00:00
my $ldap = shift // ldap_connect_anon();
2013-09-02 17:13:12 +00:00
2013-10-28 14:11:04 +00:00
return get_attribute($ldap, YEAR_DN, "year");
2013-09-28 16:52:38 +00:00
}
2013-09-02 17:13:12 +00:00
2013-09-28 16:52:38 +00:00
sub get_rights($)
{
my $login = shift;
my @rights;
my $ldap = ldap_connect_anon();
2013-09-03 05:20:58 +00:00
2013-09-02 17:13:12 +00:00
my $mesg = $ldap->search( # search
2013-10-28 14:11:04 +00:00
base => "ou=roles,ou=groups," . BASE_DN,
filter => Net::LDAP::Filter->new("&(memberUid=$login)(objectClass=intraGroup)"),
2013-09-28 16:52:38 +00:00
attrs => [ 'intraRight' ],
2013-09-02 17:13:12 +00:00
scope => "sub"
);
2013-09-28 16:52:38 +00:00
if ($mesg->code != 0) { die $mesg->error; }
for my $entry ($mesg->entries)
{
for my $r ($entry->get_value('intraRight'))
{
if ($r =~ /^!(.*)$/) {
@rights = grep { $r ne $_ } @rights;
}
else {
push @rights, Right->new($r);
}
}
}
2013-09-02 17:13:12 +00:00
2013-09-28 16:52:38 +00:00
$mesg = $ldap->search( # search
2013-10-28 14:11:04 +00:00
base => "ou=intra,ou=groups," . BASE_DN,
filter => Net::LDAP::Filter->new("&(memberUid=$login)(objectClass=intraGroup)"),
2013-09-28 16:52:38 +00:00
attrs => [ 'intraRight' ],
scope => "sub"
);
if ($mesg->code != 0) { die $mesg->error; }
if ($mesg->count != 1) { die "User $login not found or multiple presence"; }
for my $entry ($mesg->entries)
{
for my $r ($entry->get_value('intraRight')) {
push @rights, Right->new($r);
}
}
$mesg = $ldap->search( # search
2013-10-28 14:11:04 +00:00
base => "ou=users," . BASE_DN,
filter => Net::LDAP::Filter->new("&(uid=$login)(objectClass=intraAccount)"),
2013-09-28 16:52:38 +00:00
attrs => [ 'intraRight' ],
scope => "sub"
);
if ($mesg->code != 0) { die $mesg->error; }
if ($mesg->count != 1) { die "User $login not found or multiple presence"; }
for my $r ($mesg->entry(0)->get_value('intraRight')) {
push @rights, Right->new($r);
}
$ldap->unbind or die ("couldn't disconnect correctly");
return @rights;
2013-09-02 17:13:12 +00:00
}
2013-09-28 16:52:38 +00:00
sub has_right($$)
2013-09-02 17:13:12 +00:00
{
2013-09-28 16:52:38 +00:00
my $login = shift;
my $right = shift;
2013-09-02 17:13:12 +00:00
2013-09-28 16:52:38 +00:00
my $ok = 0;
for my $r (get_rights($login))
{
if ($r->{right} eq $right)
{
return 0 if ($r->{negate});
$ok = $r;
}
}
return $ok;
2013-09-02 18:43:18 +00:00
}
## Low level functions
sub get_dn($$@)
{
my $ldap = shift // ldap_connect();
my $dn = shift;
2013-09-02 17:13:12 +00:00
2013-11-15 11:40:29 +00:00
my $base = BASE_DN;
$dn = "$dn," . BASE_DN if ($dn !~ /$base$/);
2013-09-02 17:13:12 +00:00
my $mesg = $ldap->search( # search
base => "$dn",
2013-10-28 14:11:04 +00:00
filter => Net::LDAP::Filter->new("(objectClass=*)"),
2013-09-12 11:06:29 +00:00
attrs => \@_,
scope => "base"
2013-09-02 17:13:12 +00:00
);
return undef if ($mesg->code != 0);
2013-09-04 00:56:29 +00:00
if ($mesg->count != 1) { log(WARN, "$dn not found or multiple entries match"); return undef; }
2013-09-02 17:13:12 +00:00
2013-09-02 18:43:18 +00:00
return $mesg->entry(0);
}
sub add_attribute($$$@)
{
my $ldap = shift // ldap_connect();
my $dn = shift;
my $what = shift;
2013-09-02 17:13:12 +00:00
2013-09-02 18:43:18 +00:00
my $mod = 0;
2013-09-02 17:13:12 +00:00
2013-09-02 18:43:18 +00:00
my $entry = get_dn($ldap, $dn, $what);
2013-09-09 11:43:35 +00:00
if (!$entry) {
log(WARN, "Trying to add attributes ($what) to an unexisting entry: $dn");
log(TRACE, @_);
return undef;
}
2013-09-02 18:43:18 +00:00
my @data = $entry->get_value($what);
for my $value (@_)
{
2013-09-28 16:52:38 +00:00
if (! grep { $value eq $_ } @data)
{
2013-09-02 18:43:18 +00:00
$mod = 1;
2013-09-03 05:20:58 +00:00
2013-09-04 00:56:29 +00:00
log(DEBUG, "Add attribute $value to $dn");
2013-09-03 05:20:58 +00:00
2013-09-02 18:43:18 +00:00
push @data, $value;
}
2013-09-03 13:12:05 +00:00
else {
2013-09-04 00:56:29 +00:00
log(WARN, "Attribute $what with value $value for $dn already exists.");
2013-09-03 13:12:05 +00:00
}
2013-09-02 18:43:18 +00:00
}
if ($mod)
{
$entry->replace($what => \@data) or die $!;
2013-09-03 05:20:58 +00:00
my $mesg = $entry->update($ldap) or die $!;
2013-09-04 00:56:29 +00:00
if ($mesg->code != 0) { log(WARN, $mesg->error); return 0; }
2013-09-03 05:20:58 +00:00
2013-09-02 18:43:18 +00:00
return 1;
}
else {
return 0;
}
2013-09-02 17:13:12 +00:00
}
2013-09-02 18:43:18 +00:00
sub delete_attribute($$$@)
2013-09-02 17:13:12 +00:00
{
2013-09-02 18:43:18 +00:00
my $ldap = shift // ldap_connect();
2013-09-02 17:13:12 +00:00
my $dn = shift;
my $what = shift;
2013-09-02 18:43:18 +00:00
my $mod = 0;
2013-09-02 17:13:12 +00:00
2013-09-02 18:43:18 +00:00
my $entry = get_dn($ldap, $dn, $what);
my @data = $entry->get_value($what);
for my $value (@_)
{
2013-09-28 16:52:38 +00:00
if (grep { $value eq $_ } @data)
{
2013-09-04 00:56:29 +00:00
log(DEBUG, "Remove attribute $what ($value) from $dn");
2013-09-03 05:20:58 +00:00
2013-10-24 22:18:15 +00:00
@data = grep { $value ne $_ } @data;
2013-09-02 18:43:18 +00:00
$mod = 1;
}
2013-09-03 06:07:02 +00:00
else {
2013-09-04 00:56:29 +00:00
log(WARN, "No attribute $what with value $value for $dn");
2013-09-03 06:07:02 +00:00
}
2013-09-02 18:43:18 +00:00
}
2013-09-02 17:13:12 +00:00
2013-09-02 18:43:18 +00:00
if ($mod)
{
$entry->replace($what => \@data) or die $!;
2013-09-03 05:20:58 +00:00
my $mesg = $entry->update($ldap) or die $!;
2013-09-04 00:56:29 +00:00
if ($mesg->code != 0) { log(WARN, $mesg->error); return 0; }
2013-09-02 18:43:18 +00:00
return 1;
}
else {
return 0;
}
2013-09-02 17:13:12 +00:00
}
2013-09-02 18:43:18 +00:00
sub delete_entry($$)
2013-09-02 17:13:12 +00:00
{
2013-09-02 18:43:18 +00:00
my $ldap = shift // ldap_connect();
2013-09-02 17:13:12 +00:00
2013-09-03 05:20:58 +00:00
my $mesg = $ldap->delete( shift );
2013-09-04 00:56:29 +00:00
if ($mesg->code != 0) { log(WARN, $mesg->error); return 0; }
2013-09-02 17:13:12 +00:00
2013-09-03 05:20:58 +00:00
return 1;
2013-09-02 18:43:18 +00:00
}
sub flush_attribute($$@)
{
my $ldap = shift // ldap_connect();
my $dn = shift;
2013-09-02 17:13:12 +00:00
2013-09-15 22:20:26 +00:00
my $mesg = $ldap->modify($dn, delete => \@_);
2013-09-03 05:20:58 +00:00
2013-09-04 00:56:29 +00:00
if ($mesg->code != 0) { log(WARN, $mesg->error); return 0; }
2013-09-03 05:20:58 +00:00
return 1;
2013-09-02 17:13:12 +00:00
}
2013-09-02 18:43:18 +00:00
sub get_attribute($$$)
2013-09-02 17:13:12 +00:00
{
2013-09-02 18:43:18 +00:00
my $ldap = shift // ldap_connect();
2013-09-02 17:13:12 +00:00
my $dn = shift;
my $what = shift;
2013-09-06 03:22:35 +00:00
if (!$dn) { return undef; }
2013-09-02 18:43:18 +00:00
return get_dn($ldap, $dn, $what)->get_value($what);
}
2013-09-02 17:13:12 +00:00
sub search_dn($$@)
{
my $ldap = shift // ldap_connect();
my $base = shift;
my $filter = shift;
2013-10-28 14:11:04 +00:00
$base .= "," if ($base);
log (DEBUG, "Looking for $filter in $base" . BASE_DN);
my $mesg = $ldap->search( # search
2013-10-28 14:11:04 +00:00
base => $base . BASE_DN,
filter => Net::LDAP::Filter->new($filter),
attrs => [ ],
scope => "sub"
);
return undef if ($mesg->code != 0);
2013-10-28 14:11:04 +00:00
croak("$filter not found") if ($mesg->count == 0);
croak("$filter not unique") if ($mesg->count > 1);
return $mesg->entry(0)->dn;
}
2013-09-04 00:56:29 +00:00
sub search_dns($$$@)
{
my $ldap = shift // ldap_connect();
my $base = shift;
my $filter = shift;
2013-10-28 14:11:04 +00:00
$base .= "," if ($base);
2013-09-04 00:56:29 +00:00
my $mesg = $ldap->search( # search
2013-10-28 14:11:04 +00:00
base => $base . BASE_DN,
filter => Net::LDAP::Filter->new($filter),
attrs => \@_,
2013-09-04 00:56:29 +00:00
scope => "sub"
);
2013-10-28 14:11:04 +00:00
if ($mesg->code != 0) { log(WARN, $mesg->error); return []; }
2013-09-04 00:56:29 +00:00
return $mesg->entries;
}
2013-09-02 18:43:18 +00:00
sub update_attribute($$$@)
{
my $ldap = shift // ldap_connect();
my $dn = shift;
my $what = shift;
2013-09-02 17:13:12 +00:00
2013-09-02 18:43:18 +00:00
my $entry = get_dn($ldap, $dn, $what);
2013-09-03 05:20:58 +00:00
$entry->replace($what => \@_);
my $mesg = $entry->update($ldap);
if ($mesg->code != 0) {
2013-09-04 00:56:29 +00:00
log(WARN, $mesg->error);
2013-09-03 05:20:58 +00:00
return 0;
}
2013-09-02 18:43:18 +00:00
return 1;
2013-09-02 17:13:12 +00:00
}
1;