Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ EXPOSE 1080
# Debug/profiling server
EXPOSE 1081

ENTRYPOINT ["elsinod", "run"]
ENTRYPOINT ["elsinod", "mock"]
92 changes: 92 additions & 0 deletions cmd/elsinod/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
}

Expand Down Expand Up @@ -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
}
76 changes: 47 additions & 29 deletions elsinod.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand All @@ -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 {
Expand Down