diff --git a/cmd/dex/config.go b/cmd/dex/config.go index dd6d2e2ab9..9734af0ea9 100644 --- a/cmd/dex/config.go +++ b/cmd/dex/config.go @@ -149,6 +149,8 @@ type OAuth2 struct { AlwaysShowLoginScreen bool `json:"alwaysShowLoginScreen"` // This is the connector that can be used for password grant PasswordConnector string `json:"passwordConnector"` + // List of additional scope prefixes to allow + AllowedScopePrefixes []string `json:"allowedScopePrefixes"` } // Web is the config format for the HTTP server. diff --git a/cmd/dex/serve.go b/cmd/dex/serve.go index 8a69c7ee3e..9a8150b0e9 100644 --- a/cmd/dex/serve.go +++ b/cmd/dex/serve.go @@ -280,6 +280,9 @@ func runServe(options serveOptions) error { if len(c.Web.AllowedOrigins) > 0 { logger.Info("config allowed origins", "origins", c.Web.AllowedOrigins) } + if len(c.OAuth2.AllowedScopePrefixes) > 0 { + logger.Info("config allowed scope prefixes", "prefixes", strings.Join(c.OAuth2.AllowedScopePrefixes, ",")) + } // explicitly convert to UTC. now := func() time.Time { return time.Now().UTC() } @@ -295,6 +298,7 @@ func runServe(options serveOptions) error { Headers: c.Web.Headers.ToHTTPHeader(), AllowedOrigins: c.Web.AllowedOrigins, AllowedHeaders: c.Web.AllowedHeaders, + AllowedScopePrefixes: c.OAuth2.AllowedScopePrefixes, Issuer: c.Issuer, Storage: s, Web: c.Frontend, diff --git a/server/handlers.go b/server/handlers.go index 73358fe2c2..87981f98bd 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -1143,7 +1143,16 @@ func (s *Server) handlePasswordGrant(w http.ResponseWriter, r *http.Request, cli default: peerID, ok := parseCrossClientScope(scope) if !ok { - unrecognized = append(unrecognized, scope) + var recognized bool + for _, prefix := range s.allowedScopePrefixes { + if strings.HasPrefix(scope, prefix) { + recognized = true + break + } + } + if !recognized { + unrecognized = append(unrecognized, scope) + } continue } diff --git a/server/oauth2.go b/server/oauth2.go index ade9321c9f..f4b20a610c 100644 --- a/server/oauth2.go +++ b/server/oauth2.go @@ -93,6 +93,7 @@ func tokenErr(w http.ResponseWriter, typ, description string, statusCode int) er return nil } +// nolint const ( errInvalidRequest = "invalid_request" errUnauthorizedClient = "unauthorized_client" @@ -551,7 +552,16 @@ func (s *Server) parseAuthorizationRequest(r *http.Request) (*storage.AuthReques default: peerID, ok := parseCrossClientScope(scope) if !ok { - unrecognized = append(unrecognized, scope) + var recognized bool + for _, prefix := range s.allowedScopePrefixes { + if strings.HasPrefix(scope, prefix) { + recognized = true + break + } + } + if !recognized { + unrecognized = append(unrecognized, scope) + } continue } diff --git a/server/server.go b/server/server.go index 463d4d5cbc..12ecdd9818 100644 --- a/server/server.go +++ b/server/server.go @@ -120,7 +120,8 @@ type Config struct { PrometheusRegistry *prometheus.Registry - HealthChecker gosundheit.Health + HealthChecker gosundheit.Health + AllowedScopePrefixes []string } // WebConfig holds the server's frontend templates and asset configuration. @@ -189,6 +190,8 @@ type Server struct { supportedGrantTypes []string + allowedScopePrefixes []string + now func() time.Time idTokensValidFor time.Duration @@ -304,6 +307,7 @@ func newServer(ctx context.Context, c Config, rotationStrategy rotationStrategy) storage: newKeyCacher(c.Storage, now), supportedResponseTypes: supportedRes, supportedGrantTypes: supportedGrants, + allowedScopePrefixes: c.AllowedScopePrefixes, idTokensValidFor: value(c.IDTokensValidFor, 24*time.Hour), authRequestsValidFor: value(c.AuthRequestsValidFor, 24*time.Hour), deviceRequestsValidFor: value(c.DeviceRequestsValidFor, 5*time.Minute),