mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 19:46:05 +01:00
pizauth: init module
This commit is contained in:
parent
0b7147a547
commit
18ea6d7a8f
4 changed files with 274 additions and 0 deletions
12
modules/misc/news/2025/08/2025-08-09_21-07-00.nix
Normal file
12
modules/misc/news/2025/08/2025-08-09_21-07-00.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
time = "2025-08-09T22:11:00+00:00";
|
||||||
|
condition = pkgs.stdenv.hostPlatform.isLinux;
|
||||||
|
message = ''
|
||||||
|
A new service is available: 'services.pizauth'.
|
||||||
|
|
||||||
|
Pizauth is a simple program for requesting, showing, and refreshing OAuth2 access tokens.
|
||||||
|
Pizauth is formed of two components: a persistent server which interacts with the user to request tokens, and refreshes them as necessary;
|
||||||
|
and a command-line interface which can be used by programs such as fdm and msmtp to authenticate with OAuth2.
|
||||||
|
'';
|
||||||
|
}
|
||||||
190
modules/services/pizauth.nix
Normal file
190
modules/services/pizauth.nix
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
|
||||||
|
cfg = config.services.pizauth;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
meta.maintainers = [ lib.hm.maintainers.swarsel ];
|
||||||
|
|
||||||
|
options.services.pizauth = {
|
||||||
|
enable = lib.mkEnableOption ''
|
||||||
|
Pizauth, a commandline OAuth2 authentication daemon
|
||||||
|
'';
|
||||||
|
|
||||||
|
package = lib.mkPackageOption pkgs "pizauth" { };
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
description = "Additional global configuration. See pizauth.conf(5) for a available options.";
|
||||||
|
};
|
||||||
|
|
||||||
|
accounts = mkOption {
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.submodule {
|
||||||
|
options = {
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
readOnly = true;
|
||||||
|
description = ''
|
||||||
|
Unique identifier of the account. This is set to the
|
||||||
|
attribute name of the account configuration.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
authUri = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
The OAuth2 server's authentication URI.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
tokenUri = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
The OAuth2 server's token URI.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
clientId = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
The OAuth2 client ID.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
clientSecret = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
The OAuth2 client secret.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
scopes = mkOption {
|
||||||
|
type = types.nullOr (types.listOf types.str);
|
||||||
|
description = ''
|
||||||
|
The scopes which the OAuth2 token will give access to. Optional.
|
||||||
|
Note that Office365 requires the non-standard "offline_access" scope to be specified in order for pizauth to be able to operate successfully.
|
||||||
|
'';
|
||||||
|
default = [ ];
|
||||||
|
example = [
|
||||||
|
"https://outlook.office365.com/IMAP.AccessAsUser.All"
|
||||||
|
"https://outlook.office365.com/SMTP.Send"
|
||||||
|
"offline_access"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
loginHint = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
An optional login hint for the account provider.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Additional configuration that will be added to the account configuration. See pizauth.conf(5) for available options.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
default = { };
|
||||||
|
description = "Pizauth accounts that should be configured";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
assertions = [ (lib.hm.assertions.assertPlatform "services.pizauth" pkgs lib.platforms.linux) ];
|
||||||
|
|
||||||
|
home.packages = [ cfg.package ];
|
||||||
|
|
||||||
|
xdg.configFile."pizauth.conf".source =
|
||||||
|
let
|
||||||
|
indent = " ";
|
||||||
|
|
||||||
|
renderScopes =
|
||||||
|
scopes:
|
||||||
|
let
|
||||||
|
quoted = map (s: "\"${s}\"") scopes;
|
||||||
|
joined = lib.concatStringsSep ",\n${indent}${indent}" quoted;
|
||||||
|
in
|
||||||
|
"[\n${indent}${indent}${joined}\n${indent}]";
|
||||||
|
|
||||||
|
renderAccount =
|
||||||
|
name: acc:
|
||||||
|
''
|
||||||
|
account "${name}" {
|
||||||
|
${indent}auth_uri = "${acc.authUri}";
|
||||||
|
${indent}token_uri = "${acc.tokenUri}";
|
||||||
|
${indent}client_id = "${acc.clientId}";
|
||||||
|
${indent}client_secret = "${acc.clientSecret}";
|
||||||
|
''
|
||||||
|
+ lib.optionalString (acc.scopes != [ ] && acc.scopes != null) ''
|
||||||
|
${indent}scopes = ${renderScopes acc.scopes};
|
||||||
|
''
|
||||||
|
+ lib.optionalString (acc.loginHint != "" && acc.loginHint != null) ''
|
||||||
|
${indent}login_hint = "${acc.loginHint}";
|
||||||
|
''
|
||||||
|
+ lib.optionalString (acc.extraConfig != "" && acc.extraConfig != null) (
|
||||||
|
let
|
||||||
|
indentedExtraConfig = lib.concatMapStringsSep "\n" (
|
||||||
|
line: if line == "" then "" else "${indent}${line}"
|
||||||
|
) (lib.splitString "\n" acc.extraConfig);
|
||||||
|
in
|
||||||
|
indentedExtraConfig
|
||||||
|
)
|
||||||
|
+ ''
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
renderedAccounts = lib.concatStringsSep "\n" (
|
||||||
|
lib.mapAttrsToList (name: acc: renderAccount name acc) cfg.accounts
|
||||||
|
);
|
||||||
|
|
||||||
|
in
|
||||||
|
pkgs.writeTextFile {
|
||||||
|
name = "pizauth.conf";
|
||||||
|
text =
|
||||||
|
lib.optionalString (cfg.extraConfig != null && cfg.extraConfig != "") "${cfg.extraConfig}\n"
|
||||||
|
+ renderedAccounts;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.user.services.pizauth = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Pizauth OAuth2 token manager";
|
||||||
|
After = [ "network.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
Service = {
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = "${lib.getExe cfg.package} server -vvvv -d";
|
||||||
|
ExecReload = "${lib.getExe cfg.package} reload";
|
||||||
|
ExecStop = "${lib.getExe cfg.package} shutdown";
|
||||||
|
Restart = "on-failure";
|
||||||
|
|
||||||
|
LockPersonality = true;
|
||||||
|
MemoryDenyWriteExecute = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateUsers = true;
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
SystemCallFilter = "@system-service";
|
||||||
|
};
|
||||||
|
|
||||||
|
Install = {
|
||||||
|
WantedBy = [ "default.target" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
70
tests/modules/services/pizauth/basic-config.nix
Normal file
70
tests/modules/services/pizauth/basic-config.nix
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
services.pizauth = {
|
||||||
|
enable = true;
|
||||||
|
extraConfig = ''
|
||||||
|
refresh_at_least = 15s;
|
||||||
|
'';
|
||||||
|
accounts = {
|
||||||
|
test1 = {
|
||||||
|
authUri = "authUri1";
|
||||||
|
tokenUri = "tokenUri1";
|
||||||
|
clientId = "clientId1";
|
||||||
|
clientSecret = "clientSecret1";
|
||||||
|
loginHint = "testLogin1";
|
||||||
|
extraConfig = ''
|
||||||
|
redirectUri = "redirectUri1";
|
||||||
|
refresh_retry = 30s;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
test2 = {
|
||||||
|
authUri = "authUri2";
|
||||||
|
tokenUri = "tokenUri2";
|
||||||
|
clientId = "clientId2";
|
||||||
|
clientSecret = "clientSecret2";
|
||||||
|
scopes = [
|
||||||
|
"scope1"
|
||||||
|
"offline_access"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test.stubs.pizauth = { };
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
local serviceFile=home-files/.config/systemd/user/pizauth.service
|
||||||
|
|
||||||
|
assertFileExists $serviceFile
|
||||||
|
assertFileRegex $serviceFile 'ExecStart=.*/bin/dummy server -vvvv -d'
|
||||||
|
|
||||||
|
assertFileExists home-files/.config/pizauth.conf
|
||||||
|
assertFileContent home-files/.config/pizauth.conf \
|
||||||
|
${pkgs.writeText "expected-config" ''
|
||||||
|
refresh_at_least = 15s;
|
||||||
|
|
||||||
|
account "test1" {
|
||||||
|
auth_uri = "authUri1";
|
||||||
|
token_uri = "tokenUri1";
|
||||||
|
client_id = "clientId1";
|
||||||
|
client_secret = "clientSecret1";
|
||||||
|
login_hint = "testLogin1";
|
||||||
|
redirectUri = "redirectUri1";
|
||||||
|
refresh_retry = 30s;
|
||||||
|
}
|
||||||
|
|
||||||
|
account "test2" {
|
||||||
|
auth_uri = "authUri2";
|
||||||
|
token_uri = "tokenUri2";
|
||||||
|
client_id = "clientId2";
|
||||||
|
client_secret = "clientSecret2";
|
||||||
|
scopes = [
|
||||||
|
"scope1",
|
||||||
|
"offline_access"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
''}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
2
tests/modules/services/pizauth/default.nix
Normal file
2
tests/modules/services/pizauth/default.nix
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
{ lib, pkgs, ... }:
|
||||||
|
lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { pizauth-basic-config = ./basic-config.nix; }
|
||||||
Loading…
Add table
Add a link
Reference in a new issue