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
|
|
|
|
|
|
|
"github.com/authelia/authelia/internal/configuration/schema"
|
|
|
|
"github.com/authelia/authelia/internal/utils"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ValidateIdentityProviders validates and update IdentityProviders configuration.
|
|
|
|
func ValidateIdentityProviders(configuration *schema.IdentityProvidersConfiguration, validator *schema.StructValidator) {
|
|
|
|
validateOIDC(configuration.OIDC, validator)
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateOIDC(configuration *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
|
|
|
if configuration != nil {
|
|
|
|
if configuration.IssuerPrivateKey == "" {
|
|
|
|
validator.Push(fmt.Errorf("OIDC Server issuer private key must be provided"))
|
|
|
|
}
|
|
|
|
|
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
|
|
|
if configuration.AccessTokenLifespan == time.Duration(0) {
|
|
|
|
configuration.AccessTokenLifespan = schema.DefaultOpenIDConnectConfiguration.AccessTokenLifespan
|
|
|
|
}
|
|
|
|
|
|
|
|
if configuration.AuthorizeCodeLifespan == time.Duration(0) {
|
|
|
|
configuration.AuthorizeCodeLifespan = schema.DefaultOpenIDConnectConfiguration.AuthorizeCodeLifespan
|
|
|
|
}
|
|
|
|
|
|
|
|
if configuration.IDTokenLifespan == time.Duration(0) {
|
|
|
|
configuration.IDTokenLifespan = schema.DefaultOpenIDConnectConfiguration.IDTokenLifespan
|
|
|
|
}
|
|
|
|
|
|
|
|
if configuration.RefreshTokenLifespan == time.Duration(0) {
|
|
|
|
configuration.RefreshTokenLifespan = schema.DefaultOpenIDConnectConfiguration.RefreshTokenLifespan
|
|
|
|
}
|
|
|
|
|
|
|
|
if configuration.MinimumParameterEntropy != 0 && configuration.MinimumParameterEntropy < 8 {
|
|
|
|
validator.PushWarning(fmt.Errorf(errFmtOIDCServerInsecureParameterEntropy, configuration.MinimumParameterEntropy))
|
|
|
|
}
|
|
|
|
|
2021-05-04 22:06:05 +00:00
|
|
|
validateOIDCClients(configuration, validator)
|
|
|
|
|
|
|
|
if len(configuration.Clients) == 0 {
|
|
|
|
validator.Push(fmt.Errorf("OIDC Server has no clients defined"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateOIDCClients(configuration *schema.OpenIDConnectConfiguration, validator *schema.StructValidator) {
|
|
|
|
invalidID, duplicateIDs := false, false
|
|
|
|
|
|
|
|
var ids []string
|
|
|
|
|
|
|
|
for c, client := range configuration.Clients {
|
|
|
|
if client.ID == "" {
|
|
|
|
invalidID = true
|
|
|
|
} else {
|
|
|
|
if client.Description == "" {
|
|
|
|
configuration.Clients[c].Description = client.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
if utils.IsStringInSliceFold(client.ID, ids) {
|
|
|
|
duplicateIDs = true
|
|
|
|
}
|
|
|
|
ids = append(ids, client.ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
if client.Secret == "" {
|
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(errFmtOIDCServerClientInvalidSecret, client.ID))
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if client.Policy == "" {
|
|
|
|
configuration.Clients[c].Policy = schema.DefaultOpenIDConnectClientConfiguration.Policy
|
|
|
|
} else if client.Policy != oneFactorPolicy && client.Policy != twoFactorPolicy {
|
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(errFmtOIDCServerClientInvalidPolicy, client.ID, client.Policy))
|
2021-05-04 22:06:05 +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
|
|
|
validateOIDCClientScopes(c, configuration, validator)
|
|
|
|
validateOIDCClientGrantTypes(c, configuration, validator)
|
|
|
|
validateOIDCClientResponseTypes(c, configuration, validator)
|
|
|
|
validateOIDCClientResponseModes(c, configuration, validator)
|
2021-05-04 22:06:05 +00:00
|
|
|
|
|
|
|
validateOIDCClientRedirectURIs(client, validator)
|
|
|
|
}
|
|
|
|
|
|
|
|
if invalidID {
|
|
|
|
validator.Push(fmt.Errorf("OIDC Server has one or more clients with an empty ID"))
|
|
|
|
}
|
|
|
|
|
|
|
|
if duplicateIDs {
|
|
|
|
validator.Push(fmt.Errorf("OIDC Server has clients with duplicate ID's"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
if !utils.IsStringInSlice("openid", configuration.Clients[c].Scopes) {
|
|
|
|
configuration.Clients[c].Scopes = append(configuration.Clients[c].Scopes, "openid")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, scope := range configuration.Clients[c].Scopes {
|
|
|
|
if !utils.IsStringInSlice(scope, validScopes) {
|
|
|
|
validator.Push(fmt.Errorf(
|
|
|
|
errFmtOIDCServerClientInvalidScope,
|
|
|
|
configuration.Clients[c].ID, scope, strings.Join(validScopes, "', '")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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(
|
|
|
|
errFmtOIDCServerClientInvalidGrantType,
|
|
|
|
configuration.Clients[c].ID, grantType, strings.Join(validOIDCGrantTypes, "', '")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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(
|
|
|
|
errFmtOIDCServerClientInvalidResponseMode,
|
|
|
|
configuration.Clients[c].ID, responseMode, strings.Join(validOIDCResponseModes, "', '")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-04 22:06:05 +00:00
|
|
|
func validateOIDCClientRedirectURIs(client schema.OpenIDConnectClientConfiguration, validator *schema.StructValidator) {
|
|
|
|
for _, redirectURI := range client.RedirectURIs {
|
|
|
|
parsedURI, err := url.Parse(redirectURI)
|
|
|
|
|
|
|
|
if err != nil {
|
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(errFmtOIDCServerClientRedirectURICantBeParsed, client.ID, redirectURI, err))
|
2021-05-04 22:06:05 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
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
|
|
|
if parsedURI.Scheme != schemeHTTPS && parsedURI.Scheme != schemeHTTP {
|
|
|
|
validator.Push(fmt.Errorf(errFmtOIDCServerClientRedirectURI, client.ID, redirectURI, parsedURI.Scheme))
|
2021-05-04 22:06:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|