From eb9ee0bf0d780f119e37e81b79350a7f7d1a468d Mon Sep 17 00:00:00 2001 From: oddlama Date: Fri, 23 Jun 2023 15:20:58 +0200 Subject: [PATCH] feat: patch oauth2-proxy to support scopes as groups --- README.md | 5 ++- hosts/sentinel/oauth2.nix | 16 +++---- hosts/ward/microvms/adguardhome/default.nix | 2 +- modules/oauth2-proxy.nix | 8 ++-- pkgs/default.nix | 1 + pkgs/oauth2-proxy/0001-scopes-as-groups.patch | 44 +++++++++++++++++++ pkgs/oauth2-proxy/default.nix | 5 +++ 7 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 pkgs/oauth2-proxy/0001-scopes-as-groups.patch create mode 100644 pkgs/oauth2-proxy/default.nix diff --git a/README.md b/README.md index 83166a0..6686b2b 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ kanidm group create grafana-server-admins kanidm group create grafana-admins kanidm group create grafana-editors kanidm system oauth2 create grafana "Grafana" https://grafana.${personalDomain} -kanidm system oauth2 update-scope-map grafana grafana-access openid profile email +kanidm system oauth2 update-scope-map grafana grafana-access openid email profile kanidm system oauth2 update-sup-scope-map grafana grafana-server-admins server_admin kanidm system oauth2 update-sup-scope-map grafana grafana-admins admin kanidm system oauth2 update-sup-scope-map grafana grafana-editors editor @@ -160,7 +160,7 @@ kanidm system oauth2 show-basic-secret grafana kanidm group create web-sentinel-access kanidm group create web-sentinel-adguardhome-access kanidm system oauth2 create web-sentinel "Web services" https://oauth2.${personalDomain} -kanidm system oauth2 update-scope-map web-sentinel web-sentinel-access openid profile email +kanidm system oauth2 update-scope-map web-sentinel web-sentinel-access openid email kanidm system oauth2 update-sup-scope-map web-sentinel web-sentinel-adguardhome-access access_adguardhome kanidm system oauth2 show-basic-secret web-sentinel # Add new user @@ -169,6 +169,7 @@ kanidm person create myuser "My User" kanidm person update myuser --legalname "Full Name" --mail "myuser@example.com" kanidm group add-members grafana-access myuser kanidm group add-members grafana-server-admins myuser +kanidm group add-members web-sentinel-access myuser ``` diff --git a/hosts/sentinel/oauth2.nix b/hosts/sentinel/oauth2.nix index 7a7048a..1df1d8e 100644 --- a/hosts/sentinel/oauth2.nix +++ b/hosts/sentinel/oauth2.nix @@ -8,6 +8,7 @@ enable = true; cookieDomain = config.repo.secrets.local.personalDomain; portalDomain = "oauth2.${config.repo.secrets.local.personalDomain}"; + # TODO portal redirect to dashboard (in case someone clicks on kanidm "Web services") }; age.secrets.oauth2-proxy-secret = { @@ -16,24 +17,21 @@ group = "oauth2_proxy"; }; - services.oauth2_proxy = { + services.oauth2_proxy = let + clientId = "web-sentinel"; + in { provider = "oidc"; scope = "openid email"; loginURL = "https://${config.proxiedDomains.kanidm}/ui/oauth2"; redeemURL = "https://${config.proxiedDomains.kanidm}/oauth2/token"; - validateURL = "https://${config.proxiedDomains.kanidm}/oauth2/openid/web-sentinel/userinfo"; - clientID = "web-sentinel"; + validateURL = "https://${config.proxiedDomains.kanidm}/oauth2/openid/${clientId}/userinfo"; + clientID = clientId; keyFile = config.age.secrets.oauth2-proxy-secret.path; email.domains = ["*"]; extraConfig = { - # TODO good idea? would fail when offline - # TODO autorestart after 30 minutes, infinite times. - oidc-issuer-url = "https://${config.proxiedDomains.kanidm}/oauth2/openid/web-sentinel"; + oidc-issuer-url = "https://${config.proxiedDomains.kanidm}/oauth2/openid/${clientId}"; skip-provider-button = true; - - # TODO away - show-debug-on-error = true; }; }; } diff --git a/hosts/ward/microvms/adguardhome/default.nix b/hosts/ward/microvms/adguardhome/default.nix index 82b9936..c499b9c 100644 --- a/hosts/ward/microvms/adguardhome/default.nix +++ b/hosts/ward/microvms/adguardhome/default.nix @@ -36,7 +36,7 @@ in { forceSSL = true; useACMEHost = sentinelCfg.lib.extra.matchingWildcardCert adguardhomeDomain; oauth2.enable = true; - oauth2.allowedGroups = ["adguardhome"]; + oauth2.allowedGroups = ["access_adguardhome"]; locations."/" = { proxyPass = "http://adguardhome"; proxyWebsockets = true; diff --git a/modules/oauth2-proxy.nix b/modules/oauth2-proxy.nix index 81d7b16..3e1fd37 100644 --- a/modules/oauth2-proxy.nix +++ b/modules/oauth2-proxy.nix @@ -99,12 +99,14 @@ in { cookie.domain = ".${cfg.cookieDomain}"; cookie.secure = true; - cookie.httpOnly = false; - cookie.refresh = "5m"; + # FIXME disabled because of errors. My closest guess is that this + # reuses refresh tokens but kanidm forbids that. Not sure though. + #cookie.refresh = "5m"; cookie.expire = "30m"; reverseProxy = true; httpAddress = "unix:///run/oauth2_proxy/oauth2_proxy.sock"; + redirectURL = "https://${cfg.portalDomain}/oauth2/callback"; setXauthrequest = true; extraConfig = { @@ -112,12 +114,10 @@ in { code-challenge-method = "S256"; # Share the cookie with all subpages whitelist-domain = ".${cfg.cookieDomain}"; - redirect-url = "https://${cfg.portalDomain}/oauth2/callback"; set-authorization-header = true; pass-access-token = true; skip-jwt-bearer-tokens = true; upstream = "static://202"; - # TODO allowed group? }; }; diff --git a/pkgs/default.nix b/pkgs/default.nix index 6235587..7710763 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -1,3 +1,4 @@ [ (import ./caddy.nix) + (import ./oauth2-proxy) ] diff --git a/pkgs/oauth2-proxy/0001-scopes-as-groups.patch b/pkgs/oauth2-proxy/0001-scopes-as-groups.patch new file mode 100644 index 0000000..6a21f3f --- /dev/null +++ b/pkgs/oauth2-proxy/0001-scopes-as-groups.patch @@ -0,0 +1,44 @@ +diff --git a/providers/oidc.go b/providers/oidc.go +index aadaf7c5..18b03a3e 100644 +--- a/providers/oidc.go ++++ b/providers/oidc.go +@@ -10,6 +10,7 @@ import ( + "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" + "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions" + "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger" ++ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests" + "golang.org/x/oauth2" + ) + +@@ -80,6 +81,31 @@ func (p *OIDCProvider) Redeem(ctx context.Context, redirectURL, code, codeVerifi + // EnrichSession is called after Redeem to allow providers to enrich session fields + // such as User, Email, Groups with provider specific API calls. + func (p *OIDCProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error { ++ // Fallback to ValidateURL if ProfileURL not set for legacy compatibility ++ profileURL := p.ValidateURL.String() ++ if p.ProfileURL.String() != "" { ++ profileURL = p.ProfileURL.String() ++ } ++ ++ json, err := requests.New(profileURL). ++ WithContext(ctx). ++ SetHeader("Authorization", "Bearer "+s.AccessToken). ++ Do(). ++ UnmarshalSimpleJSON() ++ if err != nil { ++ logger.Errorf("failed making request %v", err) ++ return err ++ } ++ ++ groups, err := json.Get("scopes").StringArray() ++ if err == nil { ++ for _, group := range groups { ++ if group != "" { ++ s.Groups = append(s.Groups, group) ++ } ++ } ++ } ++ + // If a mandatory email wasn't set, error at this point. + if s.Email == "" { + return errors.New("neither the id_token nor the profileURL set an email") diff --git a/pkgs/oauth2-proxy/default.nix b/pkgs/oauth2-proxy/default.nix new file mode 100644 index 0000000..379ba29 --- /dev/null +++ b/pkgs/oauth2-proxy/default.nix @@ -0,0 +1,5 @@ +final: prev: { + oauth2-proxy = prev.oauth2-proxy.overrideAttrs (_: { + patches = [./0001-scopes-as-groups.patch]; + }); +}