From 46b279a4f063accc5af07689b1bb960713856282 Mon Sep 17 00:00:00 2001 From: William Petit Date: Mon, 17 Feb 2025 15:12:59 +0100 Subject: [PATCH] feat: add configurable acr/amr claims --- conf/hydra-werther.conf | 20 ++++++++++++++++---- internal/hydra/login.go | 16 +++++++++++----- internal/hydra/login_test.go | 4 ++-- internal/identp/identp.go | 6 ++++-- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/conf/hydra-werther.conf b/conf/hydra-werther.conf index 061c99e..d8b850f 100644 --- a/conf/hydra-werther.conf +++ b/conf/hydra-werther.conf @@ -125,7 +125,19 @@ WERTHER_LDAP_ROLE_BASEDN=ou=groups,dc=myorg,dc=com # [required] # WERTHER_INSECURE_SKIP_VERIFY= -# [description] Disable TLS verification on Hydra connection -# [type] True or False -# [default] false -# [required] \ No newline at end of file + # [description] Disable TLS verification on Hydra connection + # [type] True or False + # [default] false + # [required] + +# WERTHER_IDENTP_AMR= + # [description] Authentication Method Reference Values + # [type] Comma-separated list of String + # [default] + # [required] false + +# WERTHER_IDENTP_ACR= + # [description] Authentication Context Class Reference + # [type] String + # [default] + # [required] false \ No newline at end of file diff --git a/internal/hydra/login.go b/internal/hydra/login.go index f2efa9c..085fcd5 100644 --- a/internal/hydra/login.go +++ b/internal/hydra/login.go @@ -16,11 +16,13 @@ type LoginReqDoer struct { hydraURL string fakeTLSTermination bool rememberFor int + acr string + amr []string } // NewLoginReqDoer creates a LoginRequest. -func NewLoginReqDoer(hydraURL string, fakeTLSTermination bool, rememberFor int) *LoginReqDoer { - return &LoginReqDoer{hydraURL: hydraURL, fakeTLSTermination: fakeTLSTermination, rememberFor: rememberFor} +func NewLoginReqDoer(hydraURL string, fakeTLSTermination bool, rememberFor int, acr string, amr []string) *LoginReqDoer { + return &LoginReqDoer{hydraURL: hydraURL, fakeTLSTermination: fakeTLSTermination, rememberFor: rememberFor, acr: acr, amr: amr} } // InitiateRequest fetches information on the OAuth2 request. @@ -32,13 +34,17 @@ func (lrd *LoginReqDoer) InitiateRequest(challenge string) (*ReqInfo, error) { // AcceptLoginRequest accepts the requested authentication process, and returns redirect URI. func (lrd *LoginReqDoer) AcceptLoginRequest(challenge string, remember bool, subject string) (string, error) { data := struct { - Remember bool `json:"remember"` - RememberFor int `json:"remember_for"` - Subject string `json:"subject"` + Remember bool `json:"remember"` + RememberFor int `json:"remember_for"` + Subject string `json:"subject"` + ACR string `json:"acr,omitempty"` + AMR []string `json:"amr,omitempty"` }{ Remember: remember, RememberFor: lrd.rememberFor, Subject: subject, + ACR: lrd.acr, + AMR: lrd.amr, } redirectURI, err := acceptRequest(login, lrd.hydraURL, lrd.fakeTLSTermination, challenge, data) return redirectURI, errors.Wrap(err, "failed to accept login request") diff --git a/internal/hydra/login_test.go b/internal/hydra/login_test.go index f5a75ff..8dcea29 100644 --- a/internal/hydra/login_test.go +++ b/internal/hydra/login_test.go @@ -60,7 +60,7 @@ func TestInitiateLoginRequest(t *testing.T) { h := &testInitiateLoginHandler{reqInfo: tc.reqInfo, status: tc.status} srv := httptest.NewServer(h) defer srv.Close() - ldr := hydra.NewLoginReqDoer(srv.URL, false, 0) + ldr := hydra.NewLoginReqDoer(srv.URL, false, 0, "", nil) reqInfo, err := ldr.InitiateRequest(tc.challenge) @@ -160,7 +160,7 @@ func TestAcceptLoginRequest(t *testing.T) { h := &testAcceptLoginHandler{challenge: tc.challenge, status: tc.status, redirect: tc.redirect} srv := httptest.NewServer(h) defer srv.Close() - ldr := hydra.NewLoginReqDoer(srv.URL, false, tc.rememberFor) + ldr := hydra.NewLoginReqDoer(srv.URL, false, tc.rememberFor, "", nil) redirect, err := ldr.AcceptLoginRequest(tc.challenge, tc.remember, tc.subject) diff --git a/internal/identp/identp.go b/internal/identp/identp.go index cbab516..2d21eef 100644 --- a/internal/identp/identp.go +++ b/internal/identp/identp.go @@ -32,6 +32,8 @@ type Config struct { SessionTTL time.Duration `envconfig:"session_ttl" default:"24h" desc:"a user session's TTL"` ClaimScopes map[string]string `envconfig:"claim_scopes" default:"name:profile,family_name:profile,given_name:profile,email:email,https%3A%2F%2Fgithub.com%2Fi-core%2Fwerther%2Fclaims%2Froles:roles" desc:"a mapping of OpenID Connect claims to scopes (all claims are URL encoded)"` FakeTLSTermination bool `envconfig:"fake_tls_termination" default:"false" desc:"Fake tls termination by adding \"X-Forwarded-Proto: https\" to http headers "` + ACR string `envconfig:"acr" desc:"Authorization Context Class Reference"` + AMR []string `envconfig:"amr" desc:"Authentication Method References"` } // UserManager is an interface that is used for authentication and providing user's claims. @@ -85,8 +87,8 @@ func NewHandler(cnf Config, um UserManager, tr TemplateRenderer) *Handler { // AddRoutes registers all required routes for Login & Consent Provider. func (h *Handler) AddRoutes(apply func(m, p string, h http.Handler, mws ...func(http.Handler) http.Handler)) { sessionTTL := int(h.SessionTTL.Seconds()) - apply(http.MethodGet, "/login", newLoginStartHandler(hydra.NewLoginReqDoer(h.HydraURL, h.FakeTLSTermination, 0), h.tr)) - apply(http.MethodPost, "/login", newLoginEndHandler(hydra.NewLoginReqDoer(h.HydraURL, h.FakeTLSTermination, sessionTTL), h.um, h.tr)) + apply(http.MethodGet, "/login", newLoginStartHandler(hydra.NewLoginReqDoer(h.HydraURL, h.FakeTLSTermination, 0, h.ACR, h.AMR), h.tr)) + apply(http.MethodPost, "/login", newLoginEndHandler(hydra.NewLoginReqDoer(h.HydraURL, h.FakeTLSTermination, sessionTTL, h.ACR, h.AMR), h.um, h.tr)) apply(http.MethodGet, "/consent", newConsentHandler(hydra.NewConsentReqDoer(h.HydraURL, h.FakeTLSTermination, sessionTTL), h.um, h.ClaimScopes)) apply(http.MethodGet, "/logout", newLogoutHandler(hydra.NewLogoutReqDoer(h.HydraURL, h.FakeTLSTermination))) } -- 2.17.1