Unverified Commit 1769ded5 authored by Francesc Guasch's avatar Francesc Guasch Committed by GitHub
Browse files

Feat group base (#1644)

also shows info about the group in the frontend

closes #1637
parent e6ba3043
......@@ -56,14 +56,17 @@ use feature qw(signatures);
our %VALID_CONFIG = (
vm => undef
,warn_error => undef
,db => {user => undef, password => undef, hostname => undef, host => undef}
,db => {user => undef, password => undef, hostname => undef, host => undef, db => undef}
,ldap => { admin_user => { dn => undef, password => undef }
,filter => undef
,base => undef
,auth => undef
,admin_group => undef
,ravada_posix_group => undef
,groups_base => undef
,field => undef
}
,log => undef
);
=head1 NAME
......@@ -2509,19 +2512,19 @@ sub _create_vm_kvm {
return $vm_kvm;
}
sub _check_config($config_orig = {} , $valid_config = \%VALID_CONFIG ) {
sub _check_config($config_orig = {} , $valid_config = \%VALID_CONFIG, $quiet = $0=~/\.t$/ ) {
return 1 if !defined $config_orig;
my %config = %$config_orig;
for my $key (sort keys %$valid_config) {
if ( $config{$key} && ref($valid_config->{$key})) {
my $ok = _check_config( $config{$key} , $valid_config->{$key} );
my $ok = _check_config( $config{$key} , $valid_config->{$key}, $quiet );
return 0 if !$ok;
}
delete $config{$key};
}
if ( keys %config ) {
warn "Error: Unknown config entry \n".Dumper(\%config) if ! $0 =~ /\.t$/;
warn "Error: Unknown config entry \n".Dumper(\%config) if ! $quiet;
return 0;
}
warn "Warning: LDAP authentication with match is discouraged. Try bind.\n"
......
......@@ -78,6 +78,9 @@ sub add_user($name, $password, $storage='rfc2307', $algorithm=undef ) {
_init_ldap_admin();
my $base = ( $$CONFIG->{ldap}->{base} or _dc_base() );
my $field = ( $$CONFIG->{ldap}->{field} or "cn" );
$name = escape_filter_value($name);
$password = escape_filter_value($password);
......@@ -87,7 +90,7 @@ sub add_user($name, $password, $storage='rfc2307', $algorithm=undef ) {
my %entry = (
cn => $name
, uid => $name
, $field => $name
# , uidNumber => _new_uid()
# , gidNumber => $GID
, objectClass => [@OBJECT_CLASS]
......@@ -96,7 +99,7 @@ sub add_user($name, $password, $storage='rfc2307', $algorithm=undef ) {
# , homeDirectory => "/home/$name"
,userPassword => _password_store($password, $storage, $algorithm)
);
my $dn = "cn=$name,"._dc_base();
my $dn = "$field=$name,".$base;
my $mesg = $LDAP_ADMIN->add($dn, attr => [%entry]);
if ($mesg->code) {
......@@ -156,8 +159,9 @@ sub _get_gid() {
add_group('users');
($group_users) = search_group(name => 'users');
confess "Error: I can create nor find LDAP group 'users'" if !$group_users;
warn "Warning: group users has no gidNumber".Dumper($group_users) if !$group_users->get_value('gidNumber');
}
return $group_users->get_value('gidNumber');
return ($group_users->get_value('gidNumber') or '1000');
}
sub _new_uid($ldap=_init_ldap_admin(), $base=_dc_base()) {
......@@ -268,7 +272,7 @@ sub search_user {
my $username = delete $args{name} or confess "Missing user name";
my $retry = (delete $args{retry} or 0);
my $field = (delete $args{field} or $$CONFIG->{ldap}->{field} or 'uid');
my $field = (delete $args{field} or $$CONFIG->{ldap}->{field} or 'cn');
my $ldap = (delete $args{ldap} or _init_ldap_admin());
my $base = (delete $args{base} or _dc_base());
my $typesonly= (delete $args{typesonly} or 0);
......@@ -303,7 +307,7 @@ sub search_user {
);
if ( $retry <= 3 && $mesg->code && $mesg->code != 4 ) {
if ( $retry <= 3 && $mesg->code && $mesg->code != 4 && $mesg->code != 32) {
warn "LDAP error ".$mesg->code." ".$mesg->error."."
."Retrying ! [$retry]" if $retry;
$LDAP_ADMIN = undef;
......@@ -336,9 +340,11 @@ Add a group to the LDAP
=cut
sub add_group($name, $base=_dc_base(), $class=['groupOfUniqueNames','nsMemberOf','posixGroup','top' ]) {
sub add_group($name, $base=undef, $class=['groupOfUniqueNames','nsMemberOf','posixGroup','top' ]) {
$base = ($$CONFIG->{ldap}->{groups_base} or "ou=groups,"._dc_base()) if !defined $base;
my $ldap = _init_ldap_admin();
$base = _dc_base() if !defined $base;
$name = escape_filter_value($name);
my $oc_posix_group;
$oc_posix_group = grep { /^posixGroup$/ } @$class;
......@@ -350,7 +356,7 @@ sub add_group($name, $base=_dc_base(), $class=['groupOfUniqueNames','nsMemberOf'
push @attrs, (gidNumber => _search_new_gid()) if $oc_posix_group;
my @data = (
dn => "cn=$name,ou=groups,$base"
dn => "cn=$name,$base"
, cn => $name
, attrs => \@attrs
);
......@@ -386,9 +392,8 @@ Removes the group from the LDAP directory. Use with caution
sub remove_group {
my $name = shift;
my $base = shift;
$base = "ou=groups,"._dc_base() if !$base;
my $base = ( $$CONFIG->{ldap}->{groups_base} or "ou=groups,"._dc_base() );
my $entry = search_group(name => $name, base => $base);
if (!$entry) {
......@@ -409,7 +414,7 @@ sub search_group {
my %args = @_;
my $name = delete $args{name} or confess "Error: missing name";
my $base = ( delete $args{base} or "ou=groups,"._dc_base() );
my $base = ( delete $args{base} or $$CONFIG->{ldap}->{groups_base} or "ou=groups,"._dc_base() );
my $ldap = ( delete $args{ldap} or _init_ldap_admin());
my $retry =( delete $args{retry} or 0);
......@@ -438,7 +443,7 @@ sub search_group {
);
}
if ( $retry <= 3 && $mesg->code){
if ( $retry <= 3 && $mesg->code && $mesg->code != 32){
warn "LDAP error ".$mesg->code." ".$mesg->error.". [cn=$name] "
."Retrying ! [$retry]" if $retry;
$LDAP_ADMIN = undef;
......@@ -461,7 +466,8 @@ sub search_group {
=cut
sub search_group_members($cn, $retry = 0) {
my $base = "ou=groups,"._dc_base();
my $base = ($$CONFIG->{ldap}->{groups_base} or "ou=groups,"._dc_base());
my $ldap = _init_ldap_admin();
my $sizelimit = ($$CONFIG->{ldap}->{size_limit} or 1000);
......@@ -479,7 +485,7 @@ sub search_group_members($cn, $retry = 0) {
my @entries = map { $_->get_value('cn') } $mesg->entries();
$mesg = $ldap ->search (
filter => "member=cn=$cn,"._dc_base()
filter => "member=cn=$cn,".$base
,base => $base
,sizelimit => $sizelimit
);
......@@ -574,7 +580,8 @@ sub remove_from_group {
=cut
sub _search_posix_group($self, $name) {
my $base = 'ou=groups,'._dc_base();
my $base = ($$CONFIG->{ldap}->{groups_base} or "ou=groups,"._dc_base());
my $field = 'cn';
if ($name =~ /(.*?)=(.*)/) {
$field = $1;
......
......@@ -317,7 +317,9 @@ get '/admin/group/#name' => sub($c) {
."<a href='/admin/groups/'>Groups</a>"
, status => 302) if !$group;
$c->stash(object_class => [ grep !/^top$/,$group->get_value('objectClass')]);
return $c->render( template => "/main/admin_group");
return $c->render( template => "/main/admin_group"
,group => $group
);
};
any '/admin/#type' => sub {
......
......@@ -599,11 +599,17 @@ sub test_uid_cn($user, $with_posix_group) {
Ravada::Auth::LDAP::init();
my $ldap = Ravada::Auth::LDAP::_init_ldap_admin();
my $entry = $user->{_ldap_entry};
my $field = 'uid';
my $uid_value = new_domain_name();
my $mesg = $entry->replace( $field => $uid_value )->update($ldap);
$mesg->code and die $mesg->error; # check for errors
_add_to_posix_group($uid_value, $with_posix_group);
my %data = (
cn => $entry->get_value('cn')
,$field => $entry->get_value($field)
,$field => $uid_value
);
......@@ -622,11 +628,13 @@ sub test_login_fields($data) {
my $login_ok;
for my $field ( sort keys %$data ) {
my $value = $data->{$field};
$Ravada::CONFIG->{ldap}->{field} = $field;
eval { $login_ok = Ravada::Auth::login($value, $password) };
is($@,''," $field: $value");
is($@,''," $field: $value") or confess;
ok($login_ok, $value);
}
delete $Ravada::CONFIG->{ldap}->{field};
}
sub test_pass_storage($with_posix_group) {
......
use warnings;
use strict;
use Carp qw(confess);
use Data::Dumper;
use Test::More;
use YAML qw(LoadFile DumpFile);
no warnings "experimental::signatures";
use feature qw(signatures);
use lib 't/lib';
use Test::Ravada;
my $BASE_USERS = "cn=users,cn=accounts,dc=example,dc=com";
my $BASE_GROUPS = 'cn=groups,cn=accounts,dc=example,dc=com';
our @OBJECT_CLASS = ('top'
,'organizationalPerson'
,'person'
,'inetOrgPerson'
);
sub _init_base($base) {
my $dn1 = $base;
$dn1 =~ s/cn=\w+,(.*)/$1/;
my $ldap = Ravada::Auth::LDAP::_init_ldap_admin();
for my $dn ( $dn1 , $base) {
my ($filter,$base) = $dn =~ /(.*?),(.*)/;
my $mesg = $ldap->search( # Search for the user
base => $base,
filter => $filter,
scope => 'sub',
typesonly => 0,
attrs => ['*']
);
confess "LDAP error ".$mesg->code." ".$mesg->error if $mesg->code;
my @entries = $mesg->entries;
if (!@entries) {
my ($cn) = $dn =~ /^cn=(.*?),/;
my %data = (
cn => $cn
,sn => $cn
,objectclass => [@OBJECT_CLASS ]
);
warn $dn;
$mesg = $ldap->add($dn, attr => [%data]);
if ($mesg->code) {
die "Error adding $dn ".$mesg->error;
}
}
}
}
sub _create_group() {
my $g_name="group_".new_domain_name();
for my $base ( 'ou=groups,dc=example,dc=com', $BASE_GROUPS ) {
my $group = Ravada::Auth::LDAP::search_group(name => $g_name, base => $base);
if ($group) {
my $ldap = Ravada::Auth::LDAP::_init_ldap_admin();
$ldap->delete($group);
$group = undef;
}
}
Ravada::Auth::LDAP::add_group( $g_name );
my $group = Ravada::Auth::LDAP::search_group(name => $g_name);
ok($group) or return;
like($group->dn,qr/cn=.*?,$BASE_GROUPS$/);
ok($group);
return $group;
}
init('t/etc/ravada_ldap_basic.conf');
$Ravada::CONFIG->{ldap}->{base} = $BASE_USERS;
$Ravada::CONFIG->{ldap}->{field} = 'uid';
$Ravada::CONFIG->{ldap}->{groups_base} = $BASE_GROUPS;
_init_base($BASE_GROUPS);
_init_base($BASE_USERS);
{
my $group = _create_group() or next;
is( scalar(Ravada::Auth::LDAP::group_members($group)),0);
my $user = create_ldap_user(new_domain_name(),"$$");
like($user->dn,qr/uid=.*?,$BASE_USERS/) or exit;
Ravada::Auth::LDAP::add_to_group($user->dn, $group->get_value('cn'));
$group = Ravada::Auth::LDAP::search_group(name => $group->get_value('cn'));
ok($group,"Expecting group ".$group->dn." exists") or next;
my @members = Ravada::Auth::LDAP::group_members($group);
is(scalar(@members),1);
@members = Ravada::Auth::LDAP::group_members($group->get_value('cn'));
is(scalar(@members),1);
is(Ravada::Auth::LDAP::is_member($user->get_value('cn'), $group),1);
is(Ravada::Auth::LDAP::is_member($user->dn, $group),1);
my $user2 = create_ldap_user(new_domain_name(),"$$");
is(Ravada::Auth::LDAP::is_member($user2->get_value('cn'), $group),0);
is(Ravada::Auth::LDAP::is_member($user2->dn, $group),0);
delete $Ravada::CONFIG->{ldap}->{ravada_posix_group};
my $login;
eval { $login = Ravada::Auth::LDAP->new(name => $user2->get_value('cn'),password => "$$") };
is($@,'') or exit;
ok($login);
$Ravada::CONFIG->{ldap}->{group}=$group->get_value('cn');
$login =undef;
eval { $login = Ravada::Auth::LDAP->new(name => $user2->get_value('cn'),password => "$$") };
like($@,qr'.');
ok(!$login,"Expecting no login with ".$user2->get_value('cn'));
$login =undef;
eval { $login = Ravada::Auth::LDAP->new(name => $user->get_value('cn'),password => "$$") };
is($@,'');
ok($login);
Ravada::Auth::LDAP::remove_from_group($user->dn, $group->get_value('cn'));
$group = Ravada::Auth::LDAP::search_group(name => $group->get_value('cn'));
is(Ravada::Auth::LDAP::is_member($user->get_value('cn') , $group),0
,"Expecting ".$user->get_value('cn')." not member of ".$group->get_value('cn'))
or die Dumper([Ravada::Auth::LDAP::group_members($group)]);
delete $Ravada::CONFIG->{ldap}->{group};
}
end();
done_testing();
......@@ -19,7 +19,7 @@ init( $CONFIG_FILE);
rvd_back();
my $RVD_FRONT;
my $USER_DATA = { name => 'jimmy', password => 'jameson' };
my $USER_DATA = { name => 'jimmy.'.new_domain_name, password => 'jameson' };
#########################################################################
......
......@@ -906,10 +906,21 @@ sub create_user {
sub create_ldap_user($name, $password, $keep=0) {
if ( Ravada::Auth::LDAP::search_user($name) ) {
return if $keep;
diag("Removing $name");
Ravada::Auth::LDAP::remove_user($name)
my $ldap = Ravada::Auth::LDAP::_init_ldap_admin();
for my $field (qw(cn uid)) {
if (my $user = Ravada::Auth::LDAP::search_user(field => $field, name => $name) ) {
return if $keep;
diag("Removing ".$user->dn);
my $mesg;
for ( 1 .. 2 ) {
$mesg = $user->delete()->update($ldap);
if ($mesg->code == 81 ) {
Ravada::Auth::LDAP::init();
$ldap = Ravada::Auth::LDAP::_init_ldap_admin();
}
}
die $mesg->code." ".$mesg->error if $mesg->code && $mesg->code != 32;
}
}
my $user = Ravada::Auth::LDAP::search_user($name);
......@@ -1386,7 +1397,6 @@ sub _remove_old_groups_ldap() {
die $@ if $@;
for my $group ( @groups ) {
next if !$group;
warn $group->dn;
for my $n ( 1 .. 3 ) {
my $mesg = $ldap->delete($group);
last if !$mesg->code;
......
......@@ -12,7 +12,9 @@
<div class="card" id="admin-content">
<div class="card-header">
<h2 class="display-5"><%=l 'Group' %> <%= $name %></h2>
<%= join(" - ",sort @$object_class) %>
object class: <b><%= join(" - ",sort @$object_class) %></b>
<br/>
dn: <b><%= $group->dn %></b>
</div>
</div>
</div>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment