mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
feat(oidc): implement client type public (#2171)
This implements the public option for clients which allows using Authelia as an OpenID Connect Provider for cli applications and SPA's where the client secret cannot be considered secure.
This commit is contained in:
parent
0da770d900
commit
8342a46ba1
|
@ -595,7 +595,7 @@ notifier:
|
|||
## Enables additional debug messages.
|
||||
# enable_client_debug_messages: false
|
||||
|
||||
## SECURITY NOTICE: It's not recommended to change this option, and highly discouraged to have it below 8 for
|
||||
## SECURITY NOTICE: It's not recommended changing this option, and highly discouraged to have it below 8 for
|
||||
## security reasons.
|
||||
# minimum_parameter_entropy: 8
|
||||
|
||||
|
@ -611,36 +611,42 @@ notifier:
|
|||
## The client secret is a shared secret between Authelia and the consumer of this client.
|
||||
# secret: this_is_a_secret
|
||||
|
||||
## Sets the client to public. This should typically not be set, please see the documentation for usage.
|
||||
# public: false
|
||||
|
||||
## The policy to require for this client; one_factor or two_factor.
|
||||
# authorization_policy: two_factor
|
||||
|
||||
## Audience this client is allowed to request.
|
||||
# audience: []
|
||||
|
||||
## Scopes this client is allowed to request.
|
||||
# scopes:
|
||||
# - openid
|
||||
# - groups
|
||||
# - email
|
||||
# - profile
|
||||
|
||||
## Redirect URI's specifies a list of valid case-sensitive callbacks for this client.
|
||||
# redirect_uris:
|
||||
# - https://oidc.example.com:8080/oauth2/callback
|
||||
|
||||
## Scopes defines the valid scopes this client can request
|
||||
# scopes:
|
||||
# - openid
|
||||
# - groups
|
||||
# - email
|
||||
# - profile
|
||||
|
||||
## Grant Types configures which grants this client can obtain.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# grant_types:
|
||||
# - refresh_token
|
||||
# - authorization_code
|
||||
# - refresh_token
|
||||
# - authorization_code
|
||||
|
||||
## Response Types configures which responses this client can be sent.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# response_types:
|
||||
# - code
|
||||
# - code
|
||||
|
||||
## Response Modes configures which response modes this client supports.
|
||||
# response_modes:
|
||||
# - form_post
|
||||
# - query
|
||||
# - fragment
|
||||
# - form_post
|
||||
# - query
|
||||
# - fragment
|
||||
|
||||
## The algorithm used to sign userinfo endpoint responses for this client, either none or RS256.
|
||||
# userinfo_signing_algorithm: none
|
||||
|
|
|
@ -34,7 +34,7 @@ for which stage will have each feature, and may evolve over time:
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="7" class="tbl-header tbl-beta-stage">beta1</td>
|
||||
<td rowspan="8" class="tbl-header tbl-beta-stage">beta1 (4.29.0)</td>
|
||||
<td><a href="https://openid.net/specs/openid-connect-core-1_0.html#Consent" target="_blank" rel="noopener noreferrer">User Consent</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -56,9 +56,27 @@ for which stage will have each feature, and may evolve over time:
|
|||
<td class="tbl-beta-stage">Per Client List of Valid Redirection URI's</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1" class="tbl-header tbl-beta-stage">beta2 <sup>1</sup></td>
|
||||
<td class="tbl-beta-stage"><a href="https://datatracker.ietf.org/doc/html/rfc6749#section-2.1" target="_blank"rel="noopener noreferrer">Confidential Client Type</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="6" class="tbl-header tbl-beta-stage">beta2 (4.30.0) <sup>1</sup></td>
|
||||
<td class="tbl-beta-stage"><a href="https://openid.net/specs/openid-connect-core-1_0.html#UserInfo" target="_blank" rel="noopener noreferrer">Userinfo Endpoint</a> (missed in beta1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tbl-beta-stage">Parameter Entropy Configuration</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tbl-beta-stage">Token/Code Lifespan Configuration</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tbl-beta-stage">Client Debug Messages</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tbl-beta-stage">Client Audience</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tbl-beta-stage"><a href="https://datatracker.ietf.org/doc/html/rfc6749#section-2.1" target="_blank"rel="noopener noreferrer">Public Client Type</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="2" class="tbl-header tbl-beta-stage">beta3 <sup>1</sup></td>
|
||||
<td>Token Storage</td>
|
||||
|
@ -117,20 +135,22 @@ identity_providers:
|
|||
access_token_lifespan: 1h
|
||||
authorize_code_lifespan: 1m
|
||||
id_token_lifespan: 1h
|
||||
refresh_token_lifespan: 720h
|
||||
refresh_token_lifespan: 90m
|
||||
enable_client_debug_messages: false
|
||||
clients:
|
||||
- id: myapp
|
||||
description: My Application
|
||||
secret: this_is_a_secret
|
||||
public: false
|
||||
authorization_policy: two_factor
|
||||
redirect_uris:
|
||||
- https://oidc.example.com:8080/oauth2/callback
|
||||
audience: []
|
||||
scopes:
|
||||
- openid
|
||||
- groups
|
||||
- email
|
||||
- profile
|
||||
redirect_uris:
|
||||
- https://oidc.example.com:8080/oauth2/callback
|
||||
grant_types:
|
||||
- refresh_token
|
||||
- authorization_code
|
||||
|
@ -222,7 +242,7 @@ The maximum lifetime of an ID token. For more information read these docs about
|
|||
<div markdown="1">
|
||||
type: string
|
||||
{: .label .label-config .label-purple }
|
||||
default: 30d
|
||||
default: 90m
|
||||
{: .label .label-config .label-blue }
|
||||
required: no
|
||||
{: .label .label-config .label-green }
|
||||
|
@ -232,6 +252,11 @@ The maximum lifetime of a refresh token. The
|
|||
refresh token can be used to obtain new refresh tokens as well as access tokens or id tokens with an
|
||||
up-to-date expiration. For more information read these docs about [token lifespan].
|
||||
|
||||
A good starting point is 50% more or 30 minutes more (which ever is less) time than the highest lifespan out of the
|
||||
[access token lifespan](#access_token_lifespan), the [authorize code lifespan](#authorize_code_lifespan), and the
|
||||
[id token lifespan](#id_token_lifespan). For instance the default for all of these is 60 minutes, so the default refresh
|
||||
token lifespan is 90 minutes.
|
||||
|
||||
### enable_client_debug_messages
|
||||
|
||||
<div markdown="1">
|
||||
|
@ -296,14 +321,35 @@ A friendly description for this client shown in the UI. This defaults to the sam
|
|||
<div markdown="1">
|
||||
type: string
|
||||
{: .label .label-config .label-purple }
|
||||
required: yes
|
||||
{: .label .label-config .label-red }
|
||||
required: situational
|
||||
{: .label .label-config .label-yellow }
|
||||
</div>
|
||||
|
||||
The shared secret between Authelia and the application consuming this client. This secret must
|
||||
match the secret configured in the application. Currently this is stored in plain text.
|
||||
You must [generate this option yourself](#generating-a-random-secret).
|
||||
|
||||
This must be provided when the client is a confidential client type, and must be blank when using the public client
|
||||
type. To set the client type to public see the [public](#public) configuration option.
|
||||
|
||||
#### public
|
||||
|
||||
<div markdown="1">
|
||||
type: bool
|
||||
{: .label .label-config .label-purple }
|
||||
default: false
|
||||
{: .label .label-config .label-blue }
|
||||
required: no
|
||||
{: .label .label-config .label-green }
|
||||
</div>
|
||||
|
||||
This enables the public client type for this client. This is for clients that are not capable of maintaining
|
||||
confidentiality of credentials, you can read more about client types in [RFC6749](https://datatracker.ietf.org/doc/html/rfc6749#section-2.1).
|
||||
This is particularly useful for SPA's and CLI tools. This option requires setting the [client secret](#secret) to a
|
||||
blank string.
|
||||
|
||||
In addition to the standard rules for redirect URIs, public clients can use the `urn:ietf:wg:oauth:2.0:oob` redirect URI.
|
||||
|
||||
#### authorization_policy
|
||||
|
||||
<div markdown="1">
|
||||
|
@ -317,18 +363,16 @@ required: no
|
|||
|
||||
The authorization policy for this client: either `one_factor` or `two_factor`.
|
||||
|
||||
#### redirect_uris
|
||||
#### audience
|
||||
|
||||
<div markdown="1">
|
||||
type: list(string)
|
||||
{: .label .label-config .label-purple }
|
||||
required: yes
|
||||
{: .label .label-config .label-red }
|
||||
required: no
|
||||
{: .label .label-config .label-green }
|
||||
</div>
|
||||
|
||||
A list of valid callback URL´s this client will redirect to. All other callbacks will be considered
|
||||
unsafe. The URL's are case-sensitive and they differ from application to application - the community has
|
||||
provided [a list of URL´s for common applications](../../community/oidc-integrations.md).
|
||||
A list of audiences this client is allowed to request.
|
||||
|
||||
#### scopes
|
||||
|
||||
|
@ -345,6 +389,28 @@ A list of scopes to allow this client to consume. See [scope definitions](#scope
|
|||
information. The documentation for the application you want to use with Authelia will most-likely provide
|
||||
you with the scopes to allow.
|
||||
|
||||
#### redirect_uris
|
||||
|
||||
<div markdown="1">
|
||||
type: list(string)
|
||||
{: .label .label-config .label-purple }
|
||||
required: yes
|
||||
{: .label .label-config .label-red }
|
||||
</div>
|
||||
|
||||
A list of valid callback URIs this client will redirect to. All other callbacks will be considered
|
||||
unsafe. The URIs are case-sensitive and they differ from application to application - the community has
|
||||
provided [a list of URL´s for common applications](../../community/oidc-integrations.md).
|
||||
|
||||
Some restrictions that have been placed on clients and
|
||||
their redirect URIs are as follows:
|
||||
|
||||
1. If a client attempts to authorize with Authelia and its redirect URI is not listed in the client configuration the
|
||||
attempt to authorize wil fail and an error will be generated.
|
||||
2. The redirect URIs are case-sensitive.
|
||||
3. The URI must include a scheme and that scheme must be one of `http` or `https`.
|
||||
4. The client can ignore rule 3 and use `urn:ietf:wg:oauth:2.0:oob` if it is a [public](#public) client type.
|
||||
|
||||
#### grant_types
|
||||
|
||||
<div markdown="1">
|
||||
|
|
|
@ -595,7 +595,7 @@ notifier:
|
|||
## Enables additional debug messages.
|
||||
# enable_client_debug_messages: false
|
||||
|
||||
## SECURITY NOTICE: It's not recommended to change this option, and highly discouraged to have it below 8 for
|
||||
## SECURITY NOTICE: It's not recommended changing this option, and highly discouraged to have it below 8 for
|
||||
## security reasons.
|
||||
# minimum_parameter_entropy: 8
|
||||
|
||||
|
@ -611,36 +611,42 @@ notifier:
|
|||
## The client secret is a shared secret between Authelia and the consumer of this client.
|
||||
# secret: this_is_a_secret
|
||||
|
||||
## Sets the client to public. This should typically not be set, please see the documentation for usage.
|
||||
# public: false
|
||||
|
||||
## The policy to require for this client; one_factor or two_factor.
|
||||
# authorization_policy: two_factor
|
||||
|
||||
## Audience this client is allowed to request.
|
||||
# audience: []
|
||||
|
||||
## Scopes this client is allowed to request.
|
||||
# scopes:
|
||||
# - openid
|
||||
# - groups
|
||||
# - email
|
||||
# - profile
|
||||
|
||||
## Redirect URI's specifies a list of valid case-sensitive callbacks for this client.
|
||||
# redirect_uris:
|
||||
# - https://oidc.example.com:8080/oauth2/callback
|
||||
|
||||
## Scopes defines the valid scopes this client can request
|
||||
# scopes:
|
||||
# - openid
|
||||
# - groups
|
||||
# - email
|
||||
# - profile
|
||||
|
||||
## Grant Types configures which grants this client can obtain.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# grant_types:
|
||||
# - refresh_token
|
||||
# - authorization_code
|
||||
# - refresh_token
|
||||
# - authorization_code
|
||||
|
||||
## Response Types configures which responses this client can be sent.
|
||||
## It's not recommended to define this unless you know what you're doing.
|
||||
# response_types:
|
||||
# - code
|
||||
# - code
|
||||
|
||||
## Response Modes configures which response modes this client supports.
|
||||
# response_modes:
|
||||
# - form_post
|
||||
# - query
|
||||
# - fragment
|
||||
# - form_post
|
||||
# - query
|
||||
# - fragment
|
||||
|
||||
## The algorithm used to sign userinfo endpoint responses for this client, either none or RS256.
|
||||
# userinfo_signing_algorithm: none
|
||||
|
|
|
@ -25,12 +25,16 @@ type OpenIDConnectConfiguration struct {
|
|||
|
||||
// OpenIDConnectClientConfiguration configuration for an OpenID Connect client.
|
||||
type OpenIDConnectClientConfiguration struct {
|
||||
ID string `mapstructure:"id"`
|
||||
Description string `mapstructure:"description"`
|
||||
Secret string `mapstructure:"secret"`
|
||||
RedirectURIs []string `mapstructure:"redirect_uris"`
|
||||
Policy string `mapstructure:"authorization_policy"`
|
||||
ID string `mapstructure:"id"`
|
||||
Description string `mapstructure:"description"`
|
||||
Secret string `mapstructure:"secret"`
|
||||
Public bool `mapstructure:"public"`
|
||||
|
||||
Policy string `mapstructure:"authorization_policy"`
|
||||
|
||||
Audience []string `mapstructure:"audience"`
|
||||
Scopes []string `mapstructure:"scopes"`
|
||||
RedirectURIs []string `mapstructure:"redirect_uris"`
|
||||
GrantTypes []string `mapstructure:"grant_types"`
|
||||
ResponseTypes []string `mapstructure:"response_types"`
|
||||
ResponseModes []string `mapstructure:"response_modes"`
|
||||
|
|
|
@ -192,7 +192,7 @@ func TestShouldReturnCorrectResultsForValidNetworkGroups(t *testing.T) {
|
|||
}
|
||||
|
||||
validNetwork := IsNetworkGroupValid(config, "internal")
|
||||
invalidNetwork := IsNetworkGroupValid(config, "127.0.0.1")
|
||||
invalidNetwork := IsNetworkGroupValid(config, loopback)
|
||||
|
||||
assert.True(t, validNetwork)
|
||||
assert.False(t, invalidNetwork)
|
||||
|
|
|
@ -443,7 +443,7 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldHelpDetectNoInputPlacehol
|
|||
}
|
||||
|
||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldAdaptLDAPURL() {
|
||||
suite.Assert().Equal("", validateLDAPURLSimple("127.0.0.1", suite.validator))
|
||||
suite.Assert().Equal("", validateLDAPURLSimple(loopback, suite.validator))
|
||||
|
||||
suite.Assert().False(suite.validator.HasWarnings())
|
||||
suite.Require().Len(suite.validator.Errors(), 1)
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
func newDefaultConfig() schema.Configuration {
|
||||
config := schema.Configuration{}
|
||||
config.Host = "127.0.0.1"
|
||||
config.Host = loopback
|
||||
config.Port = 9090
|
||||
config.Logging.Level = "info"
|
||||
config.Logging.Format = "text"
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package validator
|
||||
|
||||
const (
|
||||
loopback = "127.0.0.1"
|
||||
oauth2InstalledApp = "urn:ietf:wg:oauth:2.0:oob"
|
||||
)
|
||||
|
||||
const (
|
||||
errFmtDeprecatedConfigurationKey = "[DEPRECATED] The %s configuration option is deprecated and will be " +
|
||||
"removed in %s, please use %s instead"
|
||||
|
@ -14,11 +19,16 @@ const (
|
|||
|
||||
errFmtOIDCServerClientRedirectURI = "OIDC client with ID '%s' redirect URI %s has an invalid scheme '%s', " +
|
||||
"should be http or https"
|
||||
errFmtOIDCClientRedirectURIPublic = "openid connect provider: client with ID '%s' redirect URI '%s' is " +
|
||||
"only valid for the public client type, not the confidential client type"
|
||||
errFmtOIDCClientRedirectURIAbsolute = "openid connect provider: client with ID '%s' redirect URI '%s' is invalid " +
|
||||
"because it has no scheme when it should be http or https"
|
||||
errFmtOIDCServerClientRedirectURICantBeParsed = "OIDC client with ID '%s' has an invalid redirect URI '%s' " +
|
||||
"could not be parsed: %v"
|
||||
errFmtOIDCServerClientInvalidPolicy = "OIDC client with ID '%s' has an invalid policy '%s', " +
|
||||
"should be either 'one_factor' or 'two_factor'"
|
||||
errFmtOIDCServerClientInvalidSecret = "OIDC client with ID '%s' has an empty secret" //nolint:gosec
|
||||
errFmtOIDCServerClientInvalidSecret = "OIDC client with ID '%s' has an empty secret" //nolint:gosec
|
||||
errFmtOIDCClientPublicInvalidSecret = "openid connect provider: client with ID '%s' is public but does not have an empty secret" //nolint:gosec
|
||||
errFmtOIDCServerClientInvalidScope = "OIDC client with ID '%s' has an invalid scope '%s', " +
|
||||
"must be one of: '%s'"
|
||||
errFmtOIDCServerClientInvalidGrantType = "OIDC client with ID '%s' has an invalid grant type '%s', " +
|
||||
|
|
|
@ -68,8 +68,14 @@ func validateOIDCClients(configuration *schema.OpenIDConnectConfiguration, valid
|
|||
ids = append(ids, client.ID)
|
||||
}
|
||||
|
||||
if client.Secret == "" {
|
||||
validator.Push(fmt.Errorf(errFmtOIDCServerClientInvalidSecret, client.ID))
|
||||
if client.Public {
|
||||
if client.Secret != "" {
|
||||
validator.Push(fmt.Errorf(errFmtOIDCClientPublicInvalidSecret, client.ID))
|
||||
}
|
||||
} else {
|
||||
if client.Secret == "" {
|
||||
validator.Push(fmt.Errorf(errFmtOIDCServerClientInvalidSecret, client.ID))
|
||||
}
|
||||
}
|
||||
|
||||
if client.Policy == "" {
|
||||
|
@ -163,15 +169,29 @@ func validateOIDDClientUserinfoAlgorithm(c int, configuration *schema.OpenIDConn
|
|||
|
||||
func validateOIDCClientRedirectURIs(client schema.OpenIDConnectClientConfiguration, validator *schema.StructValidator) {
|
||||
for _, redirectURI := range client.RedirectURIs {
|
||||
parsedURI, err := url.Parse(redirectURI)
|
||||
if redirectURI == oauth2InstalledApp {
|
||||
if client.Public {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
validator.Push(fmt.Errorf(errFmtOIDCServerClientRedirectURICantBeParsed, client.ID, redirectURI, err))
|
||||
break
|
||||
validator.Push(fmt.Errorf(errFmtOIDCClientRedirectURIPublic, client.ID, redirectURI))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if parsedURI.Scheme != schemeHTTPS && parsedURI.Scheme != schemeHTTP {
|
||||
validator.Push(fmt.Errorf(errFmtOIDCServerClientRedirectURI, client.ID, redirectURI, parsedURI.Scheme))
|
||||
parsedURL, err := url.Parse(redirectURI)
|
||||
if err != nil {
|
||||
validator.Push(fmt.Errorf(errFmtOIDCServerClientRedirectURICantBeParsed, client.ID, redirectURI, err))
|
||||
continue
|
||||
}
|
||||
|
||||
if !parsedURL.IsAbs() {
|
||||
validator.Push(fmt.Errorf(errFmtOIDCClientRedirectURIAbsolute, client.ID, redirectURI))
|
||||
return
|
||||
}
|
||||
|
||||
if parsedURL.Scheme != schemeHTTPS && parsedURL.Scheme != schemeHTTP {
|
||||
validator.Push(fmt.Errorf(errFmtOIDCServerClientRedirectURI, client.ID, redirectURI, parsedURL.Scheme))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,13 +84,21 @@ func TestShouldRaiseErrorWhenOIDCServerClientBadValues(t *testing.T) {
|
|||
"http://abc@%two",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "client-check-uri-abs",
|
||||
Secret: "a-secret",
|
||||
Policy: twoFactorPolicy,
|
||||
RedirectURIs: []string{
|
||||
"google.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ValidateIdentityProviders(config, validator)
|
||||
|
||||
require.Len(t, validator.Errors(), 7)
|
||||
require.Len(t, validator.Errors(), 8)
|
||||
|
||||
assert.Equal(t, schema.DefaultOpenIDConnectClientConfiguration.Policy, config.OIDC.Clients[0].Policy)
|
||||
assert.EqualError(t, validator.Errors()[0], fmt.Sprintf(errFmtOIDCServerClientInvalidSecret, ""))
|
||||
|
@ -98,8 +106,9 @@ func TestShouldRaiseErrorWhenOIDCServerClientBadValues(t *testing.T) {
|
|||
assert.EqualError(t, validator.Errors()[2], fmt.Sprintf(errFmtOIDCServerClientInvalidPolicy, "a-client", "a-policy"))
|
||||
assert.EqualError(t, validator.Errors()[3], fmt.Sprintf(errFmtOIDCServerClientInvalidPolicy, "a-client", "a-policy"))
|
||||
assert.EqualError(t, validator.Errors()[4], fmt.Sprintf(errFmtOIDCServerClientRedirectURICantBeParsed, "client-check-uri-parse", "http://abc@%two", errors.New("parse \"http://abc@%two\": invalid URL escape \"%tw\"")))
|
||||
assert.EqualError(t, validator.Errors()[5], "OIDC Server has one or more clients with an empty ID")
|
||||
assert.EqualError(t, validator.Errors()[6], "OIDC Server has clients with duplicate ID's")
|
||||
assert.EqualError(t, validator.Errors()[5], fmt.Sprintf(errFmtOIDCClientRedirectURIAbsolute, "client-check-uri-abs", "google.com"))
|
||||
assert.EqualError(t, validator.Errors()[6], "OIDC Server has one or more clients with an empty ID")
|
||||
assert.EqualError(t, validator.Errors()[7], "OIDC Server has clients with duplicate ID's")
|
||||
}
|
||||
|
||||
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadScopes(t *testing.T) {
|
||||
|
@ -239,6 +248,85 @@ func TestValidateIdentityProvidersShouldRaiseWarningOnSecurityIssue(t *testing.T
|
|||
assert.EqualError(t, validator.Warnings()[0], "SECURITY ISSUE: OIDC minimum parameter entropy is configured to an unsafe value, it should be above 8 but it's configured to 1.")
|
||||
}
|
||||
|
||||
func TestValidateIdentityProvidersShouldRaiseErrorsOnInvalidClientTypes(t *testing.T) {
|
||||
validator := schema.NewStructValidator()
|
||||
config := &schema.IdentityProvidersConfiguration{
|
||||
OIDC: &schema.OpenIDConnectConfiguration{
|
||||
HMACSecret: "hmac1",
|
||||
IssuerPrivateKey: "key2",
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "client-with-invalid-secret",
|
||||
Secret: "a-secret",
|
||||
Public: true,
|
||||
Policy: "two_factor",
|
||||
RedirectURIs: []string{
|
||||
"https://localhost",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "client-with-bad-redirect-uri",
|
||||
Secret: "a-secret",
|
||||
Public: false,
|
||||
Policy: "two_factor",
|
||||
RedirectURIs: []string{
|
||||
oauth2InstalledApp,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ValidateIdentityProviders(config, validator)
|
||||
|
||||
require.Len(t, validator.Errors(), 2)
|
||||
assert.Len(t, validator.Warnings(), 0)
|
||||
|
||||
assert.EqualError(t, validator.Errors()[0], fmt.Sprintf(errFmtOIDCClientPublicInvalidSecret, "client-with-invalid-secret"))
|
||||
assert.EqualError(t, validator.Errors()[1], fmt.Sprintf(errFmtOIDCClientRedirectURIPublic, "client-with-bad-redirect-uri", oauth2InstalledApp))
|
||||
}
|
||||
|
||||
func TestValidateIdentityProvidersShouldNotRaiseErrorsOnValidPublicClients(t *testing.T) {
|
||||
validator := schema.NewStructValidator()
|
||||
config := &schema.IdentityProvidersConfiguration{
|
||||
OIDC: &schema.OpenIDConnectConfiguration{
|
||||
HMACSecret: "hmac1",
|
||||
IssuerPrivateKey: "key2",
|
||||
Clients: []schema.OpenIDConnectClientConfiguration{
|
||||
{
|
||||
ID: "installed-app-client",
|
||||
Public: true,
|
||||
Policy: "two_factor",
|
||||
RedirectURIs: []string{
|
||||
oauth2InstalledApp,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "client-with-https-scheme",
|
||||
Public: true,
|
||||
Policy: "two_factor",
|
||||
RedirectURIs: []string{
|
||||
"https://localhost:9000",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "client-with-loopback",
|
||||
Public: true,
|
||||
Policy: "two_factor",
|
||||
RedirectURIs: []string{
|
||||
"http://127.0.0.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ValidateIdentityProviders(config, validator)
|
||||
|
||||
assert.Len(t, validator.Errors(), 0)
|
||||
assert.Len(t, validator.Warnings(), 0)
|
||||
}
|
||||
|
||||
func TestValidateIdentityProvidersShouldSetDefaultValues(t *testing.T) {
|
||||
validator := schema.NewStructValidator()
|
||||
config := &schema.IdentityProvidersConfiguration{
|
||||
|
|
|
@ -12,20 +12,21 @@ import (
|
|||
// NewClient creates a new InternalClient.
|
||||
func NewClient(config schema.OpenIDConnectClientConfiguration) (client *InternalClient) {
|
||||
client = &InternalClient{
|
||||
ID: config.ID,
|
||||
Description: config.Description,
|
||||
Policy: authorization.PolicyToLevel(config.Policy),
|
||||
Secret: []byte(config.Secret),
|
||||
ID: config.ID,
|
||||
Description: config.Description,
|
||||
Secret: []byte(config.Secret),
|
||||
Public: config.Public,
|
||||
|
||||
Policy: authorization.PolicyToLevel(config.Policy),
|
||||
|
||||
Audience: config.Audience,
|
||||
Scopes: config.Scopes,
|
||||
RedirectURIs: config.RedirectURIs,
|
||||
GrantTypes: config.GrantTypes,
|
||||
ResponseTypes: config.ResponseTypes,
|
||||
Scopes: config.Scopes,
|
||||
ResponseModes: []fosite.ResponseModeType{fosite.ResponseModeDefault},
|
||||
|
||||
UserinfoSigningAlgorithm: config.UserinfoSigningAlgorithm,
|
||||
|
||||
ResponseModes: []fosite.ResponseModeType{
|
||||
fosite.ResponseModeDefault,
|
||||
},
|
||||
}
|
||||
|
||||
for _, mode := range config.ResponseModes {
|
||||
|
|
|
@ -33,21 +33,21 @@ type OpenIDConnectStore struct {
|
|||
|
||||
// InternalClient represents the client internally.
|
||||
type InternalClient struct {
|
||||
ID string `json:"id"`
|
||||
Description string `json:"-"`
|
||||
Secret []byte `json:"client_secret,omitempty"`
|
||||
RedirectURIs []string `json:"redirect_uris"`
|
||||
GrantTypes []string `json:"grant_types"`
|
||||
ResponseTypes []string `json:"response_types"`
|
||||
Scopes []string `json:"scopes"`
|
||||
Audience []string `json:"audience"`
|
||||
Public bool `json:"public"`
|
||||
ID string `json:"id"`
|
||||
Description string `json:"-"`
|
||||
Secret []byte `json:"client_secret,omitempty"`
|
||||
Public bool `json:"public"`
|
||||
|
||||
Policy authorization.Level `json:"-"`
|
||||
|
||||
Audience []string `json:"audience"`
|
||||
Scopes []string `json:"scopes"`
|
||||
RedirectURIs []string `json:"redirect_uris"`
|
||||
GrantTypes []string `json:"grant_types"`
|
||||
ResponseTypes []string `json:"response_types"`
|
||||
ResponseModes []fosite.ResponseModeType `json:"response_modes"`
|
||||
|
||||
UserinfoSigningAlgorithm string `json:"userinfo_signed_response_alg,omitempty"`
|
||||
|
||||
Policy authorization.Level `json:"-"`
|
||||
}
|
||||
|
||||
// KeyManager keeps track of all of the active/inactive rsa keys and provides them to services requiring them.
|
||||
|
|
Loading…
Reference in New Issue
Block a user