Skip to content

Commit

Permalink
fix(configuration): missing request_uris option (#7033)
Browse files Browse the repository at this point in the history
This fixes a missing option for OpenID Connect 1.0 clients 'request_uris'. This feature was effectively implemented but no way to configure it existed.

Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
  • Loading branch information
james-d-elliott committed Mar 27, 2024
1 parent e944418 commit ab4d14c
Show file tree
Hide file tree
Showing 14 changed files with 136 additions and 17 deletions.
2 changes: 1 addition & 1 deletion cmd/authelia-scripts/cmd/gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions config.template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,11 @@ notifier:
# redirect_uris:
# - 'https://oidc.example.com:8080/oauth2/callback'

## Request URI's specifies a list of valid case-sensitive TLS-secured URIs for this client for use as
## URIs to fetch Request Objects.
# request_uris:
# - 'https://oidc.example.com:8080/oidc/request-object.jwk'

## Audience this client is allowed to request.
# audience: []

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ identity_providers:
public: false
redirect_uris:
- 'https://oidc.example.com:8080/oauth2/callback'
request_uris:
- 'https://oidc.example.com:8080/oidc/request-object.jwk'
audience:
- 'https://app.example.com'
scopes:
Expand Down Expand Up @@ -201,6 +203,15 @@ their redirect URIs are as follows:
2. The redirect URIs are case-sensitive.
3. The URI must include a scheme and that scheme must be one of `http` or `https`.

### request_uris

{{< confkey type="list(string)" required="no" >}}

A list of URIs which can be used for the OpenID Connect 1.0 Request Object to pass Authorize Request parameters via a
JSON Web Token remote URI using the `request_uri` parameter.

These URIs must have the `https` scheme.

### audience

{{< confkey type="list(string)" required="no" >}}
Expand Down
11 changes: 8 additions & 3 deletions docs/static/schemas/latest/json-schema/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -1205,9 +1205,14 @@
"default": false
},
"redirect_uris": {
"$ref": "#/$defs/IdentityProvidersOpenIDConnectClientRedirectURIs",
"$ref": "#/$defs/IdentityProvidersOpenIDConnectClientURIs",
"title": "Redirect URIs",
"description": "List of authorized redirect URIs."
"description": "List of whitelisted redirect URIs."
},
"request_uris": {
"$ref": "#/$defs/IdentityProvidersOpenIDConnectClientURIs",
"title": "Request URIs",
"description": "List of whitelisted request URIs."
},
"audience": {
"items": {
Expand Down Expand Up @@ -1540,7 +1545,7 @@
],
"description": "IdentityProvidersOpenIDConnectClient represents a configuration for an OpenID Connect 1.0 client."
},
"IdentityProvidersOpenIDConnectClientRedirectURIs": {
"IdentityProvidersOpenIDConnectClientURIs": {
"oneOf": [
{
"type": "string",
Expand Down
11 changes: 8 additions & 3 deletions docs/static/schemas/v4.38/json-schema/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -1205,9 +1205,14 @@
"default": false
},
"redirect_uris": {
"$ref": "#/$defs/IdentityProvidersOpenIDConnectClientRedirectURIs",
"$ref": "#/$defs/IdentityProvidersOpenIDConnectClientURIs",
"title": "Redirect URIs",
"description": "List of authorized redirect URIs."
"description": "List of whitelisted redirect URIs."
},
"request_uris": {
"$ref": "#/$defs/IdentityProvidersOpenIDConnectClientURIs",
"title": "Request URIs",
"description": "List of whitelisted request URIs."
},
"audience": {
"items": {
Expand Down Expand Up @@ -1540,7 +1545,7 @@
],
"description": "IdentityProvidersOpenIDConnectClient represents a configuration for an OpenID Connect 1.0 client."
},
"IdentityProvidersOpenIDConnectClientRedirectURIs": {
"IdentityProvidersOpenIDConnectClientURIs": {
"oneOf": [
{
"type": "string",
Expand Down
5 changes: 5 additions & 0 deletions internal/configuration/config.template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,11 @@ notifier:
# redirect_uris:
# - 'https://oidc.example.com:8080/oauth2/callback'

## Request URI's specifies a list of valid case-sensitive TLS-secured URIs for this client for use as
## URIs to fetch Request Objects.
# request_uris:
# - 'https://oidc.example.com:8080/oidc/request-object.jwk'

## Audience this client is allowed to request.
# audience: []

Expand Down
3 changes: 2 additions & 1 deletion internal/configuration/schema/identity_providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ type IdentityProvidersOpenIDConnectClient struct {
SectorIdentifierURI *url.URL `koanf:"sector_identifier_uri" json:"sector_identifier_uri" jsonschema:"title=Sector Identifier URI" jsonschema_description:"The Client Sector Identifier URI for Privacy Isolation via Pairwise subject types."`
Public bool `koanf:"public" json:"public" jsonschema:"default=false,title=Public" jsonschema_description:"Enables the Public Client Type."`

RedirectURIs IdentityProvidersOpenIDConnectClientRedirectURIs `koanf:"redirect_uris" json:"redirect_uris" jsonschema:"title=Redirect URIs" jsonschema_description:"List of authorized redirect URIs."`
RedirectURIs IdentityProvidersOpenIDConnectClientURIs `koanf:"redirect_uris" json:"redirect_uris" jsonschema:"title=Redirect URIs" jsonschema_description:"List of whitelisted redirect URIs."`
RequestURIs IdentityProvidersOpenIDConnectClientURIs `koanf:"request_uris" json:"request_uris" jsonschema:"title=Request URIs" jsonschema_description:"List of whitelisted request URIs."`

Audience []string `koanf:"audience" json:"audience" jsonschema:"uniqueItems,title=Audience" jsonschema_description:"List of authorized audiences."`
Scopes []string `koanf:"scopes" json:"scopes" jsonschema:"required,enum=openid,enum=offline_access,enum=groups,enum=email,enum=profile,enum=authelia.bearer.authz,uniqueItems,title=Scopes" jsonschema_description:"The Scopes this client is allowed request and be granted."`
Expand Down
1 change: 1 addition & 0 deletions internal/configuration/schema/keys.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions internal/configuration/schema/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,9 @@ func (AccessControlRuleNetworks) JSONSchema() *jsonschema.Schema {
return &jsonschemaWeakStringUniqueSlice
}

type IdentityProvidersOpenIDConnectClientRedirectURIs []string
type IdentityProvidersOpenIDConnectClientURIs []string

func (IdentityProvidersOpenIDConnectClientRedirectURIs) JSONSchema() *jsonschema.Schema {
func (IdentityProvidersOpenIDConnectClientURIs) JSONSchema() *jsonschema.Schema {
return &jsonschema.Schema{
OneOf: []*jsonschema.Schema{
&jsonschemaURI,
Expand Down
2 changes: 1 addition & 1 deletion internal/configuration/schema/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ func TestJSONSchema(t *testing.T) {
&AccessControlRuleMethods{},
&AccessControlRuleRegex{},
&AccessControlRuleSubjects{},
&IdentityProvidersOpenIDConnectClientRedirectURIs{},
&IdentityProvidersOpenIDConnectClientURIs{},
}

for _, tc := range testCases {
Expand Down
10 changes: 10 additions & 0 deletions internal/configuration/validator/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,15 @@ const (
"for the openid connect confidential client type"
errFmtOIDCClientRedirectURIAbsolute = errFmtOIDCClientRedirectURIHas +
"an invalid value: redirect uri '%s' must have a scheme but it's absent"

errFmtOIDCClientRequestURIHas = errFmtOIDCClientOption + "'request_uris' has "
errFmtOIDCClientRequestURICantBeParsed = errFmtOIDCClientRequestURIHas +
"an invalid value: request uri '%s' could not be parsed: %v"
errFmtOIDCClientRequestURINotAbsolute = errFmtOIDCClientRequestURIHas +
"an invalid value: request uri '%s' must have a scheme but it's absent"
errFmtOIDCClientRequestURIInvalidScheme = errFmtOIDCClientRequestURIHas +
"an invalid scheme: scheme must be 'https' but request uri '%s' has a '%s' scheme"

errFmtOIDCClientInvalidConsentMode = "identity_providers: oidc: clients: client '%s': consent: option 'mode' must be one of " +
"%s but it's configured as '%s'"
errFmtOIDCClientInvalidEntries = errFmtOIDCClientOption + errFmtMustOnlyHaveValues +
Expand Down Expand Up @@ -512,6 +521,7 @@ const (
attrOIDCResponseModes = "response_modes"
attrOIDCGrantTypes = "grant_types"
attrOIDCRedirectURIs = "redirect_uris"
attrOIDCRequestURIs = "request_uris"
attrOIDCTokenAuthMethod = "token_endpoint_auth_method"
attrOIDCDiscoSigAlg = "discovery_signed_response_alg"
attrOIDCDiscoSigKID = "discovery_signed_response_key_id"
Expand Down
27 changes: 27 additions & 0 deletions internal/configuration/validator/identity_providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ func validateOIDCClient(c int, config *schema.IdentityProvidersOpenIDConnect, va
validateOIDCClientResponseModes(c, config, validator, setDefaults, errDeprecatedFunc)
validateOIDCClientGrantTypes(c, config, validator, setDefaults, errDeprecatedFunc)
validateOIDCClientRedirectURIs(c, config, validator, errDeprecatedFunc)
validateOIDCClientRequestURIs(c, config, validator)

validateOIDDClientSigningAlgs(c, config, validator)

Expand Down Expand Up @@ -929,6 +930,32 @@ func validateOIDCClientRedirectURIs(c int, config *schema.IdentityProvidersOpenI
}
}

func validateOIDCClientRequestURIs(c int, config *schema.IdentityProvidersOpenIDConnect, validator *schema.StructValidator) {
var (
parsedRequestURI *url.URL
err error
)

for _, requestURI := range config.Clients[c].RequestURIs {
if parsedRequestURI, err = url.Parse(requestURI); err != nil {
validator.Push(fmt.Errorf(errFmtOIDCClientRequestURICantBeParsed, config.Clients[c].ID, requestURI, err))
continue
}

if !parsedRequestURI.IsAbs() {
validator.Push(fmt.Errorf(errFmtOIDCClientRequestURINotAbsolute, config.Clients[c].ID, requestURI))
} else if parsedRequestURI.Scheme != schemeHTTPS {
validator.Push(fmt.Errorf(errFmtOIDCClientRequestURIInvalidScheme, config.Clients[c].ID, requestURI, parsedRequestURI.Scheme))
}
}

_, duplicates := validateList(config.Clients[c].RequestURIs, nil, true)

if len(duplicates) != 0 {
validator.Push(fmt.Errorf(errFmtOIDCClientInvalidEntryDuplicates, config.Clients[c].ID, attrOIDCRequestURIs, strJoinAnd(duplicates)))
}
}

//nolint:gocyclo
func validateOIDCClientTokenEndpointAuth(c int, config *schema.IdentityProvidersOpenIDConnect, validator *schema.StructValidator) {
implicit := len(config.Clients[c].ResponseTypes) != 0 && utils.IsStringSliceContainsAll(config.Clients[c].ResponseTypes, validOIDCClientResponseTypesImplicitFlow)
Expand Down
60 changes: 54 additions & 6 deletions internal/configuration/validator/identity_providers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,54 @@ func TestShouldRaiseErrorWhenOIDCServerClientBadValues(t *testing.T) {
"identity_providers: oidc: clients: client 'client-check-uri-abs': option 'redirect_uris' has an invalid value: redirect uri 'google.com' must have a scheme but it's absent",
},
},
{
name: "RequestURINotValidURI",
clients: []schema.IdentityProvidersOpenIDConnectClient{
{
ID: "client-check-uri-parse",
Secret: tOpenIDConnectPlainTextClientSecret,
AuthorizationPolicy: policyTwoFactor,
RequestURIs: []string{
"http://abc@%two",
},
},
},
errors: []string{
"identity_providers: oidc: clients: client 'client-check-uri-parse': option 'request_uris' has an invalid value: request uri 'http://abc@%two' could not be parsed: parse \"http://abc@%two\": invalid URL escape \"%tw\"",
},
},
{
name: "RequestURINotAbsolute",
clients: []schema.IdentityProvidersOpenIDConnectClient{
{
ID: "client-check-uri-parse",
Secret: tOpenIDConnectPlainTextClientSecret,
AuthorizationPolicy: policyTwoFactor,
RequestURIs: []string{
exampleDotCom,
},
},
},
errors: []string{
"identity_providers: oidc: clients: client 'client-check-uri-parse': option 'request_uris' has an invalid value: request uri 'example.com' must have a scheme but it's absent",
},
},
{
name: "RequestURINotSecure",
clients: []schema.IdentityProvidersOpenIDConnectClient{
{
ID: "client-check-uri-parse",
Secret: tOpenIDConnectPlainTextClientSecret,
AuthorizationPolicy: policyTwoFactor,
RequestURIs: []string{
"http://" + exampleDotCom,
},
},
},
errors: []string{
"identity_providers: oidc: clients: client 'client-check-uri-parse': option 'request_uris' has an invalid scheme: scheme must be 'https' but request uri 'http://example.com' has a 'http' scheme",
},
},
{
name: "ValidSectorIdentifier",
clients: []schema.IdentityProvidersOpenIDConnectClient{
Expand Down Expand Up @@ -1405,7 +1453,7 @@ func TestValidateOIDCClients(t *testing.T) {
}
},
func(t *testing.T, have *schema.IdentityProvidersOpenIDConnect) {
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientRedirectURIs([]string{"https://google.com"}), have.Clients[0].RedirectURIs)
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientURIs([]string{"https://google.com"}), have.Clients[0].RedirectURIs)
},
tcv{
nil,
Expand All @@ -1432,7 +1480,7 @@ func TestValidateOIDCClients(t *testing.T) {
}
},
func(t *testing.T, have *schema.IdentityProvidersOpenIDConnect) {
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientRedirectURIs([]string{oauth2InstalledApp}), have.Clients[0].RedirectURIs)
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientURIs([]string{oauth2InstalledApp}), have.Clients[0].RedirectURIs)
},
tcv{
nil,
Expand All @@ -1457,7 +1505,7 @@ func TestValidateOIDCClients(t *testing.T) {
}
},
func(t *testing.T, have *schema.IdentityProvidersOpenIDConnect) {
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientRedirectURIs([]string{oauth2InstalledApp}), have.Clients[0].RedirectURIs)
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientURIs([]string{oauth2InstalledApp}), have.Clients[0].RedirectURIs)
},
tcv{
nil,
Expand All @@ -1484,7 +1532,7 @@ func TestValidateOIDCClients(t *testing.T) {
}
},
func(t *testing.T, have *schema.IdentityProvidersOpenIDConnect) {
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientRedirectURIs([]string{"http://abc@%two"}), have.Clients[0].RedirectURIs)
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientURIs([]string{"http://abc@%two"}), have.Clients[0].RedirectURIs)
},
tcv{
nil,
Expand All @@ -1511,7 +1559,7 @@ func TestValidateOIDCClients(t *testing.T) {
}
},
func(t *testing.T, have *schema.IdentityProvidersOpenIDConnect) {
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientRedirectURIs([]string{"google.com"}), have.Clients[0].RedirectURIs)
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientURIs([]string{"google.com"}), have.Clients[0].RedirectURIs)
},
tcv{
nil,
Expand Down Expand Up @@ -1539,7 +1587,7 @@ func TestValidateOIDCClients(t *testing.T) {
}
},
func(t *testing.T, have *schema.IdentityProvidersOpenIDConnect) {
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientRedirectURIs([]string{"https://google.com", "https://google.com"}), have.Clients[0].RedirectURIs)
assert.Equal(t, schema.IdentityProvidersOpenIDConnectClientURIs([]string{"https://google.com", "https://google.com"}), have.Clients[0].RedirectURIs)
},
tcv{
nil,
Expand Down
1 change: 1 addition & 0 deletions internal/oidc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func NewClient(config schema.IdentityProvidersOpenIDConnectClient, c *schema.Ide
Audience: config.Audience,
Scopes: config.Scopes,
RedirectURIs: config.RedirectURIs,
RequestURIs: config.RequestURIs,
GrantTypes: config.GrantTypes,
ResponseTypes: config.ResponseTypes,
ResponseModes: []oauthelia2.ResponseModeType{},
Expand Down

0 comments on commit ab4d14c

Please sign in to comment.