diff --git a/seed/openldap/dictionaries/21_openldap-server.xml b/seed/openldap/dictionaries/21_openldap-server.xml
index d0f712d5..c23a7629 100644
--- a/seed/openldap/dictionaries/21_openldap-server.xml
+++ b/seed/openldap/dictionaries/21_openldap-server.xml
@@ -14,6 +14,7 @@
/secrets/admin_ldap.pwd
/sysusers.d/risotto-openldap.conf
/tmpfiles.d/0openldap-server.conf
+ /tests/openldap.yml
diff --git a/seed/openldap/templates/config_acl.ldif b/seed/openldap/templates/config_acl.ldif
index 30123bd5..e26b4f68 100644
--- a/seed/openldap/templates/config_acl.ldif
+++ b/seed/openldap/templates/config_acl.ldif
@@ -1,10 +1,22 @@
+%set %%name_family = 'gnunux'
%set %%dns = {}
%set %%groups = []
+%%groups.append('cn=remote_test0,' + %%ldapclient_base_dn)%slurp
+%%groups.append('cn=remote_test1,' + %%ldapclient_base_dn)%slurp
+%%groups.append('cn=remote_test2,' + %%ldapclient_base_dn)%slurp
+%%dns.setdefault(None, []).append(('cn=remote_test0,' + %%ldapclient_base_dn, 'read'))%slurp
+%%dns.setdefault('all', []).append(('cn=remote_test1,' + %%ldapclient_base_dn, 'read'))%slurp
+%%dns.setdefault(%%name_family, []).append(('cn=remote_test2,' + %%ldapclient_base_dn, 'read'))%slurp
%for %%remote in %%accounts.remotes
%set %%name = %%normalize_family(%%remote)
%set %%family = %%accounts['remote_' + %%name]['family_' + %%name]
%%groups.append(%%accounts['remote_' + %%name]['dn_' + %%name])%slurp
-%%dns.setdefault(%%family, []).append((%%accounts['remote_' + %%name]['dn_' + %%name], %%accounts['remote_' + %%name]['read_only_' + %%name]))%slurp
+ %if %%accounts['remote_' + %%name]['read_only_' + %%name]
+ %set %%right = 'read'
+ %else
+ %set %%right = 'write'
+ %end if
+%%dns.setdefault(%%family, []).append((%%accounts['remote_' + %%name]['dn_' + %%name], %%right))%slurp
%end for
dn: olcDatabase={2}mdb,cn=config
changetype:modify
@@ -21,19 +33,28 @@ olcAccess: {1}to dn.subtree="%%ldap_group_dn"
%set %%aclidx = 2
%for %%family, %%remotes in %%dns.items()
%if %%family == 'all'
-olcAccess: {%%aclidx}to dn.subtree="%%ldap_account_dn"
- %else
-olcAccess: {%%aclidx}to dn.subtree="%%calc_ldapclient_base_dn(%%ldapclient_base_dn, %%family)"
+ %continue
%end if
+olcAccess: {%%aclidx}to dn.subtree="%%calc_ldapclient_base_dn(%%ldapclient_base_dn, %%family)"
by self read
%for %%remote in %%remotes
- by dn="%%remote[0]" %slurp
- %if %%remote[1]
-read
- %else
-write
- %end if
+ by dn="%%remote[0]" %%remote[1]
%end for
- %set %%aclidx += 1
+ %if %%family != 'all' and 'all' in %%dns
+ %for %%remote in %%dns['all']
+ by dn="%%remote[0]" %%remote[1]
+ %end for
+ %end if
+ %set %%aclidx += 1
+ %if %%family != 'all'
by * none
+ %end if
%end for
+%if 'all' in %%dns
+olcAccess: {%%aclidx}to dn.subtree="%%ldap_account_dn"
+ by self read
+ %for %%remote in %%dns['all']
+ by dn="%%remote[0]" %%remote[1]
+ %end for
+ by * none
+%end if
diff --git a/seed/openldap/templates/openldap.yml b/seed/openldap/templates/openldap.yml
new file mode 100644
index 00000000..5466d094
--- /dev/null
+++ b/seed/openldap/templates/openldap.yml
@@ -0,0 +1,40 @@
+%set %%username = "rougail_test@silique.fr"
+%set %%username_family = "rougail_test@gnunux.info"
+%set %%familydn = %%calc_ldapclient_base_dn(%%ldapclient_base_dn, family_name='gnunux')
+address: %%ip_eth0
+admin_dn: %%ldapclient_user
+admin_password: %%ldapclient_user_password
+user_dn: cn=%%username,%%ldap_user_dn
+user_password: %%get_password(server_name=%%ldap_server_address, username=%%username, description="ldap user", type="cleartext", hide=%%hide_secret, temporary=True)
+user_family_dn: cn=%%username_family,%%familydn
+user_family_password: %%get_password(server_name=%%ldap_server_address, username=%%username_family, description="ldap family user", type="cleartext", hide=%%hide_secret, temporary=True)
+base_account_dn: %%ldap_account_dn
+base_user_dn: %%ldap_user_dn
+base_family_dn: %%familydn
+base_group_dn: %%ldap_group_dn
+%for %%idx in %%range(3)
+ %set %%name = 'remote_test' + %%str(%%idx)
+remote%%idx: cn=%%name,%%ldapclient_base_dn
+remote_password%%idx: %%get_password(server_name=%%domain_name_eth0, username=%%name, description="remote account", type="cleartext", hide=%%hide_secret, temporary=True)
+%end for
+users:
+%for %%user in %%accounts.users.ldap_user_mail
+ %%user: cn=%%user,%%ldap_user_dn
+%end for
+%for %%family in %%accounts.families
+ %set %%families = %%calc_ldapclient_base_dn(%%ldapclient_base_dn, %%family)
+ %for %%user in %%accounts['family_' + %%family]['users_' + %%family]['ldap_user_mail_' + %%family]
+ %%user: cn=%%user,%%families
+ %end for
+%end for
+groups:
+ users:
+%for %%user in %%accounts.users.ldap_user_mail
+ - cn=%%user,%%ldap_user_dn
+%end for
+%for %%family in %%accounts.families
+ %%family:
+ %for %%user in %%accounts['family_' + %%family]['users_' + %%family]['ldap_user_mail_' + %%family]
+ - cn=%%user,%%families
+ %end for
+%end for
diff --git a/seed/openldap/templates/users.ldif b/seed/openldap/templates/users.ldif
index 03c6f1d3..057c5bcc 100644
--- a/seed/openldap/templates/users.ldif
+++ b/seed/openldap/templates/users.ldif
@@ -1,3 +1,4 @@
+%set name_family = 'gnunux'
# BaseDN
%set groups = {}
dn: %%ldapclient_base_dn
@@ -11,13 +12,21 @@ objectClass: organizationalUnit
%end if
# Remote
+%set %%acc = []
+%for %%idx in %%range(3)
+ %set %%name = 'remote_test' + %%str(%%idx)
+%%acc.append(('cn=' + %%name + ',' + %%ldapclient_base_dn, %%name, %%get_password(server_name=%%domain_name_eth0, username=%%name, description="remote account", type="cleartext", hide=%%hide_secret, temporary=True)))%slurp
+%end for
%for %%remote in %%accounts.remotes
%set %%name = %%normalize_family(%%remote)
-dn: %%accounts['remote_' + %%name]['dn_' + %%name]
+%%acc.append((%%accounts['remote_' + %%name]['dn_' + %%name], %%remote, %%accounts['remote_' + %%name]['password_' + %%name]))%slurp
+%end for
+%for %%dn, %%remote, %%password in %%acc
+dn: %%dn
cn: %%remote
sn: %%remote
uid: %%remote
-userPassword:: %%ssha_encode(%%accounts['remote_' + %%name]['password_' + %%name])
+userPassword:: %%ssha_encode(%%password)
objectClass: top
objectClass: inetOrgPerson
diff --git a/seed/openldap/templates/users_mod.ldif b/seed/openldap/templates/users_mod.ldif
index 9ff3b249..f4fce200 100644
--- a/seed/openldap/templates/users_mod.ldif
+++ b/seed/openldap/templates/users_mod.ldif
@@ -1,16 +1,27 @@
+%set groups = {}
# Remote
+%set %%acc = []
+%for %%idx in %%range(3)
+ %set %%name = 'remote_test' + %%str(%%idx)
+%%acc.append(('cn=' + %%name + ',' + %%ldapclient_base_dn, %%get_password(server_name=%%domain_name_eth0, username=%%name, description="remote account", type="cleartext", hide=%%hide_secret, temporary=True)))%slurp
+%end for
%for %%remote in %%accounts.remotes
%set %%name = %%normalize_family(%%remote)
-dn: %%accounts['remote_' + %%name]['dn_' + %%name]
+%%acc.append((%%accounts['remote_' + %%name]['dn_' + %%name], %%accounts['remote_' + %%name]['password_' + %%name]))%slurp
+%end for
+%for %%dn, %%password in %%acc
+dn: %%dn
changetype: modify
replace: userPassword
-userPassword:: %%ssha_encode(%%accounts['remote_' + %%name]['password_' + %%name])
+userPassword:: %%ssha_encode(%%password)
%end for
# Users
%set %%users = %%ldap_user_dn
%for %%user in %%accounts.users.ldap_user_mail
-dn: cn=%%user,%%users
+%set %%userdn = 'cn=' + %%user + ',' + %%users
+%%groups.setdefault('users', []).append(%%userdn)%slurp
+dn: %%userdn
changetype: modify
#add: objectClass
#objectClass: inetLocalMailRecipient
@@ -28,7 +39,9 @@ mailLocalAddress: %%alias
%for %%family in %%accounts.families
%set %%families = %%calc_ldapclient_base_dn(%%ldapclient_base_dn, %%family)
%for %%user in %%accounts['family_' + %%family]['users_' + %%family]['ldap_user_mail_' + %%family]
-dn: cn=%%user,%%families
+%set %%userdn = 'cn=' + %%user + ',' + %%families
+%%groups.setdefault(%%family, []).append(%%userdn)%slurp
+dn: %%userdn
changetype: modify
#add: objectClass
#objectClass: inetLocalMailRecipient
@@ -43,3 +56,14 @@ mailLocalAddress: %%alias
%end for
%end for
+# Groups
+%set %%groupdn = %%ldap_group_dn
+%for %%group, %%members in %%groups.items()
+dn: cn=%%group,%%groupdn
+changetype: modify
+replace: member
+ %for %%member in %%members
+member: %%member
+ %end for
+
+%end for
diff --git a/seed/openldap/tests/test_openldap.py b/seed/openldap/tests/test_openldap.py
new file mode 100644
index 00000000..62a89770
--- /dev/null
+++ b/seed/openldap/tests/test_openldap.py
@@ -0,0 +1,162 @@
+from yaml import load, SafeLoader
+from os import environ
+from pytest import raises
+from ldap import NO_SUCH_OBJECT, INVALID_CREDENTIALS, OPT_X_TLS_NEVER, OPT_X_TLS_REQUIRE_CERT, SCOPE_SUBTREE, set_option, initialize
+
+
+def test_ldap_wrong_password():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ with raises(INVALID_CREDENTIALS):
+ l.simple_bind_s(data['admin_dn'], 'a')
+
+
+def test_ldap_admin():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ l.simple_bind_s(data['admin_dn'], data['admin_password'])
+
+ assert l.search_s(data['base_account_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+
+
+def test_ldap_accounts():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ l.simple_bind_s(data['admin_dn'], data['admin_password'])
+
+ for dn, attrs in l.search_s(data['base_account_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn']):
+ cn = attrs['cn'][0].decode()
+ assert cn in data['users']
+ assert data['users'][cn] == dn
+ del data['users'][cn]
+
+ # all users are retrieved
+ assert not data['users']
+
+
+def test_ldap_groups():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ l.simple_bind_s(data['admin_dn'], data['admin_password'])
+
+ for dn, attrs in l.search_s(data['base_group_dn'], SCOPE_SUBTREE,'(objectClass=groupOfNames)',['cn', 'member']):
+ cn = attrs['cn'][0].decode()
+ assert cn in data['groups']
+ assert set(data['groups'][cn]) == set([member.decode() for member in attrs['member']])
+ del data['groups'][cn]
+
+ # all groups are retrieved
+ assert not data['groups']
+
+
+def test_ldap_user():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ l.simple_bind_s(data['user_dn'], data['user_password'])
+
+
+def test_ldap_user_family():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ l.simple_bind_s(data['user_family_dn'], data['user_family_password'])
+
+
+def test_ldap_remote_auth():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ l.simple_bind_s(data['remote0'], data['remote_password0'])
+ l.simple_bind_s(data['remote1'], data['remote_password1'])
+ l.simple_bind_s(data['remote2'], data['remote_password2'])
+
+
+def test_ldap_remote_base():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ #
+ l.simple_bind_s(data['remote0'], data['remote_password0'])
+ with raises(NO_SUCH_OBJECT):
+ l.search_s(data['base_account_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+ #
+ l.simple_bind_s(data['remote1'], data['remote_password1'])
+ l.search_s(data['base_account_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+ #
+ l.simple_bind_s(data['remote2'], data['remote_password2'])
+ with raises(NO_SUCH_OBJECT):
+ l.search_s(data['base_account_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+
+
+def test_ldap_remote_users():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ #
+ l.simple_bind_s(data['remote0'], data['remote_password0'])
+ l.search_s(data['base_user_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+ #
+ l.simple_bind_s(data['remote1'], data['remote_password1'])
+ l.search_s(data['base_user_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+ #
+ l.simple_bind_s(data['remote2'], data['remote_password2'])
+ with raises(NO_SUCH_OBJECT):
+ l.search_s(data['base_user_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+
+
+def test_ldap_remote_family():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ #
+ l.simple_bind_s(data['remote0'], data['remote_password0'])
+ with raises(NO_SUCH_OBJECT):
+ l.search_s(data['base_family_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+ #
+ l.simple_bind_s(data['remote1'], data['remote_password1'])
+ l.search_s(data['base_family_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+ #
+ l.simple_bind_s(data['remote2'], data['remote_password2'])
+ l.search_s(data['base_family_dn'], SCOPE_SUBTREE,'(objectClass=inetOrgPerson)',['cn'])
+
+
+def test_ldap_remote_group():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/openldap.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ set_option(OPT_X_TLS_REQUIRE_CERT, OPT_X_TLS_NEVER)
+ l = initialize(f'ldaps://{data["address"]}')
+ #
+ l.simple_bind_s(data['remote0'], data['remote_password0'])
+ l.search_s(data['base_group_dn'], SCOPE_SUBTREE,'(objectClass=groupOfNames)',['cn'])
+ #
+ l.simple_bind_s(data['remote1'], data['remote_password1'])
+ l.search_s(data['base_group_dn'], SCOPE_SUBTREE,'(objectClass=groupOfNames)',['cn'])
+ #
+ l.simple_bind_s(data['remote2'], data['remote_password2'])
+ l.search_s(data['base_group_dn'], SCOPE_SUBTREE,'(objectClass=groupOfNames)',['cn'])