From a302dc4b85884819a0e31ff9bb83b66ee9da3d93 Mon Sep 17 00:00:00 2001 From: Danijel Vukoje Date: Thu, 13 Nov 2025 16:13:08 +0200 Subject: [PATCH 1/2] dynamically set openid configuration endpoints based on host url --- elsinod.go | 76 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/elsinod.go b/elsinod.go index 6a230b4..3831a73 100644 --- a/elsinod.go +++ b/elsinod.go @@ -41,32 +41,34 @@ func New( issuerURL := baseURL.String() - conf := elephantine.OpenIDConnectConfig{ - Issuer: issuerURL, - UserinfoEndpoint: baseURL.JoinPath("user-info").String(), - TokenEndpoint: baseURL.JoinPath("token").String(), - AuthorizationEndpoint: baseURL.JoinPath("protocol", "openid-connect", "auth").String(), - JwksURI: baseURL.JoinPath(".well-known", "jwks.json").String(), - GrantTypesSupported: []string{ - "authorization_code", - "refresh_token", - "client_credentials", - "urn:ietf:params:oauth:grant-type:token-exchange", - }, - ResponseTypesSupported: []string{ - "code", - "token", - "id_token", - }, - IDTokenSigningAlgValuesSupported: []string{ - "ES384", - }, - TokenEndpointAuthMethodsSupported: []string{ - "client_secret_post", - }, - TokenEndpointAuthSigningAlgValuesSupported: []string{ - "ES384", - }, + conf := func(hostURL *url.URL) elephantine.OpenIDConnectConfig { + return elephantine.OpenIDConnectConfig{ + Issuer: issuerURL, + UserinfoEndpoint: hostURL.JoinPath("user-info").String(), + TokenEndpoint: hostURL.JoinPath("token").String(), + AuthorizationEndpoint: hostURL.JoinPath("protocol", "openid-connect", "auth").String(), + JwksURI: hostURL.JoinPath(".well-known", "jwks.json").String(), + GrantTypesSupported: []string{ + "authorization_code", + "refresh_token", + "client_credentials", + "urn:ietf:params:oauth:grant-type:token-exchange", + }, + ResponseTypesSupported: []string{ + "code", + "token", + "id_token", + }, + IDTokenSigningAlgValuesSupported: []string{ + "ES384", + }, + TokenEndpointAuthMethodsSupported: []string{ + "client_secret_post", + }, + TokenEndpointAuthSigningAlgValuesSupported: []string{ + "ES384", + }, + } } codes := sturdyc.New[issuedCode](1000, 1, 12*time.Second, 20, @@ -99,7 +101,7 @@ type Elsinod struct { publicURL string clientSecret string demoPassword string - oidc elephantine.OpenIDConnectConfig + oidc func(hostURL *url.URL) elephantine.OpenIDConnectConfig codes *sturdyc.Client[issuedCode] authParser elephantine.AuthInfoParser org string @@ -141,9 +143,13 @@ func (e *Elsinod) RegisterRoutes(mux *howdah.PageMux) { } func (e *Elsinod) oidcConfig( - _ context.Context, w http.ResponseWriter, _ *http.Request, + _ context.Context, w http.ResponseWriter, r *http.Request, ) (*howdah.Page, error) { - data, err := json.MarshalIndent(e.oidc, "", " ") + hostURL := getHostURLFromReq(r) + + oidc := e.oidc(hostURL) + + data, err := json.MarshalIndent(oidc, "", " ") if err != nil { return nil, fmt.Errorf("marshal config: %w", err) } @@ -159,6 +165,18 @@ func (e *Elsinod) oidcConfig( return nil, howdah.ErrSkipRender } +func getHostURLFromReq(r *http.Request) *url.URL { + scheme := "http" + if r.TLS != nil { + scheme = "https" + } + + return &url.URL{ + Scheme: scheme, + Host: r.Host, + } +} + func (e *Elsinod) keyFunc(t *jwt.Token) (any, error) { keyID, ok := t.Header["kid"].(string) if !ok { From 260f613c6d9e6e94e8d3577716637c5aa0dd9e3f Mon Sep 17 00:00:00 2001 From: Danijel Vukoje Date: Thu, 13 Nov 2025 16:14:23 +0200 Subject: [PATCH 2/2] enable dummy oidc provider to be run in docker under "mock" command --- Dockerfile | 2 +- cmd/elsinod/main.go | 92 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4a9e97f..43a45e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,4 +24,4 @@ EXPOSE 1080 # Debug/profiling server EXPOSE 1081 -ENTRYPOINT ["elsinod", "run"] +ENTRYPOINT ["elsinod", "mock"] diff --git a/cmd/elsinod/main.go b/cmd/elsinod/main.go index 3bbc065..6e12552 100644 --- a/cmd/elsinod/main.go +++ b/cmd/elsinod/main.go @@ -120,12 +120,62 @@ func main() { }, } + runOIDCMockCmd := cli.Command{ + Name: "mock", + Description: "Runs the dummy oidc provider", + Action: OIDCMockAction, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "log-level", + EnvVars: []string{"LOG_LEVEL"}, + Value: "info", + }, + &cli.StringFlag{ + Name: "addr", + Usage: "Listen address", + EnvVars: []string{"ADDR"}, + Value: ":1080", + }, + &cli.StringFlag{ + Name: "profile-addr", + Usage: "Profile listen address", + EnvVars: []string{"PROFILE_ADDR"}, + Value: ":1081", + }, + &cli.StringFlag{ + Name: "public-url", + Usage: "Publicly visible base URL", + EnvVars: []string{"PUBLIC_URL"}, + Value: "http://localhost:1080", + }, + &cli.StringFlag{ + Name: "client-secret", + Usage: "Client secret shared by all clients", + EnvVars: []string{"CLIENT_SECRET"}, + Required: true, + }, + &cli.StringFlag{ + Name: "organisation", + Usage: "The organisation used for the install", + EnvVars: []string{"ORGANISATION"}, + Value: "demo", + }, + &cli.StringFlag{ + Name: "demo-password", + Usage: "Demo password for simulating login", + EnvVars: []string{"DEMO_PASSWORD"}, + Required: true, + }, + }, + } + app := cli.App{ Name: "elsinod", Usage: "Elephant demo helper", Commands: []*cli.Command{ &runCmd, &runDeploy, + &runOIDCMockCmd, }, } @@ -427,3 +477,45 @@ type closerFunc func() error func (cf closerFunc) Close() error { return cf() } + +func OIDCMockAction(c *cli.Context) error { + ctx := c.Context + + var ( + logLevel = c.String("log-level") + addr = c.String("addr") + profileAddr = c.String("profile-addr") + publicURL = c.String("public-url") + org = c.String("organisation") + clientSecret = c.String("client-secret") + demoPassword = c.String("demo-password") + ) + + logger := elephantine.SetUpLogger(logLevel, os.Stderr) + + signingKey, err := elsinod.NewSigningKey() + if err != nil { + return fmt.Errorf("create new signing key: %w", err) + } + + keyStore := elsinod.NewStaticKeyStore("k1", signingKey) + + els, err := elsinod.New(ctx, keyStore, publicURL, clientSecret, demoPassword, org) + if err != nil { + return fmt.Errorf("create new elsinod: %w", err) + } + + server := elephantine.NewAPIServer(logger, addr, profileAddr) + + elsinodMux := server.Mux + pageMux := howdah.NewPageMux(nil, elsinodMux) + + els.RegisterRoutes(pageMux) + + err = server.ListenAndServe(ctx) + if err != nil && !errors.Is(err, http.ErrServerClosed) { + return fmt.Errorf("serve: %w", err) + } + + return nil +}