diff --git a/cmd/serve.go b/cmd/serve.go index 67cec1a..5318c87 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -2,6 +2,7 @@ package cmd import ( opaal "davidallendj/opaal/internal" + "davidallendj/opaal/internal/oidc" "errors" "fmt" "net/http" @@ -9,23 +10,31 @@ import ( "github.com/spf13/cobra" ) -var exampleCmd = &cobra.Command{ +var ( + endpoints oidc.Endpoints +) + +var serveCmd = &cobra.Command{ Use: "serve", - Short: "Start an simple identity provider server", + Short: "Start an simple, bare minimal identity provider server", Long: "The built-in identity provider is not (nor meant to be) a complete OIDC implementation and behaves like an external IdP", Run: func(cmd *cobra.Command, args []string) { s := opaal.NewServerWithConfig(&config) // FIXME: change how the server address is set with `NewServerWithConfig` s.Server.Addr = fmt.Sprintf("%s:%d", s.Issuer.Host, s.Issuer.Port) - err := s.StartIdentityProvider() + err := s.StartIdentityProvider(endpoints) if errors.Is(err, http.ErrServerClosed) { fmt.Printf("Identity provider server closed.\n") } else if err != nil { - fmt.Errorf("failed to start server: %v", err) + fmt.Printf("failed to start server: %v", err) } }, } func init() { - rootCmd.AddCommand(exampleCmd) + serveCmd.Flags().StringVar(&endpoints.Authorization, "endpoints.authorization", "", "set the authorization endpoint for the identity provider") + serveCmd.Flags().StringVar(&endpoints.Token, "endpoints.token", "", "set the token endpoint for the identity provider") + serveCmd.Flags().StringVar(&endpoints.JwksUri, "endpoints.jwks_uri", "", "set the JWKS endpoints for the identity provider") + + rootCmd.AddCommand(serveCmd) } diff --git a/internal/oidc/oidc.go b/internal/oidc/oidc.go index 2ec1f9c..f3382fc 100644 --- a/internal/oidc/oidc.go +++ b/internal/oidc/oidc.go @@ -164,3 +164,25 @@ func (p *IdentityProvider) FetchJwks() error { return nil } + +func (p *IdentityProvider) UpdateEndpoints(other *IdentityProvider) { + UpdateEndpoints(&p.Endpoints, &other.Endpoints) +} + +func UpdateEndpoints(eps *Endpoints, other *Endpoints) { + // only update endpoints that are not empty + var UpdateIf = func(ep *string, s string) { + if ep != nil { + if *ep != "" { + *ep = s + } + } + } + UpdateIf(&eps.Config, other.Config) + UpdateIf(&eps.Authorization, other.Authorization) + UpdateIf(&eps.Token, other.Token) + UpdateIf(&eps.Revocation, other.Revocation) + UpdateIf(&eps.Introspection, other.Introspection) + UpdateIf(&eps.UserInfo, other.UserInfo) + UpdateIf(&eps.JwksUri, other.JwksUri) +} diff --git a/internal/server/idp.go b/internal/server/idp.go index 67c70b1..4822e91 100644 --- a/internal/server/idp.go +++ b/internal/server/idp.go @@ -22,7 +22,7 @@ import ( "github.com/lestrrat-go/jwx/v2/jwt" ) -func (s *Server) StartIdentityProvider() error { +func (s *Server) StartIdentityProvider(eps oidc.Endpoints) error { // NOTE: this example does NOT implement CSRF tokens nor use them // create an example identity provider @@ -38,6 +38,14 @@ func (s *Server) StartIdentityProvider() error { callback = "/oidc/callback" } + // update endpoints that have values set + defaultEps := oidc.Endpoints{ + Authorization: "http://" + s.Addr + "/oauth/authorize", + Token: "http://" + s.Addr + "/oauth/token", + JwksUri: "http://" + s.Addr + "/.well-known/jwks.json", + } + oidc.UpdateEndpoints(&eps, &defaultEps) + // generate key pair used to sign JWKS and create JWTs privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { @@ -72,14 +80,13 @@ func (s *Server) StartIdentityProvider() error { w.Write(b) }) - // TODO: create .well-known openid configuration r.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { // create config JSON to serve with GET request config := map[string]any{ "issuer": "http://" + s.Addr, - "authorization_endpoint": "http://" + s.Addr + "/oauth/authorize", - "token_endpoint": "http://" + s.Addr + "/oauth/token", - "jwks_uri": "http://" + s.Addr + "/.well-known/jwks.json", + "authorization_endpoint": eps.Authorization, + "token_endpoint": eps.Token, + "jwks_uri": eps.JwksUri, "scopes_supported": []string{ "openid", "profile", diff --git a/internal/server/server.go b/internal/server/server.go index 3c7507b..c829a34 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -18,16 +18,17 @@ import ( type Server struct { *http.Server - Host string `yaml:"host"` - Port int `yaml:"port"` - Callback string `yaml:"callback"` - State string `yaml:"state"` - Issuer Issuer `yaml:"issuer"` + Host string `yaml:"host"` + Port int `yaml:"port"` + Callback string `yaml:"callback"` + State string `yaml:"state"` + Issuer IdentityProviderServer `yaml:"issuer"` } -type Issuer struct { - Host string `yaml:"host"` - Port int `yaml:"port"` +type IdentityProviderServer struct { + Host string `yaml:"host"` + Port int `yaml:"port"` + Endpoints oidc.Endpoints `yaml:"endpoints"` } type ServerParams struct {