LDAP support: include BC support for the YAML based loading

Includes a refactoring of the configuration loader.
This commit is contained in:
Graham Christensen
2022-02-09 21:06:28 -05:00
parent 61d74a7194
commit f07fb7d279
16 changed files with 475 additions and 41 deletions

View File

@ -1,6 +1,7 @@
use strict;
use warnings;
use Setup;
use Hydra::Config;
my %ctx = test_init(hydra_config => q|
<hydra_notify>
@ -14,7 +15,7 @@ my %ctx = test_init(hydra_config => q|
require Hydra::Helper::Nix;
use Test2::V0;
is(Hydra::Helper::Nix::getHydraNotifyPrometheusConfig(Hydra::Helper::Nix::getHydraConfig()), {
is(Hydra::Helper::Nix::getHydraNotifyPrometheusConfig(getHydraConfig()), {
'listen_address' => "127.0.0.1",
'port' => 9199
}, "Reading specific configuration from the hydra.conf works");

View File

@ -1,6 +1,8 @@
use strict;
use warnings;
use Setup;
use Hydra::Config;
use Test2::V0;
my %ctx = test_init(
use_external_destination_store => 0,
@ -17,10 +19,7 @@ write_file($ctx{'tmpdir'} . "/bar.conf", q|
bar = baz
|);
require Hydra::Helper::Nix;
use Test2::V0;
is(Hydra::Helper::Nix::getHydraConfig(), {
is(getHydraConfig(), {
foo => { bar => "baz" }
}, "Nested includes work.");

View File

@ -0,0 +1,242 @@
use strict;
use warnings;
use Setup;
use Hydra::Config;
use Test2::V0;
my $tmpdir = File::Temp->newdir();
my $cfgfile = "$tmpdir/conf";
my $scratchCfgFile = "$tmpdir/hydra.scratch.conf";
my $ldapInHydraConfFile = "$tmpdir/hydra.empty.conf";
write_file($ldapInHydraConfFile, <<CONF);
<ldap>
<config>
<credential>
class = Password
</credential>
</config>
<role_mapping>
hydra_admin = admin
hydra_one_group_many_roles = create-projects
hydra_one_group_many_roles = cancel-build
</role_mapping>
</ldap>
CONF
my $ldapInHydraConf = Hydra::Config::loadConfig($ldapInHydraConfFile);
my $emptyHydraConfFile = "$tmpdir/hydra.empty.conf";
write_file($emptyHydraConfFile, "");
my $emptyHydraConf = Hydra::Config::loadConfig($emptyHydraConfFile);
my $ldapYamlFile = "$tmpdir/ldap.yaml";
write_file($ldapYamlFile, <<YAML);
credential:
class: Password
YAML
subtest "getLDAPConfig" => sub {
subtest "No ldap section and an env var gets us legacy data" => sub {
like(
warning {
is(
Hydra::Config::getLDAPConfig(
$emptyHydraConf,
( HYDRA_LDAP_CONFIG => $ldapYamlFile )
),
{
config => {
credential => {
class => "Password",
},
},
role_mapping => {
"hydra_admin" => [ "admin" ],
"hydra_bump-to-front" => [ "bump-to-front" ],
"hydra_cancel-build" => [ "cancel-build" ],
"hydra_create-projects" => [ "create-projects" ],
"hydra_restart-jobs" => [ "restart-jobs" ],
}
},
"The empty file and set env var make legacy mode active."
);
},
qr/configured to use LDAP via the HYDRA_LDAP_CONFIG/,
"Having the environment variable set warns."
);
};
subtest "An ldap section and no env var gets us normalized data" => sub {
is(
warns {
is(
Hydra::Config::getLDAPConfig(
$ldapInHydraConf,
()
),
{
config => {
credential => {
class => "Password",
},
},
role_mapping => {
"hydra_admin" => [ "admin" ],
"hydra_one_group_many_roles" => [ "create-projects", "cancel-build" ],
}
},
"The empty file and set env var make legacy mode active."
);
},
0,
"No warnings are issued for non-legacy LDAP support."
);
};
};
subtest "is_ldap_in_legacy_mode" => sub {
subtest "With the environment variable set and an empty hydra.conf" => sub {
like(
warning {
is(
Hydra::Config::is_ldap_in_legacy_mode(
$emptyHydraConf,
( HYDRA_LDAP_CONFIG => $ldapYamlFile )
),
1,
"The empty file and set env var make legacy mode active."
);
},
qr/configured to use LDAP via the HYDRA_LDAP_CONFIG/,
"Having the environment variable set warns."
);
};
subtest "With the environment variable set and LDAP specified in hydra.conf" => sub {
like(
dies {
Hydra::Config::is_ldap_in_legacy_mode(
$ldapInHydraConf,
( HYDRA_LDAP_CONFIG => $ldapYamlFile )
);
},
qr/HYDRA_LDAP_CONFIG is set, but config is also specified in hydra\.conf/,
"Having the environment variable set dies to avoid misconfiguration."
);
};
subtest "Without the environment variable set and an empty hydra.conf" => sub {
is(
warns {
is(
Hydra::Config::is_ldap_in_legacy_mode(
$emptyHydraConf,
()
),
0,
"The empty file and unset env var means non-legacy."
);
},
0,
"We should receive zero warnings."
);
};
subtest "Without the environment variable set and LDAP specified in hydra.conf" => sub {
is(
warns {
is(
Hydra::Config::is_ldap_in_legacy_mode(
$ldapInHydraConf,
()
),
0,
"The empty file and unset env var means non-legacy."
);
},
0,
"We should receive zero warnings."
);
};
};
subtest "get_legacy_ldap_config" => sub {
is(
Hydra::Config::get_legacy_ldap_config($ldapYamlFile),
{
config => {
credential => {
class => "Password",
},
},
role_mapping => {
"hydra_admin" => [ "admin" ],
"hydra_bump-to-front" => [ "bump-to-front" ],
"hydra_cancel-build" => [ "cancel-build" ],
"hydra_create-projects" => [ "create-projects" ],
"hydra_restart-jobs" => [ "restart-jobs" ],
}
},
"Legacy, default role maps are applied."
);
};
subtest "validate_roles" => sub {
ok(Hydra::Config::validate_roles([]), "An empty list is valid");
ok(Hydra::Config::validate_roles(Hydra::Config::valid_roles()), "All current roles are valid.");
like(
dies { Hydra::Config::validate_roles([""]) },
qr/Invalid roles: ''./,
"Invalid roles are failing"
);
like(
dies { Hydra::Config::validate_roles(["foo", "bar"]) },
qr/Invalid roles: 'foo', 'bar'./,
"All the invalid roles are present in the error"
);
};
subtest "normalize_ldap_role_mappings" => sub {
is(
Hydra::Config::normalize_ldap_role_mappings({}),
{},
"An empty input map is an empty output map."
);
is(
Hydra::Config::normalize_ldap_role_mappings({
hydra_admin => "admin",
hydra_one_group_many_roles => [ "create-projects", "bump-to-front" ],
}),
{
hydra_admin => [ "admin" ],
hydra_one_group_many_roles => [ "create-projects", "bump-to-front" ],
},
"Lists and plain strings normalize to lists"
);
like(
dies{
Hydra::Config::normalize_ldap_role_mappings({
"group" => "invalid-role",
}),
},
qr/Invalid roles.*invalid-role/,
"Invalid roles fail to normalize."
);
like(
dies{
Hydra::Config::normalize_ldap_role_mappings({
"group" => { "nested" => "data" },
}),
},
qr/On group 'group':.* Only strings/,
"Invalid nesting fail to normalize."
);
};
done_testing;

View File

@ -1,6 +1,7 @@
use strict;
use warnings;
use Setup;
use Hydra::Config;
my %ctx = test_init(hydra_config => q|
<statsd>
@ -12,7 +13,7 @@ my %ctx = test_init(hydra_config => q|
require Hydra::Helper::Nix;
use Test2::V0;
is(Hydra::Helper::Nix::getStatsdConfig(Hydra::Helper::Nix::getHydraConfig()), {
is(Hydra::Helper::Nix::getStatsdConfig(getHydraConfig()), {
'host' => "foo.bar",
'port' => 18125
}, "Reading specific configuration from the hydra.conf works");

View File

@ -13,10 +13,12 @@ my $users = {
admin => $ldap->add_user("admin_user"),
not_admin => $ldap->add_user("not_admin_user"),
many_roles => $ldap->add_user("many_roles"),
many_roles_one_group => $ldap->add_user("many_roles_one_group"),
};
$ldap->add_group("hydra_admin", $users->{"admin"}->{"username"});
$ldap->add_group("hydra-admin", $users->{"not_admin"}->{"username"});
$ldap->add_group("hydra_one_group_many_roles", $users->{"many_roles_one_group"}->{"username"});
$ldap->add_group("hydra_create-projects", $users->{"many_roles"}->{"username"});
$ldap->add_group("hydra_restart-jobs", $users->{"many_roles"}->{"username"});
@ -69,6 +71,10 @@ my $ctx = test_context(
hydra_cancel-build = cancel-build
hydra_bump-to-front = bump-to-front
hydra_restart-jobs = restart-jobs
hydra_one_group_many_roles = create-projects
hydra_one_group_many_roles = cancel-build
hydra_one_group_many_roles = bump-to-front
</role_mapping>
</ldap>
CFG
@ -79,9 +85,10 @@ Catalyst::Test->import('Hydra');
subtest "Valid login attempts" => sub {
my %users_to_roles = (
unrelated => [],
admin => ["admin"],
not_admin => [],
many_roles => [ "create-projects", "restart-jobs", "bump-to-front", "cancel-build" ],
admin => ["admin"],
not_admin => [],
many_roles => [ "create-projects", "restart-jobs", "bump-to-front", "cancel-build" ],
many_roles_one_group => [ "create-projects", "bump-to-front", "cancel-build" ],
);
for my $username (keys %users_to_roles) {
my $user = $users->{$username};