2021-05-04 22:06:05 +00:00
|
|
|
package validator
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/url"
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
"strings"
|
|
|
|
"time"
|
2021-05-04 22:06:05 +00:00
|
|
|
|
2021-08-11 01:04:35 +00:00
|
|
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
2022-10-20 02:16:36 +00:00
|
|
|
"github.com/authelia/authelia/v4/internal/oidc"
|
2021-08-11 01:04:35 +00:00
|
|
|
"github.com/authelia/authelia/v4/internal/utils"
|
2021-05-04 22:06:05 +00:00
|
|
|
)
|
|
|
|
|
2022-04-17 23:58:24 +00:00
|
|
|
// ValidateIdentityProviders validates and updates the IdentityProviders configuration.
|
2022-02-28 03:15:01 +00:00
|
|
|
func ValidateIdentityProviders(config *schema.IdentityProvidersConfiguration, validator *schema.StructValidator) {
|
|
|
|
validateOIDC(config.OIDC, validator)
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
|
2022-02-28 03:15:01 +00:00
|
|
|
func validateOIDC(config *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
2022-10-02 02:07:40 +00:00
|
|
|
if config == nil {
|
|
|
|
return
|
|
|
|
}
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
|
2022-10-02 02:07:40 +00:00
|
|
|
setOIDCDefaults(config)
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
|
2022-10-20 02:16:36 +00:00
|
|
|
switch {
|
|
|
|
case config.IssuerPrivateKey == nil:
|
2022-10-02 02:07:40 +00:00
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCNoPrivateKey))
|
2022-10-20 02:16:36 +00:00
|
|
|
default:
|
|
|
|
if config.IssuerCertificateChain.HasCertificates() {
|
|
|
|
if !config.IssuerCertificateChain.EqualKey(config.IssuerPrivateKey) {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCCertificateMismatch))
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := config.IssuerCertificateChain.Validate(); err != nil {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCCertificateChain, err))
|
|
|
|
}
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
}
|
|
|
|
|
2022-10-20 02:16:36 +00:00
|
|
|
if config.IssuerPrivateKey.Size()*8 < 2048 {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCInvalidPrivateKeyBitSize, 2048, config.IssuerPrivateKey.Size()*8))
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
}
|
2022-10-02 02:07:40 +00:00
|
|
|
}
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
|
2022-10-02 02:07:40 +00:00
|
|
|
if config.MinimumParameterEntropy != 0 && config.MinimumParameterEntropy < 8 {
|
|
|
|
validator.PushWarning(fmt.Errorf(errFmtOIDCServerInsecureParameterEntropy, config.MinimumParameterEntropy))
|
|
|
|
}
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
|
2022-10-02 02:07:40 +00:00
|
|
|
if config.EnforcePKCE != "never" && config.EnforcePKCE != "public_clients_only" && config.EnforcePKCE != "always" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCEnforcePKCEInvalidValue, config.EnforcePKCE))
|
|
|
|
}
|
2022-03-02 04:44:05 +00:00
|
|
|
|
2022-10-02 02:07:40 +00:00
|
|
|
validateOIDCOptionsCORS(config, validator)
|
2022-03-02 04:44:05 +00:00
|
|
|
|
2022-10-02 02:07:40 +00:00
|
|
|
if len(config.Clients) == 0 {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCNoClientsConfigured))
|
|
|
|
} else {
|
2022-02-28 03:15:01 +00:00
|
|
|
validateOIDCClients(config, validator)
|
2022-10-02 02:07:40 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-04 22:06:05 +00:00
|
|
|
|
2022-10-02 02:07:40 +00:00
|
|
|
func setOIDCDefaults(config *schema.OpenIDConnectConfiguration) {
|
|
|
|
if config.AccessTokenLifespan == time.Duration(0) {
|
|
|
|
config.AccessTokenLifespan = schema.DefaultOpenIDConnectConfiguration.AccessTokenLifespan
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.AuthorizeCodeLifespan == time.Duration(0) {
|
|
|
|
config.AuthorizeCodeLifespan = schema.DefaultOpenIDConnectConfiguration.AuthorizeCodeLifespan
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.IDTokenLifespan == time.Duration(0) {
|
|
|
|
config.IDTokenLifespan = schema.DefaultOpenIDConnectConfiguration.IDTokenLifespan
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.RefreshTokenLifespan == time.Duration(0) {
|
|
|
|
config.RefreshTokenLifespan = schema.DefaultOpenIDConnectConfiguration.RefreshTokenLifespan
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.EnforcePKCE == "" {
|
|
|
|
config.EnforcePKCE = schema.DefaultOpenIDConnectConfiguration.EnforcePKCE
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-07 00:58:51 +00:00
|
|
|
func validateOIDCOptionsCORS(config *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
|
|
|
validateOIDCOptionsCORSAllowedOrigins(config, validator)
|
|
|
|
|
|
|
|
if config.CORS.AllowedOriginsFromClientRedirectURIs {
|
|
|
|
validateOIDCOptionsCORSAllowedOriginsFromClientRedirectURIs(config)
|
|
|
|
}
|
|
|
|
|
|
|
|
validateOIDCOptionsCORSEndpoints(config, validator)
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateOIDCOptionsCORSAllowedOrigins(config *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
|
|
|
for _, origin := range config.CORS.AllowedOrigins {
|
|
|
|
if origin.String() == "*" {
|
|
|
|
if len(config.CORS.AllowedOrigins) != 1 {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCCORSInvalidOriginWildcard))
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.CORS.AllowedOriginsFromClientRedirectURIs {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCCORSInvalidOriginWildcardWithClients))
|
|
|
|
}
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if origin.Path != "" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCCORSInvalidOrigin, origin.String(), "path"))
|
|
|
|
}
|
|
|
|
|
|
|
|
if origin.RawQuery != "" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCCORSInvalidOrigin, origin.String(), "query string"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateOIDCOptionsCORSAllowedOriginsFromClientRedirectURIs(config *schema.OpenIDConnectConfiguration) {
|
|
|
|
for _, client := range config.Clients {
|
|
|
|
for _, redirectURI := range client.RedirectURIs {
|
2022-09-03 01:51:02 +00:00
|
|
|
uri, err := url.ParseRequestURI(redirectURI)
|
2022-04-07 00:58:51 +00:00
|
|
|
if err != nil || (uri.Scheme != schemeHTTP && uri.Scheme != schemeHTTPS) || uri.Hostname() == "localhost" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
origin := utils.OriginFromURL(*uri)
|
|
|
|
|
|
|
|
if !utils.IsURLInSlice(origin, config.CORS.AllowedOrigins) {
|
|
|
|
config.CORS.AllowedOrigins = append(config.CORS.AllowedOrigins, origin)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateOIDCOptionsCORSEndpoints(config *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
|
|
|
for _, endpoint := range config.CORS.Endpoints {
|
|
|
|
if !utils.IsStringInSlice(endpoint, validOIDCCORSEndpoints) {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCCORSInvalidEndpoint, endpoint, strings.Join(validOIDCCORSEndpoints, "', '")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-03 01:51:02 +00:00
|
|
|
|
2022-10-20 02:16:36 +00:00
|
|
|
//nolint:gocyclo // TODO: Refactor.
|
2022-02-28 03:15:01 +00:00
|
|
|
func validateOIDCClients(config *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
2021-05-04 22:06:05 +00:00
|
|
|
invalidID, duplicateIDs := false, false
|
|
|
|
|
|
|
|
var ids []string
|
|
|
|
|
2022-02-28 03:15:01 +00:00
|
|
|
for c, client := range config.Clients {
|
2021-05-04 22:06:05 +00:00
|
|
|
if client.ID == "" {
|
|
|
|
invalidID = true
|
|
|
|
} else {
|
|
|
|
if client.Description == "" {
|
2022-02-28 03:15:01 +00:00
|
|
|
config.Clients[c].Description = client.ID
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if utils.IsStringInSliceFold(client.ID, ids) {
|
|
|
|
duplicateIDs = true
|
|
|
|
}
|
|
|
|
ids = append(ids, client.ID)
|
|
|
|
}
|
|
|
|
|
2021-07-15 11:02:03 +00:00
|
|
|
if client.Public {
|
|
|
|
if client.Secret != "" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientPublicInvalidSecret, client.ID))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if client.Secret == "" {
|
2021-08-03 09:55:21 +00:00
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidSecret, client.ID))
|
2021-07-15 11:02:03 +00:00
|
|
|
}
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if client.Policy == "" {
|
2022-02-28 03:15:01 +00:00
|
|
|
config.Clients[c].Policy = schema.DefaultOpenIDConnectClientConfiguration.Policy
|
2021-08-03 09:55:21 +00:00
|
|
|
} else if client.Policy != policyOneFactor && client.Policy != policyTwoFactor {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidPolicy, client.ID, client.Policy))
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
|
2022-10-20 02:16:36 +00:00
|
|
|
switch {
|
|
|
|
case utils.IsStringInSlice(client.ConsentMode, []string{"", "auto"}):
|
|
|
|
if client.ConsentPreConfiguredDuration != nil {
|
|
|
|
config.Clients[c].ConsentMode = oidc.ClientConsentModePreConfigured.String()
|
|
|
|
} else {
|
|
|
|
config.Clients[c].ConsentMode = oidc.ClientConsentModeExplicit.String()
|
|
|
|
}
|
|
|
|
case utils.IsStringInSlice(client.ConsentMode, validOIDCClientConsentModes):
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidConsentMode, client.ID, strings.Join(append(validOIDCClientConsentModes, "auto"), "', '"), client.ConsentMode))
|
|
|
|
}
|
|
|
|
|
|
|
|
if client.ConsentPreConfiguredDuration == nil {
|
|
|
|
config.Clients[c].ConsentPreConfiguredDuration = schema.DefaultOpenIDConnectClientConfiguration.ConsentPreConfiguredDuration
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:13:01 +00:00
|
|
|
validateOIDCClientSectorIdentifier(client, validator)
|
2022-02-28 03:15:01 +00:00
|
|
|
validateOIDCClientScopes(c, config, validator)
|
|
|
|
validateOIDCClientGrantTypes(c, config, validator)
|
|
|
|
validateOIDCClientResponseTypes(c, config, validator)
|
|
|
|
validateOIDCClientResponseModes(c, config, validator)
|
|
|
|
validateOIDDClientUserinfoAlgorithm(c, config, validator)
|
2021-05-04 22:06:05 +00:00
|
|
|
validateOIDCClientRedirectURIs(client, validator)
|
|
|
|
}
|
|
|
|
|
|
|
|
if invalidID {
|
2021-08-03 09:55:21 +00:00
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientsWithEmptyID))
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if duplicateIDs {
|
2021-08-03 09:55:21 +00:00
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientsDuplicateID))
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:13:01 +00:00
|
|
|
func validateOIDCClientSectorIdentifier(client schema.OpenIDConnectClientConfiguration, validator *schema.StructValidator) {
|
|
|
|
if client.SectorIdentifier.String() != "" {
|
2022-04-08 07:38:38 +00:00
|
|
|
if utils.IsURLHostComponent(client.SectorIdentifier) || utils.IsURLHostComponentWithPort(client.SectorIdentifier) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:13:01 +00:00
|
|
|
if client.SectorIdentifier.Scheme != "" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "scheme", client.SectorIdentifier.Scheme))
|
|
|
|
|
|
|
|
if client.SectorIdentifier.Path != "" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "path", client.SectorIdentifier.Path))
|
|
|
|
}
|
|
|
|
|
|
|
|
if client.SectorIdentifier.RawQuery != "" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "query", client.SectorIdentifier.RawQuery))
|
|
|
|
}
|
|
|
|
|
|
|
|
if client.SectorIdentifier.Fragment != "" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "fragment", client.SectorIdentifier.Fragment))
|
|
|
|
}
|
|
|
|
|
|
|
|
if client.SectorIdentifier.User != nil {
|
|
|
|
if client.SectorIdentifier.User.Username() != "" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifier, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "username", client.SectorIdentifier.User.Username()))
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, set := client.SectorIdentifier.User.Password(); set {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifierWithoutValue, client.ID, client.SectorIdentifier.String(), client.SectorIdentifier.Host, "password"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if client.SectorIdentifier.Host == "" {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidSectorIdentifierHost, client.ID, client.SectorIdentifier.String()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
func validateOIDCClientScopes(c int, configuration *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
|
|
|
if len(configuration.Clients[c].Scopes) == 0 {
|
|
|
|
configuration.Clients[c].Scopes = schema.DefaultOpenIDConnectClientConfiguration.Scopes
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-10-20 02:16:36 +00:00
|
|
|
if !utils.IsStringInSlice(oidc.ScopeOpenID, configuration.Clients[c].Scopes) {
|
|
|
|
configuration.Clients[c].Scopes = append(configuration.Clients[c].Scopes, oidc.ScopeOpenID)
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, scope := range configuration.Clients[c].Scopes {
|
2021-07-10 04:56:33 +00:00
|
|
|
if !utils.IsStringInSlice(scope, validOIDCScopes) {
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
validator.Push(fmt.Errorf(
|
2022-02-28 03:15:01 +00:00
|
|
|
errFmtOIDCClientInvalidEntry,
|
|
|
|
configuration.Clients[c].ID, "scopes", strings.Join(validOIDCScopes, "', '"), scope))
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateOIDCClientGrantTypes(c int, configuration *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
|
|
|
if len(configuration.Clients[c].GrantTypes) == 0 {
|
|
|
|
configuration.Clients[c].GrantTypes = schema.DefaultOpenIDConnectClientConfiguration.GrantTypes
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, grantType := range configuration.Clients[c].GrantTypes {
|
|
|
|
if !utils.IsStringInSlice(grantType, validOIDCGrantTypes) {
|
|
|
|
validator.Push(fmt.Errorf(
|
2022-02-28 03:15:01 +00:00
|
|
|
errFmtOIDCClientInvalidEntry,
|
|
|
|
configuration.Clients[c].ID, "grant_types", strings.Join(validOIDCGrantTypes, "', '"), grantType))
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateOIDCClientResponseTypes(c int, configuration *schema.OpenIDConnectConfiguration, _ *schema.StructValidator) {
|
|
|
|
if len(configuration.Clients[c].ResponseTypes) == 0 {
|
|
|
|
configuration.Clients[c].ResponseTypes = schema.DefaultOpenIDConnectClientConfiguration.ResponseTypes
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateOIDCClientResponseModes(c int, configuration *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
|
|
|
if len(configuration.Clients[c].ResponseModes) == 0 {
|
|
|
|
configuration.Clients[c].ResponseModes = schema.DefaultOpenIDConnectClientConfiguration.ResponseModes
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, responseMode := range configuration.Clients[c].ResponseModes {
|
|
|
|
if !utils.IsStringInSlice(responseMode, validOIDCResponseModes) {
|
|
|
|
validator.Push(fmt.Errorf(
|
2022-02-28 03:15:01 +00:00
|
|
|
errFmtOIDCClientInvalidEntry,
|
|
|
|
configuration.Clients[c].ID, "response_modes", strings.Join(validOIDCResponseModes, "', '"), responseMode))
|
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-10 04:56:33 +00:00
|
|
|
func validateOIDDClientUserinfoAlgorithm(c int, configuration *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
|
|
|
if configuration.Clients[c].UserinfoSigningAlgorithm == "" {
|
|
|
|
configuration.Clients[c].UserinfoSigningAlgorithm = schema.DefaultOpenIDConnectClientConfiguration.UserinfoSigningAlgorithm
|
|
|
|
} else if !utils.IsStringInSlice(configuration.Clients[c].UserinfoSigningAlgorithm, validOIDCUserinfoAlgorithms) {
|
2021-08-03 09:55:21 +00:00
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidUserinfoAlgorithm,
|
2022-02-28 03:15:01 +00:00
|
|
|
configuration.Clients[c].ID, strings.Join(validOIDCUserinfoAlgorithms, ", "), configuration.Clients[c].UserinfoSigningAlgorithm))
|
2021-07-10 04:56:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-04 22:06:05 +00:00
|
|
|
func validateOIDCClientRedirectURIs(client schema.OpenIDConnectClientConfiguration, validator *schema.StructValidator) {
|
|
|
|
for _, redirectURI := range client.RedirectURIs {
|
2021-07-15 11:02:03 +00:00
|
|
|
if redirectURI == oauth2InstalledApp {
|
|
|
|
if client.Public {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-02-28 03:15:01 +00:00
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientRedirectURIPublic, client.ID, oauth2InstalledApp))
|
2021-05-04 22:06:05 +00:00
|
|
|
|
2021-07-15 11:02:03 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
parsedURL, err := url.Parse(redirectURI)
|
2021-05-04 22:06:05 +00:00
|
|
|
if err != nil {
|
2021-08-03 09:55:21 +00:00
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientRedirectURICantBeParsed, client.ID, redirectURI, err))
|
2021-07-15 11:02:03 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !parsedURL.IsAbs() {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientRedirectURIAbsolute, client.ID, redirectURI))
|
|
|
|
return
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
|
2022-01-21 11:05:53 +00:00
|
|
|
if !client.Public && parsedURL.Scheme != schemeHTTPS && parsedURL.Scheme != schemeHTTP {
|
2021-08-03 09:55:21 +00:00
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCClientRedirectURI, client.ID, redirectURI, parsedURL.Scheme))
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|