1
0
Fork 0
selfhostblocks/_disnix/tests/unit/keycloak.nix

295 lines
8.2 KiB
Nix

# to run these tests:
# nix-instantiate --eval --strict . -A tests.keycloak
{ lib
, stdenv
, pkgs
}:
let
configcreator = pkgs.callPackage ./../../keycloak-cli-config/configcreator.nix {};
# Taken from https://github.com/NixOS/nixpkgs/blob/master/lib/attrsets.nix
updateManyAttrsByPath =
with builtins;
with lib.lists;
let
# When recursing into attributes, instead of updating the `path` of each
# update using `tail`, which needs to allocate an entirely new list,
# we just pass a prefix length to use and make sure to only look at the
# path without the prefix length, so that we can reuse the original list
# entries.
go = prefixLength: hasValue: value: updates:
let
# Splits updates into ones on this level (split.right)
# And ones on levels further down (split.wrong)
split = partition (el: length el.path == prefixLength) updates;
# Groups updates on further down levels into the attributes they modify
nested = groupBy (el: elemAt el.path prefixLength) split.wrong;
# Applies only nested modification to the input value
withNestedMods =
# Return the value directly if we don't have any nested modifications
if split.wrong == [] then
if hasValue then value
else
# Throw an error if there is no value. This `head` call here is
# safe, but only in this branch since `go` could only be called
# with `hasValue == false` for nested updates, in which case
# it's also always called with at least one update
let updatePath = (head split.right).path; in
throw
( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' does "
+ "not exist in the given value, but the first update to this "
+ "path tries to access the existing value.")
else
# If there are nested modifications, try to apply them to the value
if ! hasValue then
# But if we don't have a value, just use an empty attribute set
# as the value, but simplify the code a bit
mapAttrs (name: go (prefixLength + 1) false null) nested
else if isAttrs value then
# If we do have a value and it's an attribute set, override it
# with the nested modifications
value //
mapAttrs (name: go (prefixLength + 1) (value ? ${name}) value.${name}) nested
else
# However if it's not an attribute set, we can't apply the nested
# modifications, throw an error
let updatePath = (head split.wrong).path; in
throw
( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' needs to "
+ "be updated, but path '${showAttrPath (take prefixLength updatePath)}' "
+ "of the given value is not an attribute set, so we can't "
+ "update an attribute inside of it.");
# We get the final result by applying all the updates on this level
# after having applied all the nested updates
# We use foldl instead of foldl' so that in case of multiple updates,
# intermediate values aren't evaluated if not needed
in foldl (acc: el: el.update acc) withNestedMods split.right;
in updates: value: go 0 true value updates;
in
with lib.attrsets;
lib.runTests {
testConfigEmpty = {
expr = configcreator {
realm = "myrealm";
domain = "domain.com";
};
expected = {
id = "myrealm";
realm = "myrealm";
enabled = true;
clients = [];
groups = [];
roles = {
client = {};
realm = [];
};
users = [];
};
};
testConfigRole = {
expr = configcreator {
realm = "myrealm";
domain = "domain.com";
roles = {
user = [];
admin = ["user"];
};
};
expected = {
id = "myrealm";
realm = "myrealm";
enabled = true;
clients = [];
groups = [];
roles = {
realm = [
{
name = "admin";
composite = true;
composites = {
realm = ["user"];
};
}
{
name = "user";
composite = false;
}
];
client = {};
};
users = [];
};
};
testConfigClient = {
expr =
let
c = configcreator {
realm = "myrealm";
domain = "domain.com";
clients = {
myclient = {};
myclient2 = {
roles = ["uma"];
};
};
};
in
updateManyAttrsByPath [
{
path = [ "clients" ];
# We don't care about the value of the protocolMappers
# field because its value is hardcoded.
update = clients: map (filterAttrs (n: v: n != "protocolMappers")) clients;
}
] c;
expected = {
id = "myrealm";
realm = "myrealm";
enabled = true;
clients = [
{
clientId = "myclient";
rootUrl = "https://myclient.domain.com";
clientAuthenticatorType = "client-secret";
redirectUris = [
"https://myclient.domain.com/oauth2/callback"
];
webOrigins = [
"https://myclient.domain.com"
];
authorizationServicesEnabled = true;
serviceAccountsEnabled = true;
protocol = "openid-connect";
publicClient = false;
authorizationSettings = {
policyEnforcementMode = "ENFORCING";
resources = [];
policies = [];
};
}
{
clientId = "myclient2";
rootUrl = "https://myclient2.domain.com";
clientAuthenticatorType = "client-secret";
redirectUris = [
"https://myclient2.domain.com/oauth2/callback"
];
webOrigins = [
"https://myclient2.domain.com"
];
authorizationServicesEnabled = true;
serviceAccountsEnabled = true;
protocol = "openid-connect";
publicClient = false;
authorizationSettings = {
policyEnforcementMode = "ENFORCING";
resources = [];
policies = [];
};
}
];
groups = [];
roles = {
client = {
myclient = [];
myclient2 = [
{
name = "uma";
clientRole = true;
}
];
};
realm = [];
};
users = [];
};
};
testConfigUser = {
expr = configcreator {
realm = "myrealm";
domain = "domain.com";
users = {
me = {
email = "me@me.com";
firstName = null;
lastName = "Me";
realmRoles = [ "role" ];
};
};
};
expected = {
id = "myrealm";
realm = "myrealm";
enabled = true;
clients = [];
groups = [];
roles = {
client = {};
realm = [];
};
users = [
{
enabled = true;
username = "me";
email = "me@me.com";
emailVerified = true;
firstName = null;
lastName = "Me";
}
];
};
};
testConfigUserInitialPassword = {
expr = configcreator {
realm = "myrealm";
domain = "domain.com";
users = {
me = {
email = "me@me.com";
firstName = null;
lastName = "Me";
initialPassword = true;
};
};
};
expected = {
id = "myrealm";
realm = "myrealm";
enabled = true;
clients = [];
groups = [];
roles = {
client = {};
realm = [];
};
users = [
{
enabled = true;
username = "me";
email = "me@me.com";
emailVerified = true;
firstName = null;
lastName = "Me";
credentials = [
{
type = "password";
userLabel = "initial";
value = "$(keycloak.users.me.password)";
}
];
}
];
};
};
}