diff --git a/go.mod b/go.mod index 858931d5c0..bfffc32af2 100644 --- a/go.mod +++ b/go.mod @@ -95,7 +95,7 @@ require ( ) require ( - github.com/authgear/oauthrelyingparty v1.2.0 + github.com/authgear/oauthrelyingparty v1.3.0 github.com/go-jose/go-jose/v3 v3.0.3 ) diff --git a/go.sum b/go.sum index e811b75c0b..0ab1eeb31a 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/alicebob/miniredis/v2 v2.31.0 h1:ObEFUNlJwoIiyjxdrYF0QIDE7qXcLc7D3WpS github.com/alicebob/miniredis/v2 v2.31.0/go.mod h1:UB/T2Uztp7MlFSDakaX1sTXUv5CASoprx0wulRT6HBg= github.com/authgear/graphql-go-relay v0.0.0-20201016065100-df672205b892 h1:OIPk6DEk51wL35vsCYfLacc7pZ0ev8TKvmcp+EKOnPU= github.com/authgear/graphql-go-relay v0.0.0-20201016065100-df672205b892/go.mod h1:SxJGRjo7+1SFr8pfMghiCM17WWFSswRwMvtv6t1aDO8= -github.com/authgear/oauthrelyingparty v1.2.0 h1:YGlrFgz0xDukuMS6oUOwcTeoq+Exv0Lx9wKBg0QUFB4= -github.com/authgear/oauthrelyingparty v1.2.0/go.mod h1:0UcO0p5eS9BPLulX6K7TvkXkuPeTn3QhAJ/UQg4fmiQ= +github.com/authgear/oauthrelyingparty v1.3.0 h1:OqHMh4OPXIldC94zXV4GYtTesqMcMveNVhLQiFPfPTs= +github.com/authgear/oauthrelyingparty v1.3.0/go.mod h1:0UcO0p5eS9BPLulX6K7TvkXkuPeTn3QhAJ/UQg4fmiQ= github.com/aws/aws-sdk-go v1.47.9 h1:rarTsos0mA16q+huicGx0e560aYRtOucV5z2Mw23JRY= github.com/aws/aws-sdk-go v1.47.9/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= diff --git a/pkg/auth/webapp/wechat_redirect_uri_middleware.go b/pkg/auth/webapp/wechat_redirect_uri_middleware.go index 633ed1a64b..0ca60595f9 100644 --- a/pkg/auth/webapp/wechat_redirect_uri_middleware.go +++ b/pkg/auth/webapp/wechat_redirect_uri_middleware.go @@ -66,7 +66,7 @@ func (m *WeChatRedirectURIMiddleware) Handle(next http.Handler) http.Handler { func (m *WeChatRedirectURIMiddleware) isWechatEnabled() bool { for _, providerConfig := range m.IdentityConfig.OAuth.Providers { - if providerConfig.Type() == oauthrelyingpartywechat.Type { + if providerConfig.AsProviderConfig().Type() == oauthrelyingpartywechat.Type { return true } } @@ -83,7 +83,7 @@ func (m *WeChatRedirectURIMiddleware) populateWechatRedirectURI( // Validate x_wechat_redirect_uri valid := false for _, providerConfig := range m.IdentityConfig.OAuth.Providers { - if providerConfig.Type() == oauthrelyingpartywechat.Type { + if providerConfig.AsProviderConfig().Type() == oauthrelyingpartywechat.Type { for _, allowed := range oauthrelyingpartywechat.ProviderConfig(providerConfig).WechatRedirectURIs() { if weChatRedirectURI == allowed { valid = true diff --git a/pkg/lib/authenticationflow/declarative/data_identification.go b/pkg/lib/authenticationflow/declarative/data_identification.go index 44ededacc5..7dad24e2be 100644 --- a/pkg/lib/authenticationflow/declarative/data_identification.go +++ b/pkg/lib/authenticationflow/declarative/data_identification.go @@ -51,10 +51,10 @@ func NewIdentificationOptionLoginID(i config.AuthenticationFlowIdentification) I func NewIdentificationOptionsOAuth(oauthConfig *config.OAuthSSOConfig, oauthFeatureConfig *config.OAuthSSOProvidersFeatureConfig) []IdentificationOption { output := []IdentificationOption{} for _, p := range oauthConfig.Providers { - if !identity.IsOAuthSSOProviderTypeDisabled(p, oauthFeatureConfig) { + if !identity.IsOAuthSSOProviderTypeDisabled(p.AsProviderConfig(), oauthFeatureConfig) { output = append(output, IdentificationOption{ Identification: config.AuthenticationFlowIdentificationOAuth, - ProviderType: p.Type(), + ProviderType: p.AsProviderConfig().Type(), Alias: p.Alias(), WechatAppType: wechat.ProviderConfig(p).AppType(), }) diff --git a/pkg/lib/authn/identity/candidate.go b/pkg/lib/authn/identity/candidate.go index 3917b3bacd..5c7249d8d8 100644 --- a/pkg/lib/authn/identity/candidate.go +++ b/pkg/lib/authn/identity/candidate.go @@ -30,18 +30,19 @@ const ( CandidateKeyDeleteDisabled = "delete_disabled" ) -func NewOAuthCandidate(cfg oauthrelyingparty.ProviderConfig) Candidate { +func NewOAuthCandidate(cfg config.OAuthSSOProviderConfig) Candidate { return Candidate{ CandidateKeyIdentityID: "", CandidateKeyType: string(model.IdentityTypeOAuth), - CandidateKeyProviderType: string(cfg.Type()), + CandidateKeyProviderType: string(cfg.AsProviderConfig().Type()), CandidateKeyProviderAlias: cfg.Alias(), CandidateKeyProviderSubjectID: "", CandidateKeyProviderAppType: string(wechat.ProviderConfig(cfg).AppType()), CandidateKeyDisplayID: "", - CandidateKeyCreateDisabled: cfg.ModifyDisabled(), - CandidateKeyUpdateDisabled: cfg.ModifyDisabled(), - CandidateKeyDeleteDisabled: cfg.ModifyDisabled(), + CandidateKeyCreateDisabled: cfg.CreateDisabled(), + // Update is not supported + CandidateKeyUpdateDisabled: true, + CandidateKeyDeleteDisabled: cfg.DeleteDisabled(), } } diff --git a/pkg/lib/authn/identity/info.go b/pkg/lib/authn/identity/info.go index 9701232d4a..69d2300c54 100644 --- a/pkg/lib/authn/identity/info.go +++ b/pkg/lib/authn/identity/info.go @@ -4,8 +4,6 @@ import ( "fmt" "time" - "github.com/authgear/oauthrelyingparty/pkg/api/oauthrelyingparty" - "github.com/authgear/authgear-server/pkg/api/model" "github.com/authgear/authgear-server/pkg/lib/config" ) @@ -281,9 +279,9 @@ func (i *Info) findLoginIDConfig(c *config.IdentityConfig) (*config.LoginIDKeyCo return keyConfig, ok } -func (i *Info) findOAuthConfig(c *config.IdentityConfig) (oauthrelyingparty.ProviderConfig, bool) { +func (i *Info) findOAuthConfig(c *config.IdentityConfig) (config.OAuthSSOProviderConfig, bool) { alias := i.OAuth.ProviderAlias - var providerConfig oauthrelyingparty.ProviderConfig + var providerConfig config.OAuthSSOProviderConfig var ok bool = false for _, pc := range c.OAuth.Providers { pcAlias := pc.Alias() @@ -309,8 +307,7 @@ func (i *Info) CreateDisabled(c *config.IdentityConfig) bool { if !ok { return true } - // TODO(tung): Change to use create_disabled - return providerConfig.ModifyDisabled() + return providerConfig.CreateDisabled() case model.IdentityTypeAnonymous: fallthrough case model.IdentityTypeBiometric: @@ -339,8 +336,7 @@ func (i *Info) DeleteDisabled(c *config.IdentityConfig) bool { if !ok { return true } - // TODO(tung): Change to use delete_disabled - return providerConfig.ModifyDisabled() + return providerConfig.DeleteDisabled() case model.IdentityTypeAnonymous: fallthrough case model.IdentityTypeBiometric: @@ -365,12 +361,8 @@ func (i *Info) UpdateDisabled(c *config.IdentityConfig) bool { } return *keyConfig.UpdateDisabled case model.IdentityTypeOAuth: - providerConfig, ok := i.findOAuthConfig(c) - if !ok { - return true - } - // TODO(tung): Change to use update_disabled - return providerConfig.ModifyDisabled() + // Update is not supported for oauth identity + return false case model.IdentityTypeAnonymous: fallthrough case model.IdentityTypeBiometric: diff --git a/pkg/lib/authn/identity/oauth/provider.go b/pkg/lib/authn/identity/oauth/provider.go index 0717d26a4d..6dc7ea0c12 100644 --- a/pkg/lib/authn/identity/oauth/provider.go +++ b/pkg/lib/authn/identity/oauth/provider.go @@ -82,7 +82,7 @@ func (p *Provider) New( alias := "" for _, providerConfig := range p.IdentityConfig.OAuth.Providers { - providerID := providerConfig.ProviderID() + providerID := providerConfig.AsProviderConfig().ProviderID() if providerID.Equal(i.ProviderID) { alias = providerConfig.Alias() } diff --git a/pkg/lib/authn/identity/oauth/store.go b/pkg/lib/authn/identity/oauth/store.go index c5bd048b20..4d28997480 100644 --- a/pkg/lib/authn/identity/oauth/store.go +++ b/pkg/lib/authn/identity/oauth/store.go @@ -76,7 +76,7 @@ func (s *Store) scan(scn db.Scanner) (*identity.OAuth, error) { alias := "" for _, providerConfig := range s.IdentityConfig.OAuth.Providers { - providerID := providerConfig.ProviderID() + providerID := providerConfig.AsProviderConfig().ProviderID() if providerID.Equal(i.ProviderID) { alias = providerConfig.Alias() } diff --git a/pkg/lib/authn/identity/service/service.go b/pkg/lib/authn/identity/service/service.go index 166cc989d4..4ad364b124 100644 --- a/pkg/lib/authn/identity/service/service.go +++ b/pkg/lib/authn/identity/service/service.go @@ -846,10 +846,10 @@ func (s *Service) listOAuthCandidates(oauths []*identity.OAuth) []identity.Candi out := []identity.Candidate{} for _, providerConfig := range s.Identity.OAuth.Providers { pc := providerConfig - if identity.IsOAuthSSOProviderTypeDisabled(pc, s.IdentityFeatureConfig.OAuth.Providers) { + if identity.IsOAuthSSOProviderTypeDisabled(pc.AsProviderConfig(), s.IdentityFeatureConfig.OAuth.Providers) { continue } - configProviderID := pc.ProviderID() + configProviderID := pc.AsProviderConfig().ProviderID() candidate := identity.NewOAuthCandidate(pc) matched := false for _, iden := range oauths { @@ -861,7 +861,7 @@ func (s *Service) listOAuthCandidates(oauths []*identity.OAuth) []identity.Candi } } canAppend := true - if providerConfig.ModifyDisabled() && !matched { + if providerConfig.DeleteDisabled() && !matched { canAppend = false } if canAppend { diff --git a/pkg/lib/authn/identity/service/service_test.go b/pkg/lib/authn/identity/service/service_test.go index 37ce5dca88..be08fdd3e0 100644 --- a/pkg/lib/authn/identity/service/service_test.go +++ b/pkg/lib/authn/identity/service/service_test.go @@ -56,11 +56,12 @@ func TestProviderListCandidates(t *testing.T) { Convey("oauth", func() { p.Authentication.Identities = []model.IdentityType{model.IdentityTypeOAuth} - p.Identity.OAuth.Providers = []oauthrelyingparty.ProviderConfig{ + p.Identity.OAuth.Providers = []config.OAuthSSOProviderConfig{ { "alias": "google", "type": google.Type, - "modify_disabled": false, + "create_disabled": false, + "delete_disabled": false, }, } @@ -76,7 +77,7 @@ func TestProviderListCandidates(t *testing.T) { "provider_subject_id": "", "provider_app_type": "", "create_disabled": false, - "update_disabled": false, + "update_disabled": true, "delete_disabled": false, }, }) @@ -112,11 +113,12 @@ func TestProviderListCandidates(t *testing.T) { }) Convey("respect authentication", func() { - p.Identity.OAuth.Providers = []oauthrelyingparty.ProviderConfig{ + p.Identity.OAuth.Providers = []config.OAuthSSOProviderConfig{ { "alias": "google", "type": google.Type, - "modify_disabled": false, + "create_disabled": false, + "delete_disabled": false, }, } p.Identity.LoginID.Keys = []config.LoginIDKeyConfig{ @@ -182,11 +184,12 @@ func TestProviderListCandidates(t *testing.T) { userID := "a" p.Authentication.Identities = []model.IdentityType{model.IdentityTypeOAuth} - p.Identity.OAuth.Providers = []oauthrelyingparty.ProviderConfig{ + p.Identity.OAuth.Providers = []config.OAuthSSOProviderConfig{ { "alias": "google", "type": google.Type, - "modify_disabled": false, + "create_disabled": false, + "delete_disabled": false, }, } @@ -217,7 +220,7 @@ func TestProviderListCandidates(t *testing.T) { "provider_subject_id": "john.doe@gmail.com", "provider_app_type": "", "create_disabled": false, - "update_disabled": false, + "update_disabled": true, "delete_disabled": false, }, }) diff --git a/pkg/lib/config/config.go b/pkg/lib/config/config.go index 071b143db3..a9bf888e47 100644 --- a/pkg/lib/config/config.go +++ b/pkg/lib/config/config.go @@ -8,7 +8,6 @@ import ( "sigs.k8s.io/yaml" "github.com/authgear/authgear-server/pkg/api/model" - liboauthrelyingparty "github.com/authgear/authgear-server/pkg/lib/oauthrelyingparty" "github.com/authgear/authgear-server/pkg/util/validation" ) @@ -153,11 +152,10 @@ func (c *AppConfig) validateOAuthProvider(ctx *validation.Context) { } oauthProviderAliases[alias] = struct{}{} - // Validate provider config if it is a builin provider. - provider := providerConfig.MustGetProvider() - if builtinProvider, ok := provider.(liboauthrelyingparty.BuiltinProvider); ok { - builtinProvider.ValidateProviderConfig(childCtx, providerConfig) - } + // Validate provider config + provider := providerConfig.AsProviderConfig().MustGetProvider() + schema := OAuthSSOProviderConfigSchemaBuilder(validation.SchemaBuilder(provider.GetJSONSchema())).ToSimpleSchema() + childCtx.AddError(schema.Validator().ValidateValue(providerConfig)) } } diff --git a/pkg/lib/config/identity.go b/pkg/lib/config/identity.go index 9b0a5df387..10d1adb1de 100644 --- a/pkg/lib/config/identity.go +++ b/pkg/lib/config/identity.go @@ -4,6 +4,7 @@ import ( "github.com/authgear/oauthrelyingparty/pkg/api/oauthrelyingparty" "github.com/authgear/authgear-server/pkg/api/model" + "github.com/authgear/authgear-server/pkg/util/validation" ) var _ = Schema.Add("IdentityConfig", ` @@ -274,15 +275,67 @@ var _ = Schema.Add("OAuthSSOConfig", ` } `) +func OAuthSSOProviderConfigSchemaBuilder(builder validation.SchemaBuilder) validation.SchemaBuilder { + builder.Properties(). + Property("alias", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("modify_disabled", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("create_disabled", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("delete_disabled", validation.SchemaBuilder{}.Type(validation.TypeBoolean)) + builder.AddRequired("alias") + return builder +} + +type OAuthSSOProviderConfig oauthrelyingparty.ProviderConfig + +func (c OAuthSSOProviderConfig) SetDefaults() { + if _, ok := c["modify_disabled"].(bool); !ok { + c["modify_disabled"] = false + } + + if _, ok := c["create_disabled"].(bool); !ok { + c["create_disabled"] = c["modify_disabled"].(bool) + } + + if _, ok := c["delete_disabled"].(bool); !ok { + c["delete_disabled"] = c["modify_disabled"].(bool) + } + + c.AsProviderConfig().SetDefaults() + + // Cleanup deprecated fields + delete(c, "modify_disabled") +} + +func (c OAuthSSOProviderConfig) AsProviderConfig() oauthrelyingparty.ProviderConfig { + return oauthrelyingparty.ProviderConfig(c) +} + +func (c OAuthSSOProviderConfig) Alias() string { + alias, ok := c["alias"].(string) + if ok { + return alias + } + // This method is called in validateOAuthProvider which is part of the validation process + // So it is possible that alias is an invalid value + return "" +} + +func (c OAuthSSOProviderConfig) CreateDisabled() bool { + return c["create_disabled"].(bool) +} +func (c OAuthSSOProviderConfig) DeleteDisabled() bool { + return c["delete_disabled"].(bool) +} + type OAuthSSOConfig struct { - Providers []oauthrelyingparty.ProviderConfig `json:"providers,omitempty"` + Providers []OAuthSSOProviderConfig `json:"providers,omitempty"` } func (c *OAuthSSOConfig) GetProviderConfig(alias string) (oauthrelyingparty.ProviderConfig, bool) { for _, conf := range c.Providers { if conf.Alias() == alias { cc := conf - return cc, true + return cc.AsProviderConfig(), true } } return nil, false diff --git a/pkg/lib/config/testdata/config_tests.yaml b/pkg/lib/config/testdata/config_tests.yaml index 02c1b2824d..7b73ebe8d6 100644 --- a/pkg/lib/config/testdata/config_tests.yaml +++ b/pkg/lib/config/testdata/config_tests.yaml @@ -234,7 +234,7 @@ name: missing-oauth-provider-alias error: |- invalid configuration: /identity/oauth/providers/0: required - map[actual:[claims client_id modify_disabled type] expected:[alias client_id type] missing:[alias]] + map[actual:[claims client_id create_disabled delete_disabled type] expected:[alias client_id type] missing:[alias]] config: id: test http: @@ -269,7 +269,7 @@ name: oauth-provider-apple error: |- invalid configuration: /identity/oauth/providers/0: required - map[actual:[alias claims client_id modify_disabled type] expected:[alias client_id key_id team_id type] missing:[key_id team_id]] + map[actual:[alias claims client_id create_disabled delete_disabled type] expected:[alias client_id key_id team_id type] missing:[key_id team_id]] config: id: test http: @@ -286,7 +286,7 @@ name: oauth-provider-azureadv2 error: |- invalid configuration: /identity/oauth/providers/0: required - map[actual:[alias claims client_id modify_disabled type] expected:[alias client_id tenant type] missing:[tenant]] + map[actual:[alias claims client_id create_disabled delete_disabled type] expected:[alias client_id tenant type] missing:[tenant]] config: id: test http: @@ -302,7 +302,7 @@ name: oauth-provider-azureadb2c error: |- invalid configuration: /identity/oauth/providers/0: required - map[actual:[alias claims client_id modify_disabled type] expected:[alias client_id policy tenant type] missing:[policy tenant]] + map[actual:[alias claims client_id create_disabled delete_disabled type] expected:[alias client_id policy tenant type] missing:[policy tenant]] config: id: test http: @@ -319,7 +319,7 @@ name: oauth-provider-adfs error: |- invalid configuration: /identity/oauth/providers/0: required - map[actual:[alias claims client_id modify_disabled type] expected:[alias client_id discovery_document_endpoint type] missing:[discovery_document_endpoint]] + map[actual:[alias claims client_id create_disabled delete_disabled type] expected:[alias client_id discovery_document_endpoint type] missing:[discovery_document_endpoint]] config: id: test http: diff --git a/pkg/lib/config/testdata/default_config.yaml b/pkg/lib/config/testdata/default_config.yaml index 8e95e9894a..2aabf96e2a 100644 --- a/pkg/lib/config/testdata/default_config.yaml +++ b/pkg/lib/config/testdata/default_config.yaml @@ -391,7 +391,8 @@ identity: providers: - type: google alias: google - modify_disabled: false + create_disabled: false + delete_disabled: false claims: email: assume_verified: true @@ -399,7 +400,8 @@ identity: client_id: a - type: facebook alias: facebook - modify_disabled: false + create_disabled: false + delete_disabled: false claims: email: assume_verified: true @@ -407,7 +409,8 @@ identity: client_id: a - type: linkedin alias: linkedin - modify_disabled: false + create_disabled: false + delete_disabled: false claims: email: assume_verified: true @@ -415,7 +418,8 @@ identity: client_id: a - type: azureadv2 alias: azureadv2 - modify_disabled: false + create_disabled: false + delete_disabled: false claims: email: assume_verified: true @@ -424,7 +428,8 @@ identity: tenant: a - type: azureadb2c alias: azureadb2c - modify_disabled: false + create_disabled: false + delete_disabled: false claims: email: assume_verified: true @@ -434,7 +439,8 @@ identity: policy: a - type: adfs alias: adfs - modify_disabled: false + create_disabled: false + delete_disabled: false claims: email: assume_verified: true @@ -443,7 +449,8 @@ identity: discovery_document_endpoint: http://test - type: apple alias: apple - modify_disabled: false + create_disabled: false + delete_disabled: false claims: email: assume_verified: true @@ -453,7 +460,8 @@ identity: team_id: a - type: wechat alias: wechat - modify_disabled: false + create_disabled: false + delete_disabled: false claims: email: assume_verified: true diff --git a/pkg/lib/facade/coordinator.go b/pkg/lib/facade/coordinator.go index 7a382d6bb6..9761556e97 100644 --- a/pkg/lib/facade/coordinator.go +++ b/pkg/lib/facade/coordinator.go @@ -593,8 +593,8 @@ func (c *Coordinator) markOAuthEmailAsVerified(info *identity.Info) error { var cfg oauthrelyingparty.ProviderConfig for _, c := range c.IdentityConfig.OAuth.Providers { c := c - if c.ProviderID().Equal(providerID) { - cfg = c + if c.AsProviderConfig().ProviderID().Equal(providerID) { + cfg = c.AsProviderConfig() break } } diff --git a/pkg/lib/interaction/nodes/use_identity_oauth_provider.go b/pkg/lib/interaction/nodes/use_identity_oauth_provider.go index 13f732ce7c..6fb6dc1c08 100644 --- a/pkg/lib/interaction/nodes/use_identity_oauth_provider.go +++ b/pkg/lib/interaction/nodes/use_identity_oauth_provider.go @@ -26,7 +26,7 @@ type InputUseIdentityOAuthProvider interface { type EdgeUseIdentityOAuthProvider struct { IsAuthentication bool IsCreating bool - Configs []oauthrelyingparty.ProviderConfig + Configs []config.OAuthSSOProviderConfig FeatureConfig *config.OAuthSSOProvidersFeatureConfig } @@ -34,7 +34,7 @@ func (e *EdgeUseIdentityOAuthProvider) GetIdentityCandidates() []identity.Candid candidates := []identity.Candidate{} for _, c := range e.Configs { conf := c - if !identity.IsOAuthSSOProviderTypeDisabled(conf, e.FeatureConfig) { + if !identity.IsOAuthSSOProviderTypeDisabled(conf.AsProviderConfig(), e.FeatureConfig) { candidates = append(candidates, identity.NewOAuthCandidate(conf)) } } @@ -48,9 +48,9 @@ func (e *EdgeUseIdentityOAuthProvider) Instantiate(ctx *interaction.Context, gra } alias := input.GetProviderAlias() - var oauthConfig oauthrelyingparty.ProviderConfig + var oauthConfig config.OAuthSSOProviderConfig for _, c := range e.Configs { - if identity.IsOAuthSSOProviderTypeDisabled(c, e.FeatureConfig) { + if identity.IsOAuthSSOProviderTypeDisabled(c.AsProviderConfig(), e.FeatureConfig) { continue } if c.Alias() == alias { @@ -110,12 +110,12 @@ func (e *EdgeUseIdentityOAuthProvider) Instantiate(ctx *interaction.Context, gra } type NodeUseIdentityOAuthProvider struct { - IsAuthentication bool `json:"is_authentication"` - IsCreating bool `json:"is_creating"` - Config oauthrelyingparty.ProviderConfig `json:"provider_config"` - HashedNonce string `json:"hashed_nonce"` - ErrorRedirectURI string `json:"error_redirect_uri"` - RedirectURI string `json:"redirect_uri"` + IsAuthentication bool `json:"is_authentication"` + IsCreating bool `json:"is_creating"` + Config config.OAuthSSOProviderConfig `json:"provider_config"` + HashedNonce string `json:"hashed_nonce"` + ErrorRedirectURI string `json:"error_redirect_uri"` + RedirectURI string `json:"redirect_uri"` } // GetRedirectURI implements RedirectURIGetter. diff --git a/pkg/lib/interaction/nodes/use_identity_oauth_user_info.go b/pkg/lib/interaction/nodes/use_identity_oauth_user_info.go index 95fb17d8bd..e0ec07a5cc 100644 --- a/pkg/lib/interaction/nodes/use_identity_oauth_user_info.go +++ b/pkg/lib/interaction/nodes/use_identity_oauth_user_info.go @@ -8,6 +8,7 @@ import ( "github.com/authgear/authgear-server/pkg/api/model" "github.com/authgear/authgear-server/pkg/lib/authn/identity" + "github.com/authgear/authgear-server/pkg/lib/config" "github.com/authgear/authgear-server/pkg/lib/interaction" "github.com/authgear/authgear-server/pkg/util/crypto" ) @@ -24,7 +25,7 @@ type InputUseIdentityOAuthUserInfo interface { type EdgeUseIdentityOAuthUserInfo struct { IsAuthentication bool IsCreating bool - Config oauthrelyingparty.ProviderConfig + Config config.OAuthSSOProviderConfig HashedNonce string ErrorRedirectURI string } diff --git a/pkg/lib/oauthrelyingparty/adfs/provider.go b/pkg/lib/oauthrelyingparty/adfs/provider.go index 9131d683f0..3ef03e25b5 100644 --- a/pkg/lib/oauthrelyingparty/adfs/provider.go +++ b/pkg/lib/oauthrelyingparty/adfs/provider.go @@ -25,45 +25,30 @@ func (c ProviderConfig) DiscoveryDocumentEndpoint() string { } var _ oauthrelyingparty.Provider = ADFS{} -var _ liboauthrelyingparty.BuiltinProvider = ADFS{} - -var Schema = validation.NewSimpleSchema(` -{ - "type": "object", - "additionalProperties": false, - "properties": { - "alias": { "type": "string" }, - "type": { "type": "string" }, - "modify_disabled": { "type": "boolean" }, - "client_id": { "type": "string", "minLength": 1 }, - "claims": { - "type": "object", - "additionalProperties": false, - "properties": { - "email": { - "type": "object", - "additionalProperties": false, - "properties": { - "assume_verified": { "type": "boolean" }, - "required": { "type": "boolean" } - } - } - } - }, - "discovery_document_endpoint": { "type": "string", "format": "uri" } - }, - "required": ["alias", "type", "client_id", "discovery_document_endpoint"] -} -`) type ADFS struct{} -func (ADFS) ValidateProviderConfig(ctx *validation.Context, cfg oauthrelyingparty.ProviderConfig) { - ctx.AddError(Schema.Validator().ValidateValue(cfg)) +func (ADFS) GetJSONSchema() map[string]interface{} { + builder := validation.SchemaBuilder{} + builder.Type(validation.TypeObject) + builder.Properties(). + Property("type", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("client_id", validation.SchemaBuilder{}.Type(validation.TypeString).MinLength(1)). + Property("claims", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse(). + Properties(). + Property("email", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse().Properties(). + Property("assume_verified", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("required", validation.SchemaBuilder{}.Type(validation.TypeBoolean)), + ), + ). + Property("discovery_document_endpoint", validation.SchemaBuilder{}.Type(validation.TypeString).Format("uri")) + builder.Required("type", "client_id", "discovery_document_endpoint") + return builder } func (ADFS) SetDefaults(cfg oauthrelyingparty.ProviderConfig) { - cfg.SetDefaultsModifyDisabledFalse() cfg.SetDefaultsEmailClaimConfig(oauthrelyingpartyutil.Email_AssumeVerified_Required()) } diff --git a/pkg/lib/oauthrelyingparty/apple/provider.go b/pkg/lib/oauthrelyingparty/apple/provider.go index b176a92864..e7ae6155da 100644 --- a/pkg/lib/oauthrelyingparty/apple/provider.go +++ b/pkg/lib/oauthrelyingparty/apple/provider.go @@ -38,37 +38,6 @@ func (c ProviderConfig) KeyID() string { } var _ oauthrelyingparty.Provider = Apple{} -var _ liboauthrelyingparty.BuiltinProvider = Apple{} - -var Schema = validation.NewSimpleSchema(` -{ - "type": "object", - "additionalProperties": false, - "properties": { - "alias": { "type": "string" }, - "type": { "type": "string" }, - "modify_disabled": { "type": "boolean" }, - "client_id": { "type": "string", "minLength": 1 }, - "claims": { - "type": "object", - "additionalProperties": false, - "properties": { - "email": { - "type": "object", - "additionalProperties": false, - "properties": { - "assume_verified": { "type": "boolean" }, - "required": { "type": "boolean" } - } - } - } - }, - "key_id": { "type": "string" }, - "team_id": { "type": "string" } - }, - "required": ["alias", "type", "client_id", "key_id", "team_id"] -} -`) var appleOIDCConfig = oauthrelyingpartyutil.OIDCDiscoveryDocument{ JWKSUri: "https://appleid.apple.com/auth/keys", @@ -78,12 +47,28 @@ var appleOIDCConfig = oauthrelyingpartyutil.OIDCDiscoveryDocument{ type Apple struct{} -func (Apple) ValidateProviderConfig(ctx *validation.Context, cfg oauthrelyingparty.ProviderConfig) { - ctx.AddError(Schema.Validator().ValidateValue(cfg)) +func (Apple) GetJSONSchema() map[string]interface{} { + builder := validation.SchemaBuilder{} + builder.Type(validation.TypeObject) + builder.Properties(). + Property("type", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("client_id", validation.SchemaBuilder{}.Type(validation.TypeString).MinLength(1)). + Property("claims", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse(). + Properties(). + Property("email", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse().Properties(). + Property("assume_verified", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("required", validation.SchemaBuilder{}.Type(validation.TypeBoolean)), + ), + ). + Property("key_id", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("team_id", validation.SchemaBuilder{}.Type(validation.TypeString)) + builder.Required("type", "client_id", "key_id", "team_id") + return builder } func (Apple) SetDefaults(cfg oauthrelyingparty.ProviderConfig) { - cfg.SetDefaultsModifyDisabledFalse() cfg.SetDefaultsEmailClaimConfig(oauthrelyingpartyutil.Email_AssumeVerified_Required()) } diff --git a/pkg/lib/oauthrelyingparty/azureadb2c/provider.go b/pkg/lib/oauthrelyingparty/azureadb2c/provider.go index 7024b2aa1c..0536ed6ca0 100644 --- a/pkg/lib/oauthrelyingparty/azureadb2c/provider.go +++ b/pkg/lib/oauthrelyingparty/azureadb2c/provider.go @@ -31,46 +31,31 @@ func (c ProviderConfig) Policy() string { } var _ oauthrelyingparty.Provider = AzureADB2C{} -var _ liboauthrelyingparty.BuiltinProvider = AzureADB2C{} - -var Schema = validation.NewSimpleSchema(` -{ - "type": "object", - "additionalProperties": false, - "properties": { - "alias": { "type": "string" }, - "type": { "type": "string" }, - "modify_disabled": { "type": "boolean" }, - "client_id": { "type": "string", "minLength": 1 }, - "claims": { - "type": "object", - "additionalProperties": false, - "properties": { - "email": { - "type": "object", - "additionalProperties": false, - "properties": { - "assume_verified": { "type": "boolean" }, - "required": { "type": "boolean" } - } - } - } - }, - "tenant": { "type": "string" }, - "policy": { "type": "string" } - }, - "required": ["alias", "type", "client_id", "tenant", "policy"] -} -`) type AzureADB2C struct{} -func (AzureADB2C) ValidateProviderConfig(ctx *validation.Context, cfg oauthrelyingparty.ProviderConfig) { - ctx.AddError(Schema.Validator().ValidateValue(cfg)) +func (AzureADB2C) GetJSONSchema() map[string]interface{} { + builder := validation.SchemaBuilder{} + builder.Type(validation.TypeObject) + builder.Properties(). + Property("type", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("client_id", validation.SchemaBuilder{}.Type(validation.TypeString).MinLength(1)). + Property("claims", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse(). + Properties(). + Property("email", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse().Properties(). + Property("assume_verified", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("required", validation.SchemaBuilder{}.Type(validation.TypeBoolean)), + ), + ). + Property("tenant", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("policy", validation.SchemaBuilder{}.Type(validation.TypeString)) + builder.Required("type", "client_id", "tenant", "policy") + return builder } func (AzureADB2C) SetDefaults(cfg oauthrelyingparty.ProviderConfig) { - cfg.SetDefaultsModifyDisabledFalse() cfg.SetDefaultsEmailClaimConfig(oauthrelyingpartyutil.Email_AssumeVerified_Required()) } diff --git a/pkg/lib/oauthrelyingparty/azureadv2/provider.go b/pkg/lib/oauthrelyingparty/azureadv2/provider.go index 5b97d24322..7c56d8a0c4 100644 --- a/pkg/lib/oauthrelyingparty/azureadv2/provider.go +++ b/pkg/lib/oauthrelyingparty/azureadv2/provider.go @@ -26,45 +26,30 @@ func (c ProviderConfig) Tenant() string { } var _ oauthrelyingparty.Provider = AzureADv2{} -var _ liboauthrelyingparty.BuiltinProvider = AzureADv2{} - -var Schema = validation.NewSimpleSchema(` -{ - "type": "object", - "additionalProperties": false, - "properties": { - "alias": { "type": "string" }, - "type": { "type": "string" }, - "modify_disabled": { "type": "boolean" }, - "client_id": { "type": "string", "minLength": 1 }, - "claims": { - "type": "object", - "additionalProperties": false, - "properties": { - "email": { - "type": "object", - "additionalProperties": false, - "properties": { - "assume_verified": { "type": "boolean" }, - "required": { "type": "boolean" } - } - } - } - }, - "tenant": { "type": "string" } - }, - "required": ["alias", "type", "client_id", "tenant"] -} -`) type AzureADv2 struct{} -func (AzureADv2) ValidateProviderConfig(ctx *validation.Context, cfg oauthrelyingparty.ProviderConfig) { - ctx.AddError(Schema.Validator().ValidateValue(cfg)) +func (AzureADv2) GetJSONSchema() map[string]interface{} { + builder := validation.SchemaBuilder{} + builder.Type(validation.TypeObject) + builder.Properties(). + Property("type", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("client_id", validation.SchemaBuilder{}.Type(validation.TypeString).MinLength(1)). + Property("claims", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse(). + Properties(). + Property("email", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse().Properties(). + Property("assume_verified", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("required", validation.SchemaBuilder{}.Type(validation.TypeBoolean)), + ), + ). + Property("tenant", validation.SchemaBuilder{}.Type(validation.TypeString)) + builder.Required("type", "client_id", "tenant") + return builder } func (AzureADv2) SetDefaults(cfg oauthrelyingparty.ProviderConfig) { - cfg.SetDefaultsModifyDisabledFalse() cfg.SetDefaultsEmailClaimConfig(oauthrelyingpartyutil.Email_AssumeVerified_Required()) } diff --git a/pkg/lib/oauthrelyingparty/builtin.go b/pkg/lib/oauthrelyingparty/builtin.go index a568990fd7..595f3d3171 100644 --- a/pkg/lib/oauthrelyingparty/builtin.go +++ b/pkg/lib/oauthrelyingparty/builtin.go @@ -1,11 +1,5 @@ package oauthrelyingparty -import ( - "github.com/authgear/oauthrelyingparty/pkg/api/oauthrelyingparty" - - "github.com/authgear/authgear-server/pkg/util/validation" -) - const ( TypeGoogle = "google" TypeFacebook = "facebook" @@ -29,7 +23,3 @@ var BuiltinProviderTypes = []string{ TypeApple, TypeWechat, } - -type BuiltinProvider interface { - ValidateProviderConfig(ctx *validation.Context, providerConfig oauthrelyingparty.ProviderConfig) -} diff --git a/pkg/lib/oauthrelyingparty/facebook/provider.go b/pkg/lib/oauthrelyingparty/facebook/provider.go index 748e2c6456..fb12a7ee13 100644 --- a/pkg/lib/oauthrelyingparty/facebook/provider.go +++ b/pkg/lib/oauthrelyingparty/facebook/provider.go @@ -19,35 +19,6 @@ func init() { const Type = liboauthrelyingparty.TypeFacebook var _ oauthrelyingparty.Provider = Facebook{} -var _ liboauthrelyingparty.BuiltinProvider = Facebook{} - -var Schema = validation.NewSimpleSchema(` -{ - "type": "object", - "additionalProperties": false, - "properties": { - "alias": { "type": "string" }, - "type": { "type": "string" }, - "modify_disabled": { "type": "boolean" }, - "client_id": { "type": "string", "minLength": 1 }, - "claims": { - "type": "object", - "additionalProperties": false, - "properties": { - "email": { - "type": "object", - "additionalProperties": false, - "properties": { - "assume_verified": { "type": "boolean" }, - "required": { "type": "boolean" } - } - } - } - } - }, - "required": ["alias", "type", "client_id"] -} -`) const ( facebookAuthorizationURL string = "https://www.facebook.com/v11.0/dialog/oauth" @@ -58,12 +29,26 @@ const ( type Facebook struct{} -func (Facebook) ValidateProviderConfig(ctx *validation.Context, cfg oauthrelyingparty.ProviderConfig) { - ctx.AddError(Schema.Validator().ValidateValue(cfg)) +func (Facebook) GetJSONSchema() map[string]interface{} { + builder := validation.SchemaBuilder{} + builder.Type(validation.TypeObject) + builder.Properties(). + Property("type", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("client_id", validation.SchemaBuilder{}.Type(validation.TypeString).MinLength(1)). + Property("claims", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse(). + Properties(). + Property("email", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse().Properties(). + Property("assume_verified", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("required", validation.SchemaBuilder{}.Type(validation.TypeBoolean)), + ), + ) + builder.Required("type", "client_id") + return builder } func (Facebook) SetDefaults(cfg oauthrelyingparty.ProviderConfig) { - cfg.SetDefaultsModifyDisabledFalse() cfg.SetDefaultsEmailClaimConfig(oauthrelyingpartyutil.Email_AssumeVerified_Required()) } diff --git a/pkg/lib/oauthrelyingparty/github/provider.go b/pkg/lib/oauthrelyingparty/github/provider.go index 3ec1508db6..4ac4237dae 100644 --- a/pkg/lib/oauthrelyingparty/github/provider.go +++ b/pkg/lib/oauthrelyingparty/github/provider.go @@ -24,35 +24,6 @@ func init() { const Type = liboauthrelyingparty.TypeGithub var _ oauthrelyingparty.Provider = Github{} -var _ liboauthrelyingparty.BuiltinProvider = Github{} - -var Schema = validation.NewSimpleSchema(` -{ - "type": "object", - "additionalProperties": false, - "properties": { - "alias": { "type": "string" }, - "type": { "type": "string" }, - "modify_disabled": { "type": "boolean" }, - "client_id": { "type": "string", "minLength": 1 }, - "claims": { - "type": "object", - "additionalProperties": false, - "properties": { - "email": { - "type": "object", - "additionalProperties": false, - "properties": { - "assume_verified": { "type": "boolean" }, - "required": { "type": "boolean" } - } - } - } - } - }, - "required": ["alias", "type", "client_id"] -} -`) const ( githubAuthorizationURL string = "https://github.com/login/oauth/authorize" @@ -63,12 +34,26 @@ const ( type Github struct{} -func (Github) ValidateProviderConfig(ctx *validation.Context, cfg oauthrelyingparty.ProviderConfig) { - ctx.AddError(Schema.Validator().ValidateValue(cfg)) +func (Github) GetJSONSchema() map[string]interface{} { + builder := validation.SchemaBuilder{} + builder.Type(validation.TypeObject) + builder.Properties(). + Property("type", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("client_id", validation.SchemaBuilder{}.Type(validation.TypeString).MinLength(1)). + Property("claims", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse(). + Properties(). + Property("email", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse().Properties(). + Property("assume_verified", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("required", validation.SchemaBuilder{}.Type(validation.TypeBoolean)), + ), + ) + builder.Required("type", "client_id") + return builder } func (Github) SetDefaults(cfg oauthrelyingparty.ProviderConfig) { - cfg.SetDefaultsModifyDisabledFalse() cfg.SetDefaultsEmailClaimConfig(oauthrelyingpartyutil.Email_AssumeVerified_Required()) } diff --git a/pkg/lib/oauthrelyingparty/google/provider.go b/pkg/lib/oauthrelyingparty/google/provider.go index 040dbe281c..590beb8388 100644 --- a/pkg/lib/oauthrelyingparty/google/provider.go +++ b/pkg/lib/oauthrelyingparty/google/provider.go @@ -18,16 +18,12 @@ func init() { const Type = liboauthrelyingparty.TypeGoogle var _ oauthrelyingparty.Provider = Google{} -var _ liboauthrelyingparty.BuiltinProvider = Google{} var Schema = validation.NewSimpleSchema(` { "type": "object", - "additionalProperties": false, "properties": { - "alias": { "type": "string" }, "type": { "type": "string" }, - "modify_disabled": { "type": "boolean" }, "client_id": { "type": "string", "minLength": 1 }, "claims": { "type": "object", @@ -44,7 +40,7 @@ var Schema = validation.NewSimpleSchema(` } } }, - "required": ["alias", "type", "client_id"] + "required": ["type", "client_id"] } `) @@ -54,12 +50,26 @@ const ( type Google struct{} -func (Google) ValidateProviderConfig(ctx *validation.Context, cfg oauthrelyingparty.ProviderConfig) { - ctx.AddError(Schema.Validator().ValidateValue(cfg)) +func (Google) GetJSONSchema() map[string]interface{} { + builder := validation.SchemaBuilder{} + builder.Type(validation.TypeObject) + builder.Properties(). + Property("type", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("client_id", validation.SchemaBuilder{}.Type(validation.TypeString).MinLength(1)). + Property("claims", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse(). + Properties(). + Property("email", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse().Properties(). + Property("assume_verified", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("required", validation.SchemaBuilder{}.Type(validation.TypeBoolean)), + ), + ) + builder.Required("type", "client_id") + return builder } func (Google) SetDefaults(cfg oauthrelyingparty.ProviderConfig) { - cfg.SetDefaultsModifyDisabledFalse() cfg.SetDefaultsEmailClaimConfig(oauthrelyingpartyutil.Email_AssumeVerified_Required()) } diff --git a/pkg/lib/oauthrelyingparty/linkedin/provider.go b/pkg/lib/oauthrelyingparty/linkedin/provider.go index 5af5088d6c..8982802afb 100644 --- a/pkg/lib/oauthrelyingparty/linkedin/provider.go +++ b/pkg/lib/oauthrelyingparty/linkedin/provider.go @@ -16,35 +16,6 @@ func init() { const Type = liboauthrelyingparty.TypeLinkedin var _ oauthrelyingparty.Provider = Linkedin{} -var _ liboauthrelyingparty.BuiltinProvider = Linkedin{} - -var Schema = validation.NewSimpleSchema(` -{ - "type": "object", - "additionalProperties": false, - "properties": { - "alias": { "type": "string" }, - "type": { "type": "string" }, - "modify_disabled": { "type": "boolean" }, - "client_id": { "type": "string", "minLength": 1 }, - "claims": { - "type": "object", - "additionalProperties": false, - "properties": { - "email": { - "type": "object", - "additionalProperties": false, - "properties": { - "assume_verified": { "type": "boolean" }, - "required": { "type": "boolean" } - } - } - } - } - }, - "required": ["alias", "type", "client_id"] -} -`) const ( linkedinAuthorizationURL string = "https://www.linkedin.com/oauth/v2/authorization" @@ -56,12 +27,26 @@ const ( type Linkedin struct{} -func (Linkedin) ValidateProviderConfig(ctx *validation.Context, cfg oauthrelyingparty.ProviderConfig) { - ctx.AddError(Schema.Validator().ValidateValue(cfg)) +func (Linkedin) GetJSONSchema() map[string]interface{} { + builder := validation.SchemaBuilder{} + builder.Type(validation.TypeObject) + builder.Properties(). + Property("type", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("client_id", validation.SchemaBuilder{}.Type(validation.TypeString).MinLength(1)). + Property("claims", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse(). + Properties(). + Property("email", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse().Properties(). + Property("assume_verified", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("required", validation.SchemaBuilder{}.Type(validation.TypeBoolean)), + ), + ) + builder.Required("type", "client_id") + return builder } func (Linkedin) SetDefaults(cfg oauthrelyingparty.ProviderConfig) { - cfg.SetDefaultsModifyDisabledFalse() cfg.SetDefaultsEmailClaimConfig(oauthrelyingpartyutil.Email_AssumeVerified_Required()) } diff --git a/pkg/lib/oauthrelyingparty/wechat/provider.go b/pkg/lib/oauthrelyingparty/wechat/provider.go index 0a4ff53976..2edfc1cc56 100644 --- a/pkg/lib/oauthrelyingparty/wechat/provider.go +++ b/pkg/lib/oauthrelyingparty/wechat/provider.go @@ -59,39 +59,6 @@ func (c ProviderConfig) WechatRedirectURIs() []string { const Type = liboauthrelyingparty.TypeWechat var _ oauthrelyingparty.Provider = Wechat{} -var _ liboauthrelyingparty.BuiltinProvider = Wechat{} - -var Schema = validation.NewSimpleSchema(` -{ - "type": "object", - "additionalProperties": false, - "properties": { - "alias": { "type": "string" }, - "type": { "type": "string" }, - "modify_disabled": { "type": "boolean" }, - "client_id": { "type": "string", "minLength": 1 }, - "claims": { - "type": "object", - "additionalProperties": false, - "properties": { - "email": { - "type": "object", - "additionalProperties": false, - "properties": { - "assume_verified": { "type": "boolean" }, - "required": { "type": "boolean" } - } - } - } - }, - "app_type": { "type": "string", "enum": ["mobile", "web"] }, - "account_id": { "type": "string", "format": "wechat_account_id" }, - "is_sandbox_account": { "type": "boolean" }, - "wechat_redirect_uris": { "type": "array", "items": { "type": "string", "format": "uri" } } - }, - "required": ["alias", "type", "client_id", "app_type", "account_id"] -} -`) const ( wechatAuthorizationURL = "https://open.weixin.qq.com/connect/oauth2/authorize" @@ -102,12 +69,32 @@ const ( type Wechat struct{} -func (Wechat) ValidateProviderConfig(ctx *validation.Context, cfg oauthrelyingparty.ProviderConfig) { - ctx.AddError(Schema.Validator().ValidateValue(cfg)) +func (Wechat) GetJSONSchema() map[string]interface{} { + builder := validation.SchemaBuilder{} + builder.Type(validation.TypeObject) + builder.Properties(). + Property("type", validation.SchemaBuilder{}.Type(validation.TypeString)). + Property("client_id", validation.SchemaBuilder{}.Type(validation.TypeString).MinLength(1)). + Property("claims", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse(). + Properties(). + Property("email", validation.SchemaBuilder{}.Type(validation.TypeObject). + AdditionalPropertiesFalse().Properties(). + Property("assume_verified", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("required", validation.SchemaBuilder{}.Type(validation.TypeBoolean)), + ), + ). + Property("app_type", validation.SchemaBuilder{}.Type(validation.TypeString).Enum("mobile", "web")). + Property("account_id", validation.SchemaBuilder{}.Type(validation.TypeString).Format("wechat_account_id")). + Property("is_sandbox_account", validation.SchemaBuilder{}.Type(validation.TypeBoolean)). + Property("wechat_redirect_uris", validation.SchemaBuilder{}.Type(validation.TypeArray). + Items(validation.SchemaBuilder{}.Type(validation.TypeString).Format("uri")), + ) + builder.Required("type", "client_id", "app_type", "account_id") + return builder } func (Wechat) SetDefaults(cfg oauthrelyingparty.ProviderConfig) { - cfg.SetDefaultsModifyDisabledFalse() cfg.SetDefaultsEmailClaimConfig(oauthrelyingpartyutil.Email_AssumeVerified_NOT_Required()) } diff --git a/pkg/util/validation/schema_builder.go b/pkg/util/validation/schema_builder.go index 7de9f2a3a0..4760f6a6ee 100644 --- a/pkg/util/validation/schema_builder.go +++ b/pkg/util/validation/schema_builder.go @@ -57,6 +57,17 @@ func (b SchemaBuilder) Required(keys ...string) SchemaBuilder { return b } +func (b SchemaBuilder) AddRequired(keys ...string) SchemaBuilder { + originals, ok := b["required"].([]string) + if ok { + newRequired := append(originals, keys...) + b["required"] = newRequired + } else { + b["required"] = keys + } + return b +} + func (b SchemaBuilder) Enum(values ...interface{}) SchemaBuilder { b["enum"] = values return b diff --git a/portal/src/graphql/portal/SingleSignOnConfigurationWidget.tsx b/portal/src/graphql/portal/SingleSignOnConfigurationWidget.tsx index 830c225dbd..4b1c5f77b0 100644 --- a/portal/src/graphql/portal/SingleSignOnConfigurationWidget.tsx +++ b/portal/src/graphql/portal/SingleSignOnConfigurationWidget.tsx @@ -81,7 +81,8 @@ const oauthProviders: Record = { "client_secret", "key_id", "team_id", - "modify_disabled", + "create_disabled", + "delete_disabled", ]), isSecretFieldTextArea: true, }, @@ -92,7 +93,8 @@ const oauthProviders: Record = { "alias", "client_id", "client_secret", - "modify_disabled", + "create_disabled", + "delete_disabled", ]), isSecretFieldTextArea: false, }, @@ -105,7 +107,8 @@ const oauthProviders: Record = { "alias", "client_id", "client_secret", - "modify_disabled", + "create_disabled", + "delete_disabled", ]), isSecretFieldTextArea: false, }, @@ -116,7 +119,8 @@ const oauthProviders: Record = { "alias", "client_id", "client_secret", - "modify_disabled", + "create_disabled", + "delete_disabled", "email_required", ]), isSecretFieldTextArea: false, @@ -130,7 +134,8 @@ const oauthProviders: Record = { "alias", "client_id", "client_secret", - "modify_disabled", + "create_disabled", + "delete_disabled", ]), isSecretFieldTextArea: false, }, @@ -144,7 +149,8 @@ const oauthProviders: Record = { "client_id", "client_secret", "tenant", - "modify_disabled", + "create_disabled", + "delete_disabled", "email_required", ]), isSecretFieldTextArea: false, @@ -160,7 +166,8 @@ const oauthProviders: Record = { "client_secret", "tenant", "policy", - "modify_disabled", + "create_disabled", + "delete_disabled", "email_required", ]), isSecretFieldTextArea: false, @@ -175,7 +182,8 @@ const oauthProviders: Record = { "client_id", "client_secret", "discovery_document_endpoint", - "modify_disabled", + "create_disabled", + "delete_disabled", "email_required", ]), isSecretFieldTextArea: false, @@ -190,7 +198,8 @@ const oauthProviders: Record = { "client_secret", "account_id", "is_sandbox_account", - "modify_disabled", + "create_disabled", + "delete_disabled", ]), isSecretFieldTextArea: false, }, @@ -204,7 +213,8 @@ const oauthProviders: Record = { "client_secret", "account_id", "wechat_redirect_uris", - "modify_disabled", + "create_disabled", + "delete_disabled", ]), isSecretFieldTextArea: false, }, @@ -346,9 +356,14 @@ const SingleSignOnConfigurationWidget: React.VFC - onChange({ ...config, modify_disabled: value ?? false }, secret), + onChange({ ...config, create_disabled: value ?? false }, secret), + [onChange, config, secret] + ); + const onDeleteDisabledChange = useCallback( + (_, value?: boolean) => + onChange({ ...config, delete_disabled: value ?? false }, secret), [onChange, config, secret] ); const onEmailRequiredChange = useCallback( @@ -590,14 +605,25 @@ const SingleSignOnConfigurationWidget: React.VFC ) : null} - {visibleFields.has("modify_disabled") ? ( + {visibleFields.has("create_disabled") ? ( + + ) : null} + {visibleFields.has("delete_disabled") ? ( ) : null} diff --git a/portal/src/locale-data/en.json b/portal/src/locale-data/en.json index c80eee6d8d..acbf018ec8 100644 --- a/portal/src/locale-data/en.json +++ b/portal/src/locale-data/en.json @@ -655,7 +655,8 @@ "SingleSignOnConfigurationScreen.widget.account-id": "Account ID (原始 ID)", "SingleSignOnConfigurationScreen.widget.is-sandbox-account": "Is Sandbox account", "SingleSignOnConfigurationScreen.widget.email-required": "Require the email attribute", - "SingleSignOnConfigurationScreen.widget.modify-disabled": "Forbid the user to connect or disconnect after signup", + "SingleSignOnConfigurationScreen.widget.create-disabled": "Forbid the user to connect after signup", + "SingleSignOnConfigurationScreen.widget.delete-disabled": "Forbid the user to disconnect after signup", "SingleSignOnConfigurationScreen.widget.discovery-document-endpoint": "Discovery Document Endpoint", "SingleSignOnConfigurationScreen.widget.client-secret.error": "Invalid client secret", "SingleSignOnConfigurationScreen.widget.add-uri": "Add URI", diff --git a/portal/src/types.ts b/portal/src/types.ts index f6c6f76a59..be570abfed 100644 --- a/portal/src/types.ts +++ b/portal/src/types.ts @@ -86,7 +86,8 @@ export interface OAuthClaimsConfig { export interface OAuthSSOProviderConfig { alias: string; type: OAuthSSOProviderType; - modify_disabled?: boolean; + create_disabled?: boolean; + delete_disabled?: boolean; client_id?: string; tenant?: string; key_id?: string;