Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ hydra-notify: ./foreman/start-notify.sh
hydra-server: ./foreman/start-hydra.sh
manual: ./foreman/start-manual.sh
postgres: ./foreman/start-postgres.sh
kanidm: ./foreman/start-kanidm.pl
24 changes: 23 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,33 @@
let
systems = [ "x86_64-linux" "aarch64-linux" ];
forEachSystem = nixpkgs.lib.genAttrs systems;

pkgsBySystem = forEachSystem (system: import nixpkgs {
inherit system;
overlays = [ self.overlays.default ];
});
in
rec {

# A Nixpkgs overlay that provides a 'hydra' package.
overlays.default = final: prev: {
# Perl packages that are not yet in nixpkgs
perlPackages = prev.perlPackages // {
CryptURandomToken = final.perlPackages.buildPerlPackage {
pname = "Crypt-URandom-Token";
version = "0.005";
src = prev.fetchurl {
url = "mirror://cpan/authors/id/S/ST/STIGTSP/Crypt-URandom-Token-0.005.tar.gz";
hash = "sha256-3OGOqMkgmF6IfdQdmMlsKFoXRwMhqrxKdXHHEIHj1nk=";
};
buildInputs = with final.perlPackages; [ CryptURandom TestException ];
meta = {
homepage = "https://github.com/stigtsp/Crypt-URandom-Token";
description = "Password generator using Crypt::URandom";
license = with final.lib.licenses; [ artistic1 gpl1Plus ];
};
};
};
nixDependenciesForHydra = final.lib.makeScope final.newScope
(import (nix + "/packaging/dependencies.nix") {
pkgs = final;
Expand Down Expand Up @@ -85,7 +107,7 @@

packages = forEachSystem (system: let
inherit (nixpkgs) lib;
pkgs = nixpkgs.legacyPackages.${system};
pkgs = pkgsBySystem.${system};
nixDependencies = lib.makeScope pkgs.newScope
(import (nix + "/packaging/dependencies.nix") {
inherit pkgs;
Expand Down
13 changes: 13 additions & 0 deletions foreman/start-hydra.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export PATH=$(pwd)/src/script:$PATH

# wait for postgresql to listen
while ! pg_isready -h $(pwd)/.hydra-data/postgres -p 64444; do sleep 1; done
# We need to wait for kanidm to be up and start-kanidm.pl to have written the secret file.
while ! curl -ksf "https://localhost:64448/status"; do sleep 1; done
while ! [[ -e .hydra-data/kanidm/hydra_client_secret ]]; do sleep 1; done

createdb -h $(pwd)/.hydra-data/postgres -p 64444 hydra

Expand All @@ -28,6 +31,16 @@ use-substitutes = true
port = 64445
</prometheus>
</hydra_notify>

<oidc>
<provider kanidm>
display_name = "Kanidm"
discovery_url = "https://localhost:64448/oauth2/openid/hydra/.well-known/openid-configuration"
client_id = "hydra"
client_secret_file = ".hydra-data/kanidm/hydra_client_secret"
ca_file = ".hydra-data/kanidm/ca.pem"
</provider>
</oidc>
EOF
fi
HYDRA_CONFIG=$(pwd)/.hydra-data/hydra.conf exec hydra-dev-server --port 63333 --restart --debug
72 changes: 72 additions & 0 deletions foreman/start-kanidm.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env perl

# We already have a lot of code for automating kanidm for the tests, in KanidmContext.pm.
# So just lean on that as much as we can.

use strict;
use warnings;

use lib qw(t/lib);

use Cwd qw(abs_path);
use KanidmContext;
use IO::File;

mkdir ".hydra-data/kanidm";

my $ctx = KanidmContext->new(
kanidm_dir => abs_path(".hydra-data/kanidm"),
port => 64448,
);
$ctx->start();
print "Kanidm running at ${\ $ctx->url() } with admin password ${\ $ctx->admin_password }\n";

$ctx->allow_passwords();
$ctx->create_group('hydra_users');
$ctx->create_group('hydra_admins');
$ctx->create_user(
'andy',
groups => ['hydra_users', 'hydra_admins'],
# Annoyingly password quality checks in kanidm cannot be disabled.
password => 'kanidm credential',
);
$ctx->create_user(
'bert',
groups => ['hydra_users'],
password => 'kanidm credential',
);
$ctx->create_oauth2_client(
name => 'hydra',
redirect_uris => ['http://localhost:63333/oidc-callback/kanidm'],
scopes => { hydra_users => ['openid', 'email', 'profile']},
claims => {
hydra_roles => {
hydra_admins => ['admin'],
hydra_users => ['restart_jobs', 'bump_to_front', 'cancel_build'],
}
}
);
IO::File->new('.hydra-data/kanidm/hydra_client_secret', 'w')->print($ctx->get_oauth2_secret('hydra'));

my $running = 1;
$SIG{INT} = $SIG{TERM} = $SIG{HUP} = sub {
print "\nShutting down kanidm...\n";
$running = 0;
};

open my $logfh, '<', $ctx->logfile or die "Cannot open logfile: $!";

while ($running) {
while (my $line = <$logfh>) {
print $line;
}
$ctx->assert_running();

# At EOF, sleep briefly and try again
# Clear EOF condition so we can read new data appended to the file
seek($logfh, 0, 1);
sleep 1;
}

$ctx->kill();
print "Kanidm stopped.\n";
2 changes: 1 addition & 1 deletion foreman/start-manual.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/sh

mdbook serve \
exec mdbook serve \
--port 63332 \
--dest-dir ./.hydra-data/manual \
./doc/manual/
14 changes: 14 additions & 0 deletions package.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{ stdenv
, lib
, fileset
, pkgs

, rawSrc

Expand Down Expand Up @@ -34,6 +35,8 @@
, postgresql_17
, nlohmann_json
, prometheus-cpp
, kanidm_1_8
, jq

, cacert
, foreman
Expand Down Expand Up @@ -65,13 +68,15 @@ let
git
] ++ (with perlPackages; [
AuthenSASL
CacheFastMmap
CatalystActionREST
CatalystAuthenticationStoreDBIxClass
CatalystAuthenticationStoreLDAP
CatalystDevel
CatalystPluginAccessLog
CatalystPluginAuthorizationRoles
CatalystPluginCaptcha
CatalystPluginCache
CatalystPluginPrometheusTiny
CatalystPluginSessionStateCookie
CatalystPluginSessionStoreFastMmap
Expand All @@ -82,9 +87,12 @@ let
CatalystViewTT
CatalystXRoleApplicator
CatalystXScriptServerStarman
CryptJWT
CryptPassphrase
CryptPassphraseArgon2
CryptRandPasswd
CryptURandom
CryptURandomToken
DataDump
DateTime
DBDPg
Expand All @@ -97,6 +105,7 @@ let
FileLibMagic
FileSlurper
FileWhich
HTTPCookieJar
IOCompress
IPCRun
IPCRun3
Expand Down Expand Up @@ -124,10 +133,14 @@ let
TermSizeAny
TermReadKey
Test2Harness
TestLongString
TestPostgreSQL
TestWWWMechanize
TestWWWMechanizeCatalyst
TextDiff
TextTable
UUID4Tiny
WWWMechanize
YAML
XMLSimple
]));
Expand Down Expand Up @@ -195,6 +208,7 @@ stdenv.mkDerivation (finalAttrs: {
postgresql_17
pixz
nix-eval-jobs
kanidm_1_8
];

checkInputs = [
Expand Down
18 changes: 18 additions & 0 deletions src/lib/Hydra.pm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use Moose;
use Hydra::Plugin;
use Hydra::Model::DB;
use Hydra::Config qw(getLDAPConfigAmbient);
use Hydra::Helper::OIDC qw(resolveOIDCConfig);
use Catalyst::Runtime '5.70';
use Catalyst qw/ConfigLoader
Static::Simple
Expand All @@ -17,10 +18,12 @@ use Catalyst qw/ConfigLoader
Session::Store::FastMmap
Session::State::Cookie
Captcha
Cache
PrometheusTiny/,
'-Log=warn,fatal,error';
use CatalystX::RoleApplicator;
use Path::Class 'file';
use Cache::FastMmap;

our $VERSION = '0.01';

Expand Down Expand Up @@ -65,6 +68,13 @@ __PACKAGE__->config(
storage => Hydra::Model::DB::getHydraPath . "/www/session_data",
unlink_on_exit => 0
},
'Plugin::Cache' => {
backend => {
class => 'Cache::FastMmap',
unlink_on_exit => 1,
init_file => 1,
},
},
'Plugin::Captcha' => {
session_name => 'hydra-captcha',
new => {
Expand Down Expand Up @@ -94,6 +104,14 @@ has 'hydra_plugins' => (
default => sub { return $plugins; }
);

# Resolve OIDC discovery URLs and materialize endpoints into config
after setup_finalize => sub {
my $class = shift;
if ($class->config->{oidc}) {
resolveOIDCConfig($class->config->{oidc});
}
};

after setup_finalize => sub {
my $class = shift;
$plugins = [Hydra::Plugin->instantiate(db => $class->model('DB'), config => $class->config)];
Expand Down
9 changes: 9 additions & 0 deletions src/lib/Hydra/Config.pm
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,13 @@ sub valid_roles {
];
}

# Some OIDC identity provider implementations (e.g. kanidm) have restrictions on what values can
# be put in custom claims. We look for the roles to add users to based on the hydra_roles claim,
# and e.g. kanidm does not allow dashes in this claim. So accept underscores in place of dashes
# in the role names.
sub normalize_role_name {
my ($role) = @_;
return $role =~ s/_/-/gr;
}

1;
Loading