mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-09 19:13:26 +03:00

Previously, if you set group memberships in both locations, they will get replaced by the ones in extraJsonFile, which is unexpected as it kicks users from the group. Now the state files get merged recursively, including the arrays.
562 lines
23 KiB
Nix
562 lines
23 KiB
Nix
{ pkgs, ... }:
|
|
let
|
|
certs = import ./common/acme/server/snakeoil-certs.nix;
|
|
serverDomain = certs.domain;
|
|
|
|
# copy certs to store to work around mount namespacing
|
|
certsPath = pkgs.runCommandNoCC "snakeoil-certs" { } ''
|
|
mkdir $out
|
|
cp ${certs."${serverDomain}".cert} $out/snakeoil.crt
|
|
cp ${certs."${serverDomain}".key} $out/snakeoil.key
|
|
'';
|
|
|
|
provisionAdminPassword = "very-strong-password-for-admin";
|
|
provisionIdmAdminPassword = "very-strong-password-for-idm-admin";
|
|
provisionIdmAdminPassword2 = "very-strong-alternative-password-for-idm-admin";
|
|
in
|
|
{
|
|
name = "kanidm-provisioning";
|
|
meta.maintainers = with pkgs.lib.maintainers; [ oddlama ];
|
|
|
|
nodes.provision =
|
|
{ pkgs, lib, ... }:
|
|
{
|
|
services.kanidm = {
|
|
package = pkgs.kanidmWithSecretProvisioning_1_6;
|
|
enableServer = true;
|
|
serverSettings = {
|
|
origin = "https://${serverDomain}";
|
|
domain = serverDomain;
|
|
bindaddress = "[::]:443";
|
|
ldapbindaddress = "[::1]:636";
|
|
tls_chain = "${certsPath}/snakeoil.crt";
|
|
tls_key = "${certsPath}/snakeoil.key";
|
|
};
|
|
# So we can check whether provisioning did what we wanted
|
|
enableClient = true;
|
|
clientSettings = {
|
|
uri = "https://${serverDomain}";
|
|
verify_ca = true;
|
|
verify_hostnames = true;
|
|
};
|
|
};
|
|
|
|
specialisation.credentialProvision.configuration =
|
|
{ ... }:
|
|
{
|
|
services.kanidm.provision = lib.mkForce {
|
|
enable = true;
|
|
adminPasswordFile = pkgs.writeText "admin-pw" provisionAdminPassword;
|
|
idmAdminPasswordFile = pkgs.writeText "idm-admin-pw" provisionIdmAdminPassword;
|
|
};
|
|
};
|
|
|
|
specialisation.changedCredential.configuration =
|
|
{ ... }:
|
|
{
|
|
services.kanidm.provision = lib.mkForce {
|
|
enable = true;
|
|
idmAdminPasswordFile = pkgs.writeText "idm-admin-pw" provisionIdmAdminPassword2;
|
|
};
|
|
};
|
|
|
|
specialisation.addEntities.configuration =
|
|
{ ... }:
|
|
{
|
|
services.kanidm.provision = lib.mkForce {
|
|
enable = true;
|
|
# Test whether credential recovery works without specific idmAdmin password
|
|
#idmAdminPasswordFile =
|
|
|
|
groups.supergroup1 = {
|
|
members = [ "testgroup1" ];
|
|
};
|
|
|
|
groups.testgroup1 = { };
|
|
|
|
persons.testuser1 = {
|
|
displayName = "Test User";
|
|
legalName = "Jane Doe";
|
|
mailAddresses = [ "jane.doe@example.com" ];
|
|
groups = [
|
|
"testgroup1"
|
|
"service1-access"
|
|
];
|
|
};
|
|
|
|
persons.testuser2 = {
|
|
displayName = "Powerful Test User";
|
|
legalName = "Ryouiki Tenkai";
|
|
groups = [ "service1-admin" ];
|
|
};
|
|
|
|
groups.service1-access = { };
|
|
groups.service1-admin = { };
|
|
systems.oauth2.service1 = {
|
|
displayName = "Service One";
|
|
originUrl = "https://one.example.com/";
|
|
originLanding = "https://one.example.com/landing";
|
|
basicSecretFile = pkgs.writeText "bs-service1" "very-strong-secret-for-service1";
|
|
scopeMaps.service1-access = [
|
|
"openid"
|
|
"email"
|
|
"profile"
|
|
];
|
|
supplementaryScopeMaps.service1-admin = [ "admin" ];
|
|
claimMaps.groups = {
|
|
valuesByGroup.service1-admin = [ "admin" ];
|
|
};
|
|
};
|
|
|
|
systems.oauth2.service2 = {
|
|
displayName = "Service Two";
|
|
originUrl = "https://two.example.com/";
|
|
originLanding = "https://landing2.example.com/";
|
|
# Test not setting secret
|
|
# basicSecretFile =
|
|
allowInsecureClientDisablePkce = true;
|
|
preferShortUsername = true;
|
|
};
|
|
};
|
|
};
|
|
|
|
specialisation.changeAttributes.configuration =
|
|
{ ... }:
|
|
{
|
|
services.kanidm.provision = lib.mkForce {
|
|
enable = true;
|
|
# Changing admin credentials at any time should not be a problem:
|
|
idmAdminPasswordFile = pkgs.writeText "idm-admin-pw" provisionIdmAdminPassword;
|
|
|
|
groups.supergroup1 = {
|
|
#members = ["testgroup1"];
|
|
};
|
|
|
|
groups.testgroup1 = { };
|
|
|
|
persons.testuser1 = {
|
|
displayName = "Test User (changed)";
|
|
legalName = "Jane Doe (changed)";
|
|
mailAddresses = [
|
|
"jane.doe@example.com"
|
|
"second.doe@example.com"
|
|
];
|
|
groups = [
|
|
#"testgroup1"
|
|
"service1-access"
|
|
];
|
|
};
|
|
|
|
persons.testuser2 = {
|
|
displayName = "Powerful Test User (changed)";
|
|
legalName = "Ryouiki Tenkai (changed)";
|
|
groups = [ "service1-admin" ];
|
|
};
|
|
|
|
groups.service1-access = { };
|
|
groups.service1-admin = { };
|
|
systems.oauth2.service1 = {
|
|
displayName = "Service One (changed)";
|
|
# multiple origin urls
|
|
originUrl = [
|
|
"https://changed-one.example.com/"
|
|
"https://changed-one.example.org/"
|
|
];
|
|
originLanding = "https://changed-one.example.com/landing-changed";
|
|
basicSecretFile = pkgs.writeText "bs-service1" "changed-very-strong-secret-for-service1";
|
|
scopeMaps.service1-access = [
|
|
"openid"
|
|
"email"
|
|
#"profile"
|
|
];
|
|
supplementaryScopeMaps.service1-admin = [ "adminchanged" ];
|
|
claimMaps.groups = {
|
|
valuesByGroup.service1-admin = [ "adminchanged" ];
|
|
};
|
|
};
|
|
|
|
systems.oauth2.service2 = {
|
|
displayName = "Service Two (changed)";
|
|
originUrl = "https://changed-two.example.com/";
|
|
originLanding = "https://changed-landing2.example.com/";
|
|
# Test not setting secret
|
|
# basicSecretFile =
|
|
allowInsecureClientDisablePkce = false;
|
|
preferShortUsername = false;
|
|
};
|
|
};
|
|
};
|
|
|
|
specialisation.removeAttributes.configuration =
|
|
{ ... }:
|
|
{
|
|
services.kanidm.provision = lib.mkForce {
|
|
enable = true;
|
|
idmAdminPasswordFile = pkgs.writeText "idm-admin-pw" provisionIdmAdminPassword;
|
|
|
|
groups.supergroup1 = { };
|
|
|
|
persons.testuser1 = {
|
|
displayName = "Test User (changed)";
|
|
};
|
|
|
|
persons.testuser2 = {
|
|
displayName = "Powerful Test User (changed)";
|
|
groups = [ "service1-admin" ];
|
|
};
|
|
|
|
groups.service1-access = { };
|
|
groups.service1-admin = { };
|
|
systems.oauth2.service1 = {
|
|
displayName = "Service One (changed)";
|
|
originUrl = "https://changed-one.example.com/";
|
|
originLanding = "https://changed-one.example.com/landing-changed";
|
|
basicSecretFile = pkgs.writeText "bs-service1" "changed-very-strong-secret-for-service1";
|
|
# Removing maps requires setting them to the empty list
|
|
scopeMaps.service1-access = [ ];
|
|
supplementaryScopeMaps.service1-admin = [ ];
|
|
};
|
|
|
|
systems.oauth2.service2 = {
|
|
displayName = "Service Two (changed)";
|
|
originUrl = "https://changed-two.example.com/";
|
|
originLanding = "https://changed-landing2.example.com/";
|
|
};
|
|
};
|
|
};
|
|
|
|
specialisation.removeEntities.configuration =
|
|
{ ... }:
|
|
{
|
|
services.kanidm.provision = lib.mkForce {
|
|
enable = true;
|
|
idmAdminPasswordFile = pkgs.writeText "idm-admin-pw" provisionIdmAdminPassword;
|
|
};
|
|
};
|
|
|
|
specialisation.extraJsonFile.configuration =
|
|
{ ... }:
|
|
{
|
|
services.kanidm.provision = lib.mkForce {
|
|
enable = true;
|
|
idmAdminPasswordFile = pkgs.writeText "idm-admin-pw" provisionIdmAdminPassword;
|
|
|
|
extraJsonFile = pkgs.writeText "extra-json.json" (
|
|
builtins.toJSON {
|
|
persons.testuser2.displayName = "Test User 2";
|
|
groups.testgroup1.members = [ "testuser2" ];
|
|
}
|
|
);
|
|
|
|
groups.testgroup1 = { };
|
|
|
|
persons.testuser1 = {
|
|
displayName = "Test User 1";
|
|
groups = [ "testgroup1" ];
|
|
};
|
|
};
|
|
};
|
|
|
|
security.pki.certificateFiles = [ certs.ca.cert ];
|
|
|
|
networking.hosts."::1" = [ serverDomain ];
|
|
networking.firewall.allowedTCPPorts = [ 443 ];
|
|
|
|
users.users.kanidm.shell = pkgs.bashInteractive;
|
|
|
|
environment.systemPackages = with pkgs; [
|
|
kanidm
|
|
openldap
|
|
ripgrep
|
|
jq
|
|
];
|
|
};
|
|
|
|
testScript =
|
|
{ nodes, ... }:
|
|
let
|
|
# We need access to the config file in the test script.
|
|
filteredConfig = pkgs.lib.converge (pkgs.lib.filterAttrsRecursive (
|
|
_: v: v != null
|
|
)) nodes.provision.services.kanidm.serverSettings;
|
|
serverConfigFile = (pkgs.formats.toml { }).generate "server.toml" filteredConfig;
|
|
|
|
specialisations = "${nodes.provision.system.build.toplevel}/specialisation";
|
|
in
|
|
''
|
|
import re
|
|
|
|
def assert_contains(haystack, needle):
|
|
if needle not in haystack:
|
|
print("The haystack that will cause the following exception is:")
|
|
print("---")
|
|
print(haystack)
|
|
print("---")
|
|
raise Exception(f"Expected string '{needle}' was not found")
|
|
|
|
def assert_matches(haystack, expr):
|
|
if not re.search(expr, haystack):
|
|
print("The haystack that will cause the following exception is:")
|
|
print("---")
|
|
print(haystack)
|
|
print("---")
|
|
raise Exception(f"Expected regex '{expr}' did not match")
|
|
|
|
def assert_lacks(haystack, needle):
|
|
if needle in haystack:
|
|
print("The haystack that will cause the following exception is:")
|
|
print("---")
|
|
print(haystack, end="")
|
|
print("---")
|
|
raise Exception(f"Unexpected string '{needle}' was found")
|
|
|
|
provision.start()
|
|
|
|
def provision_login(pw):
|
|
provision.wait_for_unit("kanidm.service")
|
|
provision.wait_until_succeeds("curl -Lsf https://${serverDomain} | grep Kanidm")
|
|
if pw is None:
|
|
pw = provision.succeed("su - kanidm -c 'kanidmd recover-account -c ${serverConfigFile} idm_admin 2>&1 | rg -o \'[A-Za-z0-9]{48}\' '").strip().removeprefix("'").removesuffix("'")
|
|
out = provision.succeed(f"KANIDM_PASSWORD={pw} kanidm login -D idm_admin")
|
|
assert_contains(out, "Login Success for idm_admin")
|
|
|
|
with subtest("Test Provisioning - setup"):
|
|
provision_login(None)
|
|
provision.succeed("kanidm logout -D idm_admin")
|
|
|
|
with subtest("Test Provisioning - credentialProvision"):
|
|
provision.succeed('${specialisations}/credentialProvision/bin/switch-to-configuration test')
|
|
provision_login("${provisionIdmAdminPassword}")
|
|
|
|
# Make sure neither password is logged
|
|
provision.fail("journalctl --since -10m --unit kanidm.service --grep '${provisionAdminPassword}'")
|
|
provision.fail("journalctl --since -10m --unit kanidm.service --grep '${provisionIdmAdminPassword}'")
|
|
|
|
# Test provisioned admin pw
|
|
out = provision.succeed("KANIDM_PASSWORD=${provisionAdminPassword} kanidm login -D admin")
|
|
assert_contains(out, "Login Success for admin")
|
|
provision.succeed("kanidm logout -D admin")
|
|
provision.succeed("kanidm logout -D idm_admin")
|
|
|
|
with subtest("Test Provisioning - changedCredential"):
|
|
provision.succeed('${specialisations}/changedCredential/bin/switch-to-configuration test')
|
|
provision_login("${provisionIdmAdminPassword2}")
|
|
provision.succeed("kanidm logout -D idm_admin")
|
|
|
|
with subtest("Test Provisioning - addEntities"):
|
|
provision.succeed('${specialisations}/addEntities/bin/switch-to-configuration test')
|
|
# Unspecified idm admin password
|
|
provision_login(None)
|
|
|
|
out = provision.succeed("kanidm group get testgroup1")
|
|
assert_contains(out, "name: testgroup1")
|
|
|
|
out = provision.succeed("kanidm group get supergroup1")
|
|
assert_contains(out, "name: supergroup1")
|
|
assert_contains(out, "member: testgroup1")
|
|
|
|
out = provision.succeed("kanidm person get testuser1")
|
|
assert_contains(out, "name: testuser1")
|
|
assert_contains(out, "displayname: Test User")
|
|
assert_contains(out, "legalname: Jane Doe")
|
|
assert_contains(out, "mail: jane.doe@example.com")
|
|
assert_contains(out, "memberof: testgroup1")
|
|
assert_contains(out, "memberof: service1-access")
|
|
|
|
out = provision.succeed("kanidm person get testuser2")
|
|
assert_contains(out, "name: testuser2")
|
|
assert_contains(out, "displayname: Powerful Test User")
|
|
assert_contains(out, "legalname: Ryouiki Tenkai")
|
|
assert_contains(out, "memberof: service1-admin")
|
|
assert_lacks(out, "mail:")
|
|
|
|
out = provision.succeed("kanidm group get service1-access")
|
|
assert_contains(out, "name: service1-access")
|
|
|
|
out = provision.succeed("kanidm group get service1-admin")
|
|
assert_contains(out, "name: service1-admin")
|
|
|
|
out = provision.succeed("kanidm system oauth2 get service1")
|
|
assert_contains(out, "name: service1")
|
|
assert_contains(out, "displayname: Service One")
|
|
assert_contains(out, "oauth2_rs_origin: https://one.example.com/")
|
|
assert_contains(out, "oauth2_rs_origin_landing: https://one.example.com/landing")
|
|
assert_matches(out, 'oauth2_rs_scope_map: service1-access.*{"email", "openid", "profile"}')
|
|
assert_matches(out, 'oauth2_rs_sup_scope_map: service1-admin.*{"admin"}')
|
|
assert_matches(out, 'oauth2_rs_claim_map: groups:.*"admin"')
|
|
|
|
out = provision.succeed("kanidm system oauth2 show-basic-secret service1")
|
|
assert_contains(out, "very-strong-secret-for-service1")
|
|
|
|
out = provision.succeed("kanidm system oauth2 get service2")
|
|
assert_contains(out, "name: service2")
|
|
assert_contains(out, "displayname: Service Two")
|
|
assert_contains(out, "oauth2_rs_origin: https://two.example.com/")
|
|
assert_contains(out, "oauth2_rs_origin_landing: https://landing2.example.com/")
|
|
assert_contains(out, "oauth2_allow_insecure_client_disable_pkce: true")
|
|
assert_contains(out, "oauth2_prefer_short_username: true")
|
|
|
|
provision.succeed("kanidm logout -D idm_admin")
|
|
|
|
with subtest("Test Provisioning - changeAttributes"):
|
|
provision.succeed('${specialisations}/changeAttributes/bin/switch-to-configuration test')
|
|
provision_login("${provisionIdmAdminPassword}")
|
|
|
|
out = provision.succeed("kanidm group get testgroup1")
|
|
assert_contains(out, "name: testgroup1")
|
|
|
|
out = provision.succeed("kanidm group get supergroup1")
|
|
assert_contains(out, "name: supergroup1")
|
|
assert_lacks(out, "member: testgroup1")
|
|
|
|
out = provision.succeed("kanidm person get testuser1")
|
|
assert_contains(out, "name: testuser1")
|
|
assert_contains(out, "displayname: Test User (changed)")
|
|
assert_contains(out, "legalname: Jane Doe (changed)")
|
|
assert_contains(out, "mail: jane.doe@example.com")
|
|
assert_contains(out, "mail: second.doe@example.com")
|
|
assert_lacks(out, "memberof: testgroup1")
|
|
assert_contains(out, "memberof: service1-access")
|
|
|
|
out = provision.succeed("kanidm person get testuser2")
|
|
assert_contains(out, "name: testuser2")
|
|
assert_contains(out, "displayname: Powerful Test User (changed)")
|
|
assert_contains(out, "legalname: Ryouiki Tenkai (changed)")
|
|
assert_contains(out, "memberof: service1-admin")
|
|
assert_lacks(out, "mail:")
|
|
|
|
out = provision.succeed("kanidm group get service1-access")
|
|
assert_contains(out, "name: service1-access")
|
|
|
|
out = provision.succeed("kanidm group get service1-admin")
|
|
assert_contains(out, "name: service1-admin")
|
|
|
|
out = provision.succeed("kanidm system oauth2 get service1")
|
|
assert_contains(out, "name: service1")
|
|
assert_contains(out, "displayname: Service One (changed)")
|
|
assert_contains(out, "oauth2_rs_origin: https://changed-one.example.com/")
|
|
assert_contains(out, "oauth2_rs_origin: https://changed-one.example.org/")
|
|
assert_contains(out, "oauth2_rs_origin_landing: https://changed-one.example.com/landing")
|
|
assert_matches(out, 'oauth2_rs_scope_map: service1-access.*{"email", "openid"}')
|
|
assert_matches(out, 'oauth2_rs_sup_scope_map: service1-admin.*{"adminchanged"}')
|
|
assert_matches(out, 'oauth2_rs_claim_map: groups:.*"adminchanged"')
|
|
|
|
out = provision.succeed("kanidm system oauth2 show-basic-secret service1")
|
|
assert_contains(out, "changed-very-strong-secret-for-service1")
|
|
|
|
out = provision.succeed("kanidm system oauth2 get service2")
|
|
assert_contains(out, "name: service2")
|
|
assert_contains(out, "displayname: Service Two (changed)")
|
|
assert_contains(out, "oauth2_rs_origin: https://changed-two.example.com/")
|
|
assert_contains(out, "oauth2_rs_origin_landing: https://changed-landing2.example.com/")
|
|
assert_lacks(out, "oauth2_allow_insecure_client_disable_pkce: true")
|
|
assert_lacks(out, "oauth2_prefer_short_username: true")
|
|
|
|
provision.succeed("kanidm logout -D idm_admin")
|
|
|
|
with subtest("Test Provisioning - removeAttributes"):
|
|
provision.succeed('${specialisations}/removeAttributes/bin/switch-to-configuration test')
|
|
provision_login("${provisionIdmAdminPassword}")
|
|
|
|
out = provision.succeed("kanidm group get testgroup1")
|
|
assert_lacks(out, "name: testgroup1")
|
|
|
|
out = provision.succeed("kanidm group get supergroup1")
|
|
assert_contains(out, "name: supergroup1")
|
|
assert_lacks(out, "member: testgroup1")
|
|
|
|
out = provision.succeed("kanidm person get testuser1")
|
|
assert_contains(out, "name: testuser1")
|
|
assert_contains(out, "displayname: Test User (changed)")
|
|
assert_lacks(out, "legalname: Jane Doe (changed)")
|
|
assert_lacks(out, "mail: jane.doe@example.com")
|
|
assert_lacks(out, "mail: second.doe@example.com")
|
|
assert_lacks(out, "memberof: testgroup1")
|
|
assert_lacks(out, "memberof: service1-access")
|
|
|
|
out = provision.succeed("kanidm person get testuser2")
|
|
assert_contains(out, "name: testuser2")
|
|
assert_contains(out, "displayname: Powerful Test User (changed)")
|
|
assert_lacks(out, "legalname: Ryouiki Tenkai (changed)")
|
|
assert_contains(out, "memberof: service1-admin")
|
|
assert_lacks(out, "mail:")
|
|
|
|
out = provision.succeed("kanidm group get service1-access")
|
|
assert_contains(out, "name: service1-access")
|
|
|
|
out = provision.succeed("kanidm group get service1-admin")
|
|
assert_contains(out, "name: service1-admin")
|
|
|
|
out = provision.succeed("kanidm system oauth2 get service1")
|
|
assert_contains(out, "name: service1")
|
|
assert_contains(out, "displayname: Service One (changed)")
|
|
assert_contains(out, "oauth2_rs_origin: https://changed-one.example.com/")
|
|
assert_lacks(out, "oauth2_rs_origin: https://changed-one.example.org/")
|
|
assert_contains(out, "oauth2_rs_origin_landing: https://changed-one.example.com/landing")
|
|
assert_lacks(out, "oauth2_rs_scope_map")
|
|
assert_lacks(out, "oauth2_rs_sup_scope_map")
|
|
assert_lacks(out, "oauth2_rs_claim_map")
|
|
|
|
out = provision.succeed("kanidm system oauth2 show-basic-secret service1")
|
|
assert_contains(out, "changed-very-strong-secret-for-service1")
|
|
|
|
out = provision.succeed("kanidm system oauth2 get service2")
|
|
assert_contains(out, "name: service2")
|
|
assert_contains(out, "displayname: Service Two (changed)")
|
|
assert_contains(out, "oauth2_rs_origin: https://changed-two.example.com/")
|
|
assert_contains(out, "oauth2_rs_origin_landing: https://changed-landing2.example.com/")
|
|
assert_lacks(out, "oauth2_allow_insecure_client_disable_pkce: true")
|
|
assert_lacks(out, "oauth2_prefer_short_username: true")
|
|
|
|
provision.succeed("kanidm logout -D idm_admin")
|
|
|
|
with subtest("Test Provisioning - removeEntities"):
|
|
provision.succeed('${specialisations}/removeEntities/bin/switch-to-configuration test')
|
|
provision_login("${provisionIdmAdminPassword}")
|
|
|
|
out = provision.succeed("kanidm group get testgroup1")
|
|
assert_lacks(out, "name: testgroup1")
|
|
|
|
out = provision.succeed("kanidm group get supergroup1")
|
|
assert_lacks(out, "name: supergroup1")
|
|
|
|
out = provision.succeed("kanidm person get testuser1")
|
|
assert_lacks(out, "name: testuser1")
|
|
|
|
out = provision.succeed("kanidm person get testuser2")
|
|
assert_lacks(out, "name: testuser2")
|
|
|
|
out = provision.succeed("kanidm group get service1-access")
|
|
assert_lacks(out, "name: service1-access")
|
|
|
|
out = provision.succeed("kanidm group get service1-admin")
|
|
assert_lacks(out, "name: service1-admin")
|
|
|
|
out = provision.succeed("kanidm system oauth2 get service1")
|
|
assert_lacks(out, "name: service1")
|
|
|
|
out = provision.succeed("kanidm system oauth2 get service2")
|
|
assert_lacks(out, "name: service2")
|
|
|
|
provision.succeed("kanidm logout -D idm_admin")
|
|
|
|
with subtest("Test Provisioning - extraJsonFile"):
|
|
provision.succeed('${specialisations}/extraJsonFile/bin/switch-to-configuration test')
|
|
provision_login("${provisionIdmAdminPassword}")
|
|
|
|
out = provision.succeed("kanidm group get testgroup1")
|
|
assert_contains(out, "name: testgroup1")
|
|
|
|
out = provision.succeed("kanidm person get testuser1")
|
|
assert_contains(out, "name: testuser1")
|
|
|
|
out = provision.succeed("kanidm person get testuser2")
|
|
assert_contains(out, "name: testuser2")
|
|
|
|
out = provision.succeed("kanidm group get testgroup1")
|
|
assert_contains(out, "member: testuser1")
|
|
assert_contains(out, "member: testuser2")
|
|
|
|
provision.succeed("kanidm logout -D idm_admin")
|
|
'';
|
|
}
|