summaryrefslogtreecommitdiff
path: root/internal/configuration/validator/identity_providers.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/configuration/validator/identity_providers.go')
-rw-r--r--internal/configuration/validator/identity_providers.go380
1 files changed, 272 insertions, 108 deletions
diff --git a/internal/configuration/validator/identity_providers.go b/internal/configuration/validator/identity_providers.go
index b9ea7e9b9..cb61e31db 100644
--- a/internal/configuration/validator/identity_providers.go
+++ b/internal/configuration/validator/identity_providers.go
@@ -3,6 +3,7 @@ package validator
import (
"fmt"
"net/url"
+ "strconv"
"strings"
"time"
@@ -125,10 +126,10 @@ func validateOIDCOptionsCORSAllowedOriginsFromClientRedirectURIs(config *schema.
continue
}
- origin := utils.OriginFromURL(*uri)
+ origin := utils.OriginFromURL(uri)
- if !utils.IsURLInSlice(origin, config.CORS.AllowedOrigins) {
- config.CORS.AllowedOrigins = append(config.CORS.AllowedOrigins, origin)
+ if !utils.IsURLInSlice(*origin, config.CORS.AllowedOrigins) {
+ config.CORS.AllowedOrigins = append(config.CORS.AllowedOrigins, *origin)
}
}
}
@@ -137,113 +138,135 @@ func validateOIDCOptionsCORSAllowedOriginsFromClientRedirectURIs(config *schema.
func validateOIDCOptionsCORSEndpoints(config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
for _, endpoint := range config.CORS.Endpoints {
if !utils.IsStringInSlice(endpoint, validOIDCCORSEndpoints) {
- val.Push(fmt.Errorf(errFmtOIDCCORSInvalidEndpoint, endpoint, strings.Join(validOIDCCORSEndpoints, "', '")))
+ val.Push(fmt.Errorf(errFmtOIDCCORSInvalidEndpoint, endpoint, strJoinOr(validOIDCCORSEndpoints)))
}
}
}
func validateOIDCClients(config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
- invalidID, duplicateIDs := false, false
+ var (
+ errDeprecated bool
- var ids []string
+ clientIDs, duplicateClientIDs, blankClientIDs []string
+ )
+
+ errDeprecatedFunc := func() { errDeprecated = true }
for c, client := range config.Clients {
if client.ID == "" {
- invalidID = true
+ blankClientIDs = append(blankClientIDs, "#"+strconv.Itoa(c+1))
} else {
if client.Description == "" {
config.Clients[c].Description = client.ID
}
- if utils.IsStringInSliceFold(client.ID, ids) {
- duplicateIDs = true
+ if id := strings.ToLower(client.ID); utils.IsStringInSlice(id, clientIDs) {
+ if !utils.IsStringInSlice(id, duplicateClientIDs) {
+ duplicateClientIDs = append(duplicateClientIDs, id)
+ }
+ } else {
+ clientIDs = append(clientIDs, id)
}
- ids = append(ids, client.ID)
}
- if client.Public {
- if client.Secret != nil {
- val.Push(fmt.Errorf(errFmtOIDCClientPublicInvalidSecret, client.ID))
- }
- } else {
- if client.Secret == nil {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidSecret, client.ID))
- } else if client.Secret.IsPlainText() {
- val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidSecretPlainText, client.ID))
- }
- }
+ validateOIDCClient(c, config, val, errDeprecatedFunc)
+ }
- if client.Policy == "" {
- config.Clients[c].Policy = schema.DefaultOpenIDConnectClientConfiguration.Policy
- } else if client.Policy != policyOneFactor && client.Policy != policyTwoFactor {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidPolicy, client.ID, client.Policy))
- }
+ if errDeprecated {
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientsDeprecated))
+ }
- switch client.PKCEChallengeMethod {
- case "", "plain", "S256":
- break
- default:
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidPKCEChallengeMethod, client.ID, client.PKCEChallengeMethod))
- }
+ if len(blankClientIDs) != 0 {
+ val.Push(fmt.Errorf(errFmtOIDCClientsWithEmptyID, buildJoinedString(", ", "or", "", blankClientIDs)))
+ }
- validateOIDCClientConsentMode(c, config, val)
- validateOIDCClientSectorIdentifier(client, val)
- validateOIDCClientScopes(c, config, val)
- validateOIDCClientGrantTypes(c, config, val)
- validateOIDCClientResponseTypes(c, config, val)
- validateOIDCClientResponseModes(c, config, val)
- validateOIDDClientUserinfoAlgorithm(c, config, val)
- validateOIDCClientRedirectURIs(client, val)
+ if len(duplicateClientIDs) != 0 {
+ val.Push(fmt.Errorf(errFmtOIDCClientsDuplicateID, strJoinOr(duplicateClientIDs)))
}
+}
- if invalidID {
- val.Push(fmt.Errorf(errFmtOIDCClientsWithEmptyID))
+func validateOIDCClient(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator, errDeprecatedFunc func()) {
+ if config.Clients[c].Public {
+ if config.Clients[c].Secret != nil {
+ val.Push(fmt.Errorf(errFmtOIDCClientPublicInvalidSecret, config.Clients[c].ID))
+ }
+ } else {
+ if config.Clients[c].Secret == nil {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidSecret, config.Clients[c].ID))
+ } else if config.Clients[c].Secret.IsPlainText() {
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidSecretPlainText, config.Clients[c].ID))
+ }
}
- if duplicateIDs {
- val.Push(fmt.Errorf(errFmtOIDCClientsDuplicateID))
+ switch config.Clients[c].Policy {
+ case "":
+ config.Clients[c].Policy = schema.DefaultOpenIDConnectClientConfiguration.Policy
+ case policyOneFactor, policyTwoFactor:
+ break
+ default:
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue, config.Clients[c].ID, "policy", strJoinOr([]string{policyOneFactor, policyTwoFactor}), config.Clients[c].Policy))
+ }
+
+ switch config.Clients[c].PKCEChallengeMethod {
+ case "", oidc.PKCEChallengeMethodPlain, oidc.PKCEChallengeMethodSHA256:
+ break
+ default:
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue, config.Clients[c].ID, attrOIDCPKCEChallengeMethod, strJoinOr([]string{oidc.PKCEChallengeMethodPlain, oidc.PKCEChallengeMethodSHA256}), config.Clients[c].PKCEChallengeMethod))
}
+
+ validateOIDCClientConsentMode(c, config, val)
+
+ validateOIDCClientScopes(c, config, val, errDeprecatedFunc)
+ validateOIDCClientResponseTypes(c, config, val, errDeprecatedFunc)
+ validateOIDCClientResponseModes(c, config, val, errDeprecatedFunc)
+ validateOIDCClientGrantTypes(c, config, val, errDeprecatedFunc)
+ validateOIDCClientRedirectURIs(c, config, val, errDeprecatedFunc)
+
+ validateOIDCClientTokenEndpointAuthMethod(c, config, val)
+ validateOIDDClientUserinfoAlgorithm(c, config, val)
+
+ validateOIDCClientSectorIdentifier(c, config, val)
}
-func validateOIDCClientSectorIdentifier(client schema.OpenIDConnectClientConfiguration, val *schema.StructValidator) {
- if client.SectorIdentifier.String() != "" {
- if utils.IsURLHostComponent(client.SectorIdentifier) || utils.IsURLHostComponentWithPort(client.SectorIdentifier) {
+func validateOIDCClientSectorIdentifier(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
+ if config.Clients[c].SectorIdentifier.String() != "" {
+ if utils.IsURLHostComponent(config.Clients[c].SectorIdentifier) || utils.IsURLHostComponentWithPort(config.Clients[c].SectorIdentifier) {
return
}
- if client.SectorIdentifier.Scheme != "" {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "scheme", client.SectorIdentifier.Scheme))
+ if config.Clients[c].SectorIdentifier.Scheme != "" {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, config.Clients[c].ID, config.Clients[c].SectorIdentifier.String(), config.Clients[c].SectorIdentifier.Host, "scheme", config.Clients[c].SectorIdentifier.Scheme))
- if client.SectorIdentifier.Path != "" {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "path", client.SectorIdentifier.Path))
+ if config.Clients[c].SectorIdentifier.Path != "" {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, config.Clients[c].ID, config.Clients[c].SectorIdentifier.String(), config.Clients[c].SectorIdentifier.Host, "path", config.Clients[c].SectorIdentifier.Path))
}
- if client.SectorIdentifier.RawQuery != "" {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "query", client.SectorIdentifier.RawQuery))
+ if config.Clients[c].SectorIdentifier.RawQuery != "" {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, config.Clients[c].ID, config.Clients[c].SectorIdentifier.String(), config.Clients[c].SectorIdentifier.Host, "query", config.Clients[c].SectorIdentifier.RawQuery))
}
- if client.SectorIdentifier.Fragment != "" {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "fragment", client.SectorIdentifier.Fragment))
+ if config.Clients[c].SectorIdentifier.Fragment != "" {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, config.Clients[c].ID, config.Clients[c].SectorIdentifier.String(), config.Clients[c].SectorIdentifier.Host, "fragment", config.Clients[c].SectorIdentifier.Fragment))
}
- if client.SectorIdentifier.User != nil {
- if client.SectorIdentifier.User.Username() != "" {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "username", client.SectorIdentifier.User.Username()))
+ if config.Clients[c].SectorIdentifier.User != nil {
+ if config.Clients[c].SectorIdentifier.User.Username() != "" {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, config.Clients[c].ID, config.Clients[c].SectorIdentifier.String(), config.Clients[c].SectorIdentifier.Host, "username", config.Clients[c].SectorIdentifier.User.Username()))
}
- if _, set := client.SectorIdentifier.User.Password(); set {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifierWithoutValue, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "password"))
+ if _, set := config.Clients[c].SectorIdentifier.User.Password(); set {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifierWithoutValue, config.Clients[c].ID, config.Clients[c].SectorIdentifier.String(), config.Clients[c].SectorIdentifier.Host, "password"))
}
}
- } else if client.SectorIdentifier.Host == "" {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifierHost, client.ID, client.SectorIdentifier.String()))
+ } else if config.Clients[c].SectorIdentifier.Host == "" {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifierHost, config.Clients[c].ID, config.Clients[c].SectorIdentifier.String()))
}
}
}
func validateOIDCClientConsentMode(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
switch {
- case utils.IsStringInSlice(config.Clients[c].ConsentMode, []string{"", "auto"}):
+ case utils.IsStringInSlice(config.Clients[c].ConsentMode, []string{"", auto}):
if config.Clients[c].ConsentPreConfiguredDuration != nil {
config.Clients[c].ConsentMode = oidc.ClientConsentModePreConfigured.String()
} else {
@@ -252,7 +275,7 @@ func validateOIDCClientConsentMode(c int, config *schema.OpenIDConnectConfigurat
case utils.IsStringInSlice(config.Clients[c].ConsentMode, validOIDCClientConsentModes):
break
default:
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidConsentMode, config.Clients[c].ID, strings.Join(append(validOIDCClientConsentModes, "auto"), "', '"), config.Clients[c].ConsentMode))
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidConsentMode, config.Clients[c].ID, strJoinOr(append(validOIDCClientConsentModes, auto)), config.Clients[c].ConsentMode))
}
if config.Clients[c].ConsentMode == oidc.ClientConsentModePreConfigured.String() && config.Clients[c].ConsentPreConfiguredDuration == nil {
@@ -260,92 +283,233 @@ func validateOIDCClientConsentMode(c int, config *schema.OpenIDConnectConfigurat
}
}
-func validateOIDCClientScopes(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
+func validateOIDCClientScopes(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator, errDeprecatedFunc func()) {
if len(config.Clients[c].Scopes) == 0 {
config.Clients[c].Scopes = schema.DefaultOpenIDConnectClientConfiguration.Scopes
- return
}
if !utils.IsStringInSlice(oidc.ScopeOpenID, config.Clients[c].Scopes) {
- config.Clients[c].Scopes = append(config.Clients[c].Scopes, oidc.ScopeOpenID)
+ config.Clients[c].Scopes = append([]string{oidc.ScopeOpenID}, config.Clients[c].Scopes...)
}
- for _, scope := range config.Clients[c].Scopes {
- if !utils.IsStringInSlice(scope, validOIDCScopes) {
- val.Push(fmt.Errorf(
- errFmtOIDCClientInvalidEntry,
- config.Clients[c].ID, "scopes", strings.Join(validOIDCScopes, "', '"), scope))
- }
+ invalid, duplicates := validateList(config.Clients[c].Scopes, validOIDCClientScopes, true)
+
+ if len(invalid) != 0 {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidEntries, config.Clients[c].ID, attrOIDCScopes, strJoinOr(validOIDCClientScopes), strJoinAnd(invalid)))
}
-}
-func validateOIDCClientGrantTypes(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
- if len(config.Clients[c].GrantTypes) == 0 {
- config.Clients[c].GrantTypes = schema.DefaultOpenIDConnectClientConfiguration.GrantTypes
- return
+ if len(duplicates) != 0 {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidEntryDuplicates, config.Clients[c].ID, attrOIDCScopes, strJoinAnd(duplicates)))
}
- for _, grantType := range config.Clients[c].GrantTypes {
- if !utils.IsStringInSlice(grantType, validOIDCGrantTypes) {
- val.Push(fmt.Errorf(
- errFmtOIDCClientInvalidEntry,
- config.Clients[c].ID, "grant_types", strings.Join(validOIDCGrantTypes, "', '"), grantType))
- }
+ if utils.IsStringSliceContainsAny([]string{oidc.ScopeOfflineAccess, oidc.ScopeOffline}, config.Clients[c].Scopes) &&
+ !utils.IsStringSliceContainsAny(validOIDCClientResponseTypesRefreshToken, config.Clients[c].ResponseTypes) {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidRefreshTokenOptionWithoutCodeResponseType,
+ config.Clients[c].ID, attrOIDCScopes,
+ strJoinOr([]string{oidc.ScopeOfflineAccess, oidc.ScopeOffline}),
+ strJoinOr(validOIDCClientResponseTypesRefreshToken)),
+ )
}
}
-func validateOIDCClientResponseTypes(c int, config *schema.OpenIDConnectConfiguration, _ *schema.StructValidator) {
+func validateOIDCClientResponseTypes(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator, errDeprecatedFunc func()) {
if len(config.Clients[c].ResponseTypes) == 0 {
config.Clients[c].ResponseTypes = schema.DefaultOpenIDConnectClientConfiguration.ResponseTypes
- return
+ }
+
+ invalid, duplicates := validateList(config.Clients[c].ResponseTypes, validOIDCClientResponseTypes, true)
+
+ if len(invalid) != 0 {
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidEntries, config.Clients[c].ID, attrOIDCResponseTypes, strJoinOr(validOIDCClientResponseTypes), strJoinAnd(invalid)))
+ }
+
+ if len(duplicates) != 0 {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidEntryDuplicates, config.Clients[c].ID, attrOIDCResponseTypes, strJoinAnd(duplicates)))
}
}
-func validateOIDCClientResponseModes(c int, config *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
+func validateOIDCClientResponseModes(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator, errDeprecatedFunc func()) {
if len(config.Clients[c].ResponseModes) == 0 {
config.Clients[c].ResponseModes = schema.DefaultOpenIDConnectClientConfiguration.ResponseModes
- return
+
+ for _, responseType := range config.Clients[c].ResponseTypes {
+ switch responseType {
+ case oidc.ResponseTypeAuthorizationCodeFlow:
+ if !utils.IsStringInSlice(oidc.ResponseModeQuery, config.Clients[c].ResponseModes) {
+ config.Clients[c].ResponseModes = append(config.Clients[c].ResponseModes, oidc.ResponseModeQuery)
+ }
+ case oidc.ResponseTypeImplicitFlowIDToken, oidc.ResponseTypeImplicitFlowToken, oidc.ResponseTypeImplicitFlowBoth,
+ oidc.ResponseTypeHybridFlowIDToken, oidc.ResponseTypeHybridFlowToken, oidc.ResponseTypeHybridFlowBoth:
+ if !utils.IsStringInSlice(oidc.ResponseModeFragment, config.Clients[c].ResponseModes) {
+ config.Clients[c].ResponseModes = append(config.Clients[c].ResponseModes, oidc.ResponseModeFragment)
+ }
+ }
+ }
+ }
+
+ invalid, duplicates := validateList(config.Clients[c].ResponseModes, validOIDCClientResponseModes, true)
+
+ if len(invalid) != 0 {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidEntries, config.Clients[c].ID, attrOIDCResponseModes, strJoinOr(validOIDCClientResponseModes), strJoinAnd(invalid)))
+ }
+
+ if len(duplicates) != 0 {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidEntryDuplicates, config.Clients[c].ID, attrOIDCResponseModes, strJoinAnd(duplicates)))
+ }
+}
+
+func validateOIDCClientGrantTypes(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator, errDeprecatedFunc func()) {
+ if len(config.Clients[c].GrantTypes) == 0 {
+ validateOIDCClientGrantTypesSetDefaults(c, config)
+ }
+
+ validateOIDCClientGrantTypesCheckRelated(c, config, val, errDeprecatedFunc)
+
+ invalid, duplicates := validateList(config.Clients[c].GrantTypes, validOIDCClientGrantTypes, true)
+
+ if len(invalid) != 0 {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidEntries, config.Clients[c].ID, attrOIDCGrantTypes, strJoinOr(validOIDCClientGrantTypes), strJoinAnd(invalid)))
}
- for _, responseMode := range config.Clients[c].ResponseModes {
- if !utils.IsStringInSlice(responseMode, validOIDCResponseModes) {
- validator.Push(fmt.Errorf(
- errFmtOIDCClientInvalidEntry,
- config.Clients[c].ID, "response_modes", strings.Join(validOIDCResponseModes, "', '"), responseMode))
+ if len(duplicates) != 0 {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidEntryDuplicates, config.Clients[c].ID, attrOIDCGrantTypes, strJoinAnd(duplicates)))
+ }
+}
+
+func validateOIDCClientGrantTypesSetDefaults(c int, config *schema.OpenIDConnectConfiguration) {
+ for _, responseType := range config.Clients[c].ResponseTypes {
+ switch responseType {
+ case oidc.ResponseTypeAuthorizationCodeFlow:
+ if !utils.IsStringInSlice(oidc.GrantTypeAuthorizationCode, config.Clients[c].GrantTypes) {
+ config.Clients[c].GrantTypes = append(config.Clients[c].GrantTypes, oidc.GrantTypeAuthorizationCode)
+ }
+ case oidc.ResponseTypeImplicitFlowIDToken, oidc.ResponseTypeImplicitFlowToken, oidc.ResponseTypeImplicitFlowBoth:
+ if !utils.IsStringInSlice(oidc.GrantTypeImplicit, config.Clients[c].GrantTypes) {
+ config.Clients[c].GrantTypes = append(config.Clients[c].GrantTypes, oidc.GrantTypeImplicit)
+ }
+ case oidc.ResponseTypeHybridFlowIDToken, oidc.ResponseTypeHybridFlowToken, oidc.ResponseTypeHybridFlowBoth:
+ if !utils.IsStringInSlice(oidc.GrantTypeAuthorizationCode, config.Clients[c].GrantTypes) {
+ config.Clients[c].GrantTypes = append(config.Clients[c].GrantTypes, oidc.GrantTypeAuthorizationCode)
+ }
+
+ if !utils.IsStringInSlice(oidc.GrantTypeImplicit, config.Clients[c].GrantTypes) {
+ config.Clients[c].GrantTypes = append(config.Clients[c].GrantTypes, oidc.GrantTypeImplicit)
+ }
}
}
}
-func validateOIDDClientUserinfoAlgorithm(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
- if config.Clients[c].UserinfoSigningAlgorithm == "" {
- config.Clients[c].UserinfoSigningAlgorithm = schema.DefaultOpenIDConnectClientConfiguration.UserinfoSigningAlgorithm
- } else if !utils.IsStringInSlice(config.Clients[c].UserinfoSigningAlgorithm, validOIDCUserinfoAlgorithms) {
- val.Push(fmt.Errorf(errFmtOIDCClientInvalidUserinfoAlgorithm,
- config.Clients[c].ID, strings.Join(validOIDCUserinfoAlgorithms, ", "), config.Clients[c].UserinfoSigningAlgorithm))
+func validateOIDCClientGrantTypesCheckRelated(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator, errDeprecatedFunc func()) {
+ for _, grantType := range config.Clients[c].GrantTypes {
+ switch grantType {
+ case oidc.GrantTypeImplicit:
+ if !utils.IsStringSliceContainsAny(validOIDCClientResponseTypesImplicitFlow, config.Clients[c].ResponseTypes) && !utils.IsStringSliceContainsAny(validOIDCClientResponseTypesHybridFlow, config.Clients[c].ResponseTypes) {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidGrantTypeMatch, config.Clients[c].ID, grantType, "for either the implicit or hybrid flow", strJoinOr(append(append([]string{}, validOIDCClientResponseTypesImplicitFlow...), validOIDCClientResponseTypesHybridFlow...)), strJoinAnd(config.Clients[c].ResponseTypes)))
+ }
+ case oidc.GrantTypeAuthorizationCode:
+ if !utils.IsStringInSlice(oidc.ResponseTypeAuthorizationCodeFlow, config.Clients[c].ResponseTypes) && !utils.IsStringSliceContainsAny(validOIDCClientResponseTypesHybridFlow, config.Clients[c].ResponseTypes) {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidGrantTypeMatch, config.Clients[c].ID, grantType, "for either the authorization code or hybrid flow", strJoinOr(append([]string{oidc.ResponseTypeAuthorizationCodeFlow}, validOIDCClientResponseTypesHybridFlow...)), strJoinAnd(config.Clients[c].ResponseTypes)))
+ }
+ case oidc.GrantTypeRefreshToken:
+ if !utils.IsStringSliceContainsAny([]string{oidc.ScopeOfflineAccess, oidc.ScopeOffline}, config.Clients[c].Scopes) {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidGrantTypeRefresh, config.Clients[c].ID))
+ }
+
+ if !utils.IsStringSliceContainsAny(validOIDCClientResponseTypesRefreshToken, config.Clients[c].ResponseTypes) {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidRefreshTokenOptionWithoutCodeResponseType,
+ config.Clients[c].ID, attrOIDCGrantTypes,
+ strJoinOr([]string{oidc.GrantTypeRefreshToken}),
+ strJoinOr(validOIDCClientResponseTypesRefreshToken)),
+ )
+ }
+ }
}
}
-func validateOIDCClientRedirectURIs(client schema.OpenIDConnectClientConfiguration, val *schema.StructValidator) {
- for _, redirectURI := range client.RedirectURIs {
+func validateOIDCClientRedirectURIs(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator, errDeprecatedFunc func()) {
+ var (
+ parsedRedirectURI *url.URL
+ err error
+ )
+
+ for _, redirectURI := range config.Clients[c].RedirectURIs {
if redirectURI == oauth2InstalledApp {
- if client.Public {
+ if config.Clients[c].Public {
continue
}
- val.Push(fmt.Errorf(errFmtOIDCClientRedirectURIPublic, client.ID, oauth2InstalledApp))
+ val.Push(fmt.Errorf(errFmtOIDCClientRedirectURIPublic, config.Clients[c].ID, oauth2InstalledApp))
continue
}
- parsedURL, err := url.Parse(redirectURI)
- if err != nil {
- val.Push(fmt.Errorf(errFmtOIDCClientRedirectURICantBeParsed, client.ID, redirectURI, err))
+ if parsedRedirectURI, err = url.Parse(redirectURI); err != nil {
+ val.Push(fmt.Errorf(errFmtOIDCClientRedirectURICantBeParsed, config.Clients[c].ID, redirectURI, err))
continue
}
- if !parsedURL.IsAbs() || (!client.Public && parsedURL.Scheme == "") {
- val.Push(fmt.Errorf(errFmtOIDCClientRedirectURIAbsolute, client.ID, redirectURI))
+ if !parsedRedirectURI.IsAbs() || (!config.Clients[c].Public && parsedRedirectURI.Scheme == "") {
+ val.Push(fmt.Errorf(errFmtOIDCClientRedirectURIAbsolute, config.Clients[c].ID, redirectURI))
return
}
}
+
+ _, duplicates := validateList(config.Clients[c].RedirectURIs, nil, true)
+
+ if len(duplicates) != 0 {
+ errDeprecatedFunc()
+
+ val.PushWarning(fmt.Errorf(errFmtOIDCClientInvalidEntryDuplicates, config.Clients[c].ID, attrOIDCRedirectURIs, strJoinAnd(duplicates)))
+ }
+}
+
+func validateOIDCClientTokenEndpointAuthMethod(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
+ implcit := len(config.Clients[c].ResponseTypes) != 0 && utils.IsStringSliceContainsAll(config.Clients[c].ResponseTypes, validOIDCClientResponseTypesImplicitFlow)
+
+ if config.Clients[c].TokenEndpointAuthMethod == "" && (config.Clients[c].Public || implcit) {
+ config.Clients[c].TokenEndpointAuthMethod = oidc.ClientAuthMethodNone
+ }
+
+ switch {
+ case config.Clients[c].TokenEndpointAuthMethod == "":
+ break
+ case !utils.IsStringInSlice(config.Clients[c].TokenEndpointAuthMethod, validOIDCClientTokenEndpointAuthMethods):
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue,
+ config.Clients[c].ID, attrOIDCTokenAuthMethod, strJoinOr(validOIDCClientTokenEndpointAuthMethods), config.Clients[c].TokenEndpointAuthMethod))
+ case config.Clients[c].TokenEndpointAuthMethod == oidc.ClientAuthMethodNone && !config.Clients[c].Public && !implcit:
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidTokenEndpointAuthMethod,
+ config.Clients[c].ID, strJoinOr(validOIDCClientTokenEndpointAuthMethodsConfidential), strJoinAnd(validOIDCClientResponseTypesImplicitFlow), config.Clients[c].TokenEndpointAuthMethod))
+ case config.Clients[c].TokenEndpointAuthMethod != oidc.ClientAuthMethodNone && config.Clients[c].Public:
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidTokenEndpointAuthMethodPublic,
+ config.Clients[c].ID, config.Clients[c].TokenEndpointAuthMethod))
+ }
+}
+
+func validateOIDDClientUserinfoAlgorithm(c int, config *schema.OpenIDConnectConfiguration, val *schema.StructValidator) {
+ if config.Clients[c].UserinfoSigningAlgorithm == "" {
+ config.Clients[c].UserinfoSigningAlgorithm = schema.DefaultOpenIDConnectClientConfiguration.UserinfoSigningAlgorithm
+ }
+
+ if !utils.IsStringInSlice(config.Clients[c].UserinfoSigningAlgorithm, validOIDCClientUserinfoAlgorithms) {
+ val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue,
+ config.Clients[c].ID, attrOIDCUsrSigAlg, strJoinOr(validOIDCClientUserinfoAlgorithms), config.Clients[c].UserinfoSigningAlgorithm))
+ }
}