Synced users get their comment from the 'comment' attribute, but synced groups never get one, as only the name and the members of a group are queried. With FreeIPA for example, groups are described with the 'description' attribute, which is then not visible in Proxmox VE. Set the comment of a synced group to its description, if it has one. Like for the attributes of users, an existing comment is overwritten by the synced one, and kept if the group has no description, unless 'properties' is part of 'remove-vanished'. Signed-off-by: Michal Fox <me@dualfroz.com>
366 lines
9.8 KiB
Perl
366 lines
9.8 KiB
Perl
#!/usr/bin/perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Test::MockModule;
|
|
use Test::More;
|
|
use Storable qw(dclone);
|
|
|
|
use PVE::AccessControl;
|
|
use PVE::API2::Domains;
|
|
|
|
my $domainscfg = {
|
|
ids => {
|
|
"pam" => { type => 'pam' },
|
|
"pve" => { type => 'pve' },
|
|
"syncedrealm" => { type => 'ldap' },
|
|
},
|
|
};
|
|
|
|
my $initialusercfg = {
|
|
users => {
|
|
'root@pam' => { username => 'root' },
|
|
'user1@syncedrealm' => {
|
|
username => 'user1',
|
|
enable => 1,
|
|
'keys' => 'some',
|
|
},
|
|
'user2@syncedrealm' => {
|
|
username => 'user2',
|
|
enable => 1,
|
|
},
|
|
'user3@syncedrealm' => {
|
|
username => 'user3',
|
|
enable => 1,
|
|
},
|
|
},
|
|
groups => {
|
|
'group1-syncedrealm' => { users => {}, comment => 'outdated comment' },
|
|
'group2-syncedrealm' => { users => {} },
|
|
},
|
|
acl_root => {
|
|
users => {
|
|
'user3@syncedrealm' => {},
|
|
},
|
|
groups => {},
|
|
},
|
|
};
|
|
|
|
my $sync_response = {
|
|
user => [
|
|
{
|
|
attributes => { 'uid' => ['user1'] },
|
|
dn => 'uid=user1,dc=syncedrealm',
|
|
},
|
|
{
|
|
attributes => { 'uid' => ['user2'] },
|
|
dn => 'uid=user2,dc=syncedrealm',
|
|
},
|
|
{
|
|
attributes => { 'uid' => ['user4'] },
|
|
dn => 'uid=user4,dc=syncedrealm',
|
|
},
|
|
],
|
|
groups => [
|
|
{
|
|
dn => 'dc=group1,dc=syncedrealm',
|
|
description => 'First group',
|
|
members => [
|
|
'uid=user1,dc=syncedrealm',
|
|
],
|
|
},
|
|
{
|
|
dn => 'dc=group3,dc=syncedrealm',
|
|
members => [
|
|
'uid=nonexisting,dc=syncedrealm',
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
my $returned_user_cfg = {};
|
|
|
|
# mocking all cluster and ldap operations
|
|
my $pve_cluster_module = Test::MockModule->new('PVE::Cluster');
|
|
$pve_cluster_module->mock(
|
|
cfs_update => sub { },
|
|
cfs_read_file => sub {
|
|
my ($filename) = @_;
|
|
if ($filename eq 'domains.cfg') { return dclone($domainscfg); }
|
|
if ($filename eq 'user.cfg') { return dclone($initialusercfg); }
|
|
die "unexpected cfs_read_file";
|
|
},
|
|
cfs_write_file => sub {
|
|
my ($filename, $data) = @_;
|
|
if ($filename eq 'user.cfg') {
|
|
$returned_user_cfg = $data;
|
|
return;
|
|
}
|
|
die "unexpected cfs_read_file";
|
|
},
|
|
cfs_lock_file => sub {
|
|
my ($filename, $timeout, $code) = @_;
|
|
return $code->();
|
|
},
|
|
);
|
|
|
|
my $pve_api_domains = Test::MockModule->new('PVE::API2::Domains');
|
|
$pve_api_domains->mock(
|
|
cfs_read_file => sub { PVE::Cluster::cfs_read_file(@_); },
|
|
cfs_write_file => sub { PVE::Cluster::cfs_write_file(@_); },
|
|
);
|
|
|
|
my $pve_accesscontrol = Test::MockModule->new('PVE::AccessControl');
|
|
$pve_accesscontrol->mock(
|
|
cfs_lock_file => sub { PVE::Cluster::cfs_lock_file(@_); },
|
|
);
|
|
|
|
my $pve_rpcenvironment = Test::MockModule->new('PVE::RPCEnvironment');
|
|
$pve_rpcenvironment->mock(
|
|
get => sub { return bless {}, 'PVE::RPCEnvironment'; },
|
|
get_user => sub { return 'root@pam'; },
|
|
fork_worker => sub {
|
|
my ($class, $workertype, $id, $user, $code) = @_;
|
|
|
|
return $code->();
|
|
},
|
|
);
|
|
|
|
my $pve_ldap_module = Test::MockModule->new('PVE::LDAP');
|
|
$pve_ldap_module->mock(
|
|
ldap_connect => sub { return {}; },
|
|
ldap_bind => sub { },
|
|
query_users => sub {
|
|
return $sync_response->{user};
|
|
},
|
|
query_groups => sub {
|
|
return $sync_response->{groups};
|
|
},
|
|
);
|
|
|
|
my $pve_auth_ldap = Test::MockModule->new('PVE::Auth::LDAP');
|
|
$pve_auth_ldap->mock(
|
|
connect_and_bind => sub { return {}; },
|
|
);
|
|
|
|
my $tests = [
|
|
[
|
|
"non-full without purge",
|
|
{
|
|
realm => 'syncedrealm',
|
|
scope => 'both',
|
|
},
|
|
{
|
|
users => {
|
|
'root@pam' => { username => 'root' },
|
|
'user1@syncedrealm' => {
|
|
username => 'user1',
|
|
enable => 1,
|
|
'keys' => 'some',
|
|
},
|
|
'user2@syncedrealm' => {
|
|
username => 'user2',
|
|
enable => 1,
|
|
},
|
|
'user3@syncedrealm' => {
|
|
username => 'user3',
|
|
enable => 1,
|
|
},
|
|
'user4@syncedrealm' => {
|
|
username => 'user4',
|
|
enable => 1,
|
|
},
|
|
},
|
|
groups => {
|
|
'group1-syncedrealm' => {
|
|
users => {
|
|
'user1@syncedrealm' => 1,
|
|
},
|
|
comment => 'First group',
|
|
},
|
|
'group2-syncedrealm' => { users => {} },
|
|
'group3-syncedrealm' => { users => {} },
|
|
},
|
|
acl_root => {
|
|
users => {
|
|
'user3@syncedrealm' => {},
|
|
},
|
|
groups => {},
|
|
},
|
|
},
|
|
],
|
|
[
|
|
"full without purge",
|
|
{
|
|
realm => 'syncedrealm',
|
|
'remove-vanished' => 'entry;properties',
|
|
scope => 'both',
|
|
},
|
|
{
|
|
users => {
|
|
'root@pam' => { username => 'root' },
|
|
'user1@syncedrealm' => {
|
|
username => 'user1',
|
|
enable => 1,
|
|
},
|
|
'user2@syncedrealm' => {
|
|
username => 'user2',
|
|
enable => 1,
|
|
},
|
|
'user4@syncedrealm' => {
|
|
username => 'user4',
|
|
enable => 1,
|
|
},
|
|
},
|
|
groups => {
|
|
'group1-syncedrealm' => {
|
|
users => {
|
|
'user1@syncedrealm' => 1,
|
|
},
|
|
comment => 'First group',
|
|
},
|
|
'group3-syncedrealm' => { users => {} },
|
|
},
|
|
acl_root => {
|
|
users => {
|
|
'user3@syncedrealm' => {},
|
|
},
|
|
groups => {},
|
|
},
|
|
},
|
|
],
|
|
[
|
|
"non-full with purge",
|
|
{
|
|
realm => 'syncedrealm',
|
|
'remove-vanished' => 'acl',
|
|
scope => 'both',
|
|
},
|
|
{
|
|
users => {
|
|
'root@pam' => { username => 'root' },
|
|
'user1@syncedrealm' => {
|
|
username => 'user1',
|
|
enable => 1,
|
|
'keys' => 'some',
|
|
},
|
|
'user2@syncedrealm' => {
|
|
username => 'user2',
|
|
enable => 1,
|
|
},
|
|
'user3@syncedrealm' => {
|
|
username => 'user3',
|
|
enable => 1,
|
|
},
|
|
'user4@syncedrealm' => {
|
|
username => 'user4',
|
|
enable => 1,
|
|
},
|
|
},
|
|
groups => {
|
|
'group1-syncedrealm' => {
|
|
users => {
|
|
'user1@syncedrealm' => 1,
|
|
},
|
|
comment => 'First group',
|
|
},
|
|
'group2-syncedrealm' => { users => {} },
|
|
'group3-syncedrealm' => { users => {} },
|
|
},
|
|
acl_root => {
|
|
users => {},
|
|
groups => {},
|
|
},
|
|
},
|
|
],
|
|
[
|
|
"full with purge",
|
|
{
|
|
realm => 'syncedrealm',
|
|
'remove-vanished' => 'acl;entry;properties',
|
|
scope => 'both',
|
|
},
|
|
{
|
|
users => {
|
|
'root@pam' => { username => 'root' },
|
|
'user1@syncedrealm' => {
|
|
username => 'user1',
|
|
enable => 1,
|
|
},
|
|
'user2@syncedrealm' => {
|
|
username => 'user2',
|
|
enable => 1,
|
|
},
|
|
'user4@syncedrealm' => {
|
|
username => 'user4',
|
|
enable => 1,
|
|
},
|
|
},
|
|
groups => {
|
|
'group1-syncedrealm' => {
|
|
users => {
|
|
'user1@syncedrealm' => 1,
|
|
},
|
|
comment => 'First group',
|
|
},
|
|
'group3-syncedrealm' => { users => {} },
|
|
},
|
|
acl_root => {
|
|
users => {},
|
|
groups => {},
|
|
},
|
|
},
|
|
],
|
|
[
|
|
"don't delete properties, but users and acls",
|
|
{
|
|
realm => 'syncedrealm',
|
|
'remove-vanished' => 'acl;entry',
|
|
scope => 'both',
|
|
},
|
|
{
|
|
users => {
|
|
'root@pam' => { username => 'root' },
|
|
'user1@syncedrealm' => {
|
|
username => 'user1',
|
|
enable => 1,
|
|
'keys' => 'some',
|
|
},
|
|
'user2@syncedrealm' => {
|
|
username => 'user2',
|
|
enable => 1,
|
|
},
|
|
'user4@syncedrealm' => {
|
|
username => 'user4',
|
|
enable => 1,
|
|
},
|
|
},
|
|
groups => {
|
|
'group1-syncedrealm' => {
|
|
users => {
|
|
'user1@syncedrealm' => 1,
|
|
},
|
|
comment => 'First group',
|
|
},
|
|
'group3-syncedrealm' => { users => {} },
|
|
},
|
|
acl_root => {
|
|
users => {},
|
|
groups => {},
|
|
},
|
|
},
|
|
],
|
|
];
|
|
|
|
for my $test (@$tests) {
|
|
my $name = $test->[0];
|
|
my $parameters = $test->[1];
|
|
my $expected = $test->[2];
|
|
$returned_user_cfg = {};
|
|
PVE::API2::Domains->sync($parameters);
|
|
is_deeply($returned_user_cfg, $expected, $name);
|
|
}
|
|
|
|
done_testing();
|