2153 lines
72 KiB
Go
2153 lines
72 KiB
Go
package validator
|
|
|
|
import (
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
"github.com/authelia/authelia/v4/internal/oidc"
|
|
"github.com/authelia/authelia/v4/internal/utils"
|
|
)
|
|
|
|
func TestShouldRaiseErrorWhenInvalidOIDCServerConfiguration(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "abc",
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
require.Len(t, validator.Errors(), 2)
|
|
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: option 'issuer_private_key' is required")
|
|
assert.EqualError(t, validator.Errors()[1], "identity_providers: oidc: option 'clients' must have one or more clients configured")
|
|
}
|
|
|
|
func TestShouldNotRaiseErrorWhenCORSEndpointsValid(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
CORS: schema.OpenIDConnectCORSConfiguration{
|
|
Endpoints: []string{oidc.EndpointAuthorization, oidc.EndpointToken, oidc.EndpointIntrospection, oidc.EndpointRevocation, oidc.EndpointUserinfo},
|
|
},
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "example",
|
|
Secret: MustDecodeSecret("$plaintext$example"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
assert.Len(t, validator.Errors(), 0)
|
|
}
|
|
|
|
func TestShouldRaiseErrorWhenCORSEndpointsNotValid(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
CORS: schema.OpenIDConnectCORSConfiguration{
|
|
Endpoints: []string{oidc.EndpointAuthorization, oidc.EndpointToken, oidc.EndpointIntrospection, oidc.EndpointRevocation, oidc.EndpointUserinfo, "invalid_endpoint"},
|
|
},
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "example",
|
|
Secret: MustDecodeSecret("$plaintext$example"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
require.Len(t, validator.Errors(), 1)
|
|
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: cors: option 'endpoints' contains an invalid value 'invalid_endpoint': must be one of 'authorization', 'pushed-authorization-request', 'token', 'introspection', 'revocation', or 'userinfo'")
|
|
}
|
|
|
|
func TestShouldRaiseErrorWhenOIDCPKCEEnforceValueInvalid(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
EnforcePKCE: testInvalid,
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
require.Len(t, validator.Errors(), 2)
|
|
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: option 'enforce_pkce' must be 'never', 'public_clients_only' or 'always', but it's configured as 'invalid'")
|
|
assert.EqualError(t, validator.Errors()[1], "identity_providers: oidc: option 'clients' must have one or more clients configured")
|
|
}
|
|
|
|
func TestShouldRaiseErrorWhenOIDCCORSOriginsHasInvalidValues(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
CORS: schema.OpenIDConnectCORSConfiguration{
|
|
AllowedOrigins: utils.URLsFromStringSlice([]string{"https://example.com/", "https://site.example.com/subpath", "https://site.example.com?example=true", "*"}),
|
|
AllowedOriginsFromClientRedirectURIs: true,
|
|
},
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "myclient",
|
|
Secret: MustDecodeSecret("$plaintext$jk12nb3klqwmnelqkwenm"),
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{"https://example.com/oauth2_callback", "https://localhost:566/callback", "http://an.example.com/callback", "file://a/file"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
require.Len(t, validator.Errors(), 5)
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: cors: option 'allowed_origins' contains an invalid value 'https://example.com/' as it has a path: origins must only be scheme, hostname, and an optional port")
|
|
assert.EqualError(t, validator.Errors()[1], "identity_providers: oidc: cors: option 'allowed_origins' contains an invalid value 'https://site.example.com/subpath' as it has a path: origins must only be scheme, hostname, and an optional port")
|
|
assert.EqualError(t, validator.Errors()[2], "identity_providers: oidc: cors: option 'allowed_origins' contains an invalid value 'https://site.example.com?example=true' as it has a query string: origins must only be scheme, hostname, and an optional port")
|
|
assert.EqualError(t, validator.Errors()[3], "identity_providers: oidc: cors: option 'allowed_origins' contains the wildcard origin '*' with more than one origin but the wildcard origin must be defined by itself")
|
|
assert.EqualError(t, validator.Errors()[4], "identity_providers: oidc: cors: option 'allowed_origins' contains the wildcard origin '*' cannot be specified with option 'allowed_origins_from_client_redirect_uris' enabled")
|
|
|
|
require.Len(t, config.OIDC.CORS.AllowedOrigins, 6)
|
|
assert.Equal(t, "*", config.OIDC.CORS.AllowedOrigins[3].String())
|
|
assert.Equal(t, "https://example.com", config.OIDC.CORS.AllowedOrigins[4].String())
|
|
}
|
|
|
|
func TestShouldRaiseErrorWhenOIDCServerNoClients(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
require.Len(t, validator.Errors(), 1)
|
|
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: option 'clients' must have one or more clients configured")
|
|
}
|
|
|
|
func TestShouldRaiseErrorWhenOIDCServerClientBadValues(t *testing.T) {
|
|
mustParseURL := func(u string) url.URL {
|
|
out, err := url.Parse(u)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return *out
|
|
}
|
|
|
|
testCases := []struct {
|
|
Name string
|
|
Clients []schema.OpenIDConnectClientConfiguration
|
|
Errors []string
|
|
}{
|
|
{
|
|
Name: "EmptyIDAndSecret",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "",
|
|
Secret: nil,
|
|
Policy: "",
|
|
RedirectURIs: []string{},
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: client '': option 'secret' is required",
|
|
"identity_providers: oidc: clients: option 'id' is required but was absent on the clients in positions #1",
|
|
},
|
|
},
|
|
{
|
|
Name: "InvalidPolicy",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-1",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: "a-policy",
|
|
RedirectURIs: []string{
|
|
"https://google.com",
|
|
},
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: client 'client-1': option 'policy' must be one of 'one_factor' or 'two_factor' but it's configured as 'a-policy'",
|
|
},
|
|
},
|
|
{
|
|
Name: "ClientIDDuplicated",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-x",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{},
|
|
},
|
|
{
|
|
ID: "client-x",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{},
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: clients: option 'id' must be unique for every client but one or more clients share the following 'id' values 'client-x'",
|
|
},
|
|
},
|
|
{
|
|
Name: "RedirectURIInvalid",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-check-uri-parse",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{
|
|
"http://abc@%two",
|
|
},
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: client 'client-check-uri-parse': option 'redirect_uris' has an invalid value: redirect uri 'http://abc@%two' could not be parsed: parse \"http://abc@%two\": invalid URL escape \"%tw\"",
|
|
},
|
|
},
|
|
{
|
|
Name: "RedirectURINotAbsolute",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-check-uri-abs",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{
|
|
"google.com",
|
|
},
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: 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: "ValidSectorIdentifier",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-valid-sector",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{
|
|
"https://google.com",
|
|
},
|
|
SectorIdentifier: mustParseURL(exampleDotCom),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "ValidSectorIdentifierWithPort",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-valid-sector",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{
|
|
"https://google.com",
|
|
},
|
|
SectorIdentifier: mustParseURL("example.com:2000"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "InvalidSectorIdentifierInvalidURL",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-invalid-sector",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{
|
|
"https://google.com",
|
|
},
|
|
SectorIdentifier: mustParseURL("https://user:pass@example.com/path?query=abc#fragment"),
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: client 'client-invalid-sector': option 'sector_identifier' with value 'https://user:pass@example.com/path?query=abc#fragment': must be a URL with only the host component for example 'example.com' but it has a scheme with the value 'https'",
|
|
"identity_providers: oidc: client 'client-invalid-sector': option 'sector_identifier' with value 'https://user:pass@example.com/path?query=abc#fragment': must be a URL with only the host component for example 'example.com' but it has a path with the value '/path'",
|
|
"identity_providers: oidc: client 'client-invalid-sector': option 'sector_identifier' with value 'https://user:pass@example.com/path?query=abc#fragment': must be a URL with only the host component for example 'example.com' but it has a query with the value 'query=abc'",
|
|
"identity_providers: oidc: client 'client-invalid-sector': option 'sector_identifier' with value 'https://user:pass@example.com/path?query=abc#fragment': must be a URL with only the host component for example 'example.com' but it has a fragment with the value 'fragment'",
|
|
"identity_providers: oidc: client 'client-invalid-sector': option 'sector_identifier' with value 'https://user:pass@example.com/path?query=abc#fragment': must be a URL with only the host component for example 'example.com' but it has a username with the value 'user'",
|
|
"identity_providers: oidc: client 'client-invalid-sector': option 'sector_identifier' with value 'https://user:pass@example.com/path?query=abc#fragment': must be a URL with only the host component for example 'example.com' but it has a password",
|
|
},
|
|
},
|
|
{
|
|
Name: "InvalidSectorIdentifierInvalidHost",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-invalid-sector",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{
|
|
"https://google.com",
|
|
},
|
|
SectorIdentifier: mustParseURL("example.com/path?query=abc#fragment"),
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: client 'client-invalid-sector': option 'sector_identifier' with value 'example.com/path?query=abc#fragment': must be a URL with only the host component but appears to be invalid",
|
|
},
|
|
},
|
|
{
|
|
Name: "InvalidConsentMode",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-bad-consent-mode",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{
|
|
"https://google.com",
|
|
},
|
|
ConsentMode: "cap",
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: client 'client-bad-consent-mode': consent: option 'mode' must be one of 'auto', 'implicit', 'explicit', 'pre-configured', or 'auto' but it's configured as 'cap'",
|
|
},
|
|
},
|
|
{
|
|
Name: "InvalidPKCEChallengeMethod",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-bad-pkce-mode",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{
|
|
"https://google.com",
|
|
},
|
|
PKCEChallengeMethod: "abc",
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: client 'client-bad-pkce-mode': option 'pkce_challenge_method' must be one of 'plain' or 'S256' but it's configured as 'abc'",
|
|
},
|
|
},
|
|
{
|
|
Name: "InvalidPKCEChallengeMethodLowerCaseS256",
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-bad-pkce-mode-s256",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: policyTwoFactor,
|
|
RedirectURIs: []string{
|
|
"https://google.com",
|
|
},
|
|
PKCEChallengeMethod: "s256",
|
|
},
|
|
},
|
|
Errors: []string{
|
|
"identity_providers: oidc: client 'client-bad-pkce-mode-s256': option 'pkce_challenge_method' must be one of 'plain' or 'S256' but it's configured as 's256'",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
Clients: tc.Clients,
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
errs := validator.Errors()
|
|
|
|
require.Len(t, errs, len(tc.Errors))
|
|
for i, errStr := range tc.Errors {
|
|
t.Run(fmt.Sprintf("Error%d", i+1), func(t *testing.T) {
|
|
assert.EqualError(t, errs[i], errStr)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadScopes(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "good_id",
|
|
Secret: MustDecodeSecret("$plaintext$good_secret"),
|
|
Policy: "two_factor",
|
|
Scopes: []string{"openid", "bad_scope"},
|
|
RedirectURIs: []string{
|
|
"https://google.com/callback",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
require.Len(t, validator.Errors(), 1)
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: client 'good_id': option 'scopes' must only have the values 'openid', 'email', 'profile', 'groups', or 'offline_access' but the values 'bad_scope' are present")
|
|
}
|
|
|
|
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadGrantTypes(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "good_id",
|
|
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
|
|
Policy: "two_factor",
|
|
GrantTypes: []string{"bad_grant_type"},
|
|
RedirectURIs: []string{
|
|
"https://google.com/callback",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
require.Len(t, validator.Errors(), 1)
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: client 'good_id': option 'grant_types' must only have the values 'implicit', 'refresh_token', or 'authorization_code' but the values 'bad_grant_type' are present")
|
|
}
|
|
|
|
func TestShouldNotErrorOnCertificateValid(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerCertificateChain: MustParseX509CertificateChain(testCert1),
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "good_id",
|
|
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{
|
|
"https://google.com/callback",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
assert.Len(t, validator.Warnings(), 0)
|
|
assert.Len(t, validator.Errors(), 0)
|
|
}
|
|
|
|
func TestShouldRaiseErrorOnCertificateNotValid(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerCertificateChain: MustParseX509CertificateChain(testCert1),
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey2),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "good_id",
|
|
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{
|
|
"https://google.com/callback",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
assert.Len(t, validator.Warnings(), 0)
|
|
require.Len(t, validator.Errors(), 1)
|
|
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: option 'issuer_private_key' does not appear to be the private key the certificate provided by option 'issuer_certificate_chain'")
|
|
}
|
|
|
|
func TestShouldRaiseErrorOnKeySizeTooSmall(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey3),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "good_id",
|
|
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{
|
|
"https://google.com/callback",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
assert.Len(t, validator.Warnings(), 0)
|
|
require.Len(t, validator.Errors(), 1)
|
|
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: option 'issuer_private_key' must be an RSA private key with 2048 bits or more but it only has 1024 bits")
|
|
}
|
|
|
|
func TestShouldRaiseErrorOnKeyInvalidPublicKey(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey3),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "good_id",
|
|
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{
|
|
"https://google.com/callback",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
config.OIDC.IssuerPrivateKey.PublicKey.N = nil
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
assert.Len(t, validator.Warnings(), 0)
|
|
require.Len(t, validator.Errors(), 1)
|
|
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: option 'issuer_private_key' must be a valid RSA private key but the provided data is missing the public key bits")
|
|
}
|
|
|
|
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadResponseModes(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "good_id",
|
|
Secret: MustDecodeSecret("$plaintext$good_secret"),
|
|
Policy: "two_factor",
|
|
ResponseModes: []string{"bad_responsemode"},
|
|
RedirectURIs: []string{
|
|
"https://google.com/callback",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
require.Len(t, validator.Errors(), 1)
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: client 'good_id': option 'response_modes' must only have the values 'form_post', 'query', or 'fragment' but the values 'bad_responsemode' are present")
|
|
}
|
|
|
|
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadUserinfoAlg(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "rLABDrx87et5KvRHVUgTm3pezWWd8LMN",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "good_id",
|
|
Secret: MustDecodeSecret("$plaintext$good_secret"),
|
|
Policy: "two_factor",
|
|
UserinfoSigningAlgorithm: "rs256",
|
|
RedirectURIs: []string{
|
|
"https://google.com/callback",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
require.Len(t, validator.Errors(), 1)
|
|
assert.EqualError(t, validator.Errors()[0], "identity_providers: oidc: client 'good_id': option 'userinfo_signing_algorithm' must be one of 'none' or 'RS256' but it's configured as 'rs256'")
|
|
}
|
|
|
|
func TestValidateIdentityProvidersShouldRaiseWarningOnSecurityIssue(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "abc",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
MinimumParameterEntropy: 1,
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "good_id",
|
|
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{
|
|
"https://google.com/callback",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
assert.Len(t, validator.Errors(), 0)
|
|
require.Len(t, validator.Warnings(), 1)
|
|
|
|
assert.EqualError(t, validator.Warnings()[0], "openid connect provider: SECURITY ISSUE - 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: MustParseRSAPrivateKey(testKey1),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-with-invalid-secret",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Public: true,
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{
|
|
"https://localhost",
|
|
},
|
|
},
|
|
{
|
|
ID: "client-with-bad-redirect-uri",
|
|
Secret: MustDecodeSecret(goodOpenIDConnectClientSecret),
|
|
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], "identity_providers: oidc: client 'client-with-invalid-secret': option 'secret' is required to be empty when option 'public' is true")
|
|
assert.EqualError(t, validator.Errors()[1], "identity_providers: oidc: client 'client-with-bad-redirect-uri': option 'redirect_uris' has the redirect uri 'urn:ietf:wg:oauth:2.0:oob' when option 'public' is false but this is invalid as this uri is not valid for the openid connect confidential client type")
|
|
}
|
|
|
|
func TestValidateIdentityProvidersShouldNotRaiseErrorsOnValidClientOptions(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "hmac1",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
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",
|
|
},
|
|
},
|
|
{
|
|
ID: "client-with-pkce-mode-plain",
|
|
Public: true,
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{
|
|
"https://pkce.com",
|
|
},
|
|
PKCEChallengeMethod: "plain",
|
|
},
|
|
{
|
|
ID: "client-with-pkce-mode-S256",
|
|
Public: true,
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{
|
|
"https://pkce.com",
|
|
},
|
|
PKCEChallengeMethod: "S256",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
assert.Len(t, validator.Errors(), 0)
|
|
assert.Len(t, validator.Warnings(), 0)
|
|
}
|
|
|
|
func TestValidateIdentityProvidersShouldRaiseWarningOnPlainTextClients(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
config := &schema.IdentityProvidersConfiguration{
|
|
OIDC: &schema.OpenIDConnectConfiguration{
|
|
HMACSecret: "hmac1",
|
|
IssuerPrivateKey: MustParseRSAPrivateKey(testKey1),
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "client-with-invalid-secret_standard",
|
|
Secret: MustDecodeSecret("$plaintext$a-secret"),
|
|
Policy: "two_factor",
|
|
RedirectURIs: []string{
|
|
"https://localhost",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ValidateIdentityProviders(config, validator)
|
|
|
|
assert.Len(t, validator.Errors(), 0)
|
|
require.Len(t, validator.Warnings(), 1)
|
|
|
|
assert.EqualError(t, validator.Warnings()[0], "identity_providers: oidc: client 'client-with-invalid-secret_standard': option 'secret' is plaintext but for clients not using the 'token_endpoint_auth_method' of 'client_secret_jwt' it should be a hashed value as plaintext values are deprecated with the exception of 'client_secret_jwt' and will be removed when oidc becomes stable")
|
|
}
|
|
|
|
// All valid schemes are supported as defined in https://datatracker.ietf.org/doc/html/rfc8252#section-7.1
|
|
func TestValidateOIDCClientRedirectURIsSupportingPrivateUseURISchemes(t *testing.T) {
|
|
have := &schema.OpenIDConnectConfiguration{
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "owncloud",
|
|
RedirectURIs: []string{
|
|
"https://www.mywebsite.com",
|
|
"http://www.mywebsite.com",
|
|
"oc://ios.owncloud.com",
|
|
// example given in the RFC https://datatracker.ietf.org/doc/html/rfc8252#section-7.1
|
|
"com.example.app:/oauth2redirect/example-provider",
|
|
oauth2InstalledApp,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
t.Run("public", func(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
have.Clients[0].Public = true
|
|
validateOIDCClientRedirectURIs(0, have, validator, nil)
|
|
|
|
assert.Len(t, validator.Warnings(), 0)
|
|
assert.Len(t, validator.Errors(), 0)
|
|
})
|
|
|
|
t.Run("not public", func(t *testing.T) {
|
|
validator := schema.NewStructValidator()
|
|
have.Clients[0].Public = false
|
|
validateOIDCClientRedirectURIs(0, have, validator, nil)
|
|
|
|
assert.Len(t, validator.Warnings(), 0)
|
|
assert.Len(t, validator.Errors(), 1)
|
|
assert.ElementsMatch(t, validator.Errors(), []error{
|
|
errors.New("identity_providers: oidc: client 'owncloud': option 'redirect_uris' has the redirect uri 'urn:ietf:wg:oauth:2.0:oob' when option 'public' is false but this is invalid as this uri is not valid for the openid connect confidential client type"),
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestValidateOIDCClients(t *testing.T) {
|
|
type tcv struct {
|
|
Scopes []string
|
|
ResponseTypes []string
|
|
ResponseModes []string
|
|
GrantTypes []string
|
|
}
|
|
|
|
testCasses := []struct {
|
|
name string
|
|
setup func(have *schema.OpenIDConnectConfiguration)
|
|
validate func(t *testing.T, have *schema.OpenIDConnectConfiguration)
|
|
have tcv
|
|
expected tcv
|
|
serrs []string // Soft errors which will be warnings before GA.
|
|
errs []string
|
|
}{
|
|
{
|
|
"ShouldSetDefaultResponseTypeAndResponseModes",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldIncludeMinimalScope",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
[]string{oidc.ScopeEmail},
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultResponseModesFlowAuthorizeCode",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultResponseModesFlowImplicit",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeImplicitFlowBoth},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeImplicitFlowBoth},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeFragment},
|
|
[]string{oidc.GrantTypeImplicit},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultResponseModesFlowHybrid",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeHybridFlowBoth},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeHybridFlowBoth},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeFragment},
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeImplicit},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultResponseModesFlowMixedAuthorizeCodeHybrid",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeHybridFlowBoth},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeHybridFlowBoth},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery, oidc.ResponseModeFragment},
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeImplicit},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultResponseModesFlowMixedAuthorizeCodeImplicit",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeImplicitFlowBoth},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeImplicitFlowBoth},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery, oidc.ResponseModeFragment},
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeImplicit},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultResponseModesFlowMixedAll",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeImplicitFlowBoth, oidc.ResponseTypeHybridFlowBoth},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeImplicitFlowBoth, oidc.ResponseTypeHybridFlowBoth},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery, oidc.ResponseModeFragment},
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeImplicit},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldNotOverrideValues",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeImplicitFlowBoth, oidc.ResponseTypeHybridFlowBoth},
|
|
[]string{oidc.ResponseModeFormPost},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeImplicitFlowBoth, oidc.ResponseTypeHybridFlowBoth},
|
|
[]string{oidc.ResponseModeFormPost},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnDuplicateScopes",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeOpenID},
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeOpenID},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'scopes' must have unique values but the values 'openid' are duplicated",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidScopes",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeProfile, "group"},
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeProfile, "group"},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'scopes' must only have the values 'openid', 'email', 'profile', 'groups', or 'offline_access' but the values 'group' are present",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnMissingAuthorizationCodeFlowResponseTypeWithRefreshTokenValues",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeOfflineAccess},
|
|
[]string{oidc.ResponseTypeImplicitFlowBoth},
|
|
nil,
|
|
[]string{oidc.GrantTypeImplicit, oidc.GrantTypeRefreshToken},
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeOfflineAccess},
|
|
[]string{oidc.ResponseTypeImplicitFlowBoth},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeFragment},
|
|
[]string{oidc.GrantTypeImplicit, oidc.GrantTypeRefreshToken},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'scopes' should only have the values 'offline_access' or 'offline' if the client is also configured with a 'response_type' such as 'code', 'code id_token', 'code token', or 'code id_token token' which respond with authorization codes",
|
|
"identity_providers: oidc: client 'test': option 'grant_types' should only have the values 'refresh_token' if the client is also configured with a 'response_type' such as 'code', 'code id_token', 'code token', or 'code id_token token' which respond with authorization codes",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnDuplicateResponseTypes",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeImplicitFlowBoth, oidc.ResponseTypeAuthorizationCodeFlow},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow, oidc.ResponseTypeImplicitFlowBoth, oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery, oidc.ResponseModeFragment},
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeImplicit},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'response_types' must have unique values but the values 'code' are duplicated",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidResponseTypesOrder",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeImplicitFlowBoth, "token id_token"},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeImplicitFlowBoth, "token id_token"},
|
|
[]string{"form_post", "fragment"},
|
|
[]string{"implicit"},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'response_types' must only have the values 'code', 'id_token', 'token', 'id_token token', 'code id_token', 'code token', or 'code id_token token' but the values 'token id_token' are present",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidResponseTypes",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{"not_valid"},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{"not_valid"},
|
|
[]string{oidc.ResponseModeFormPost},
|
|
nil,
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'response_types' must only have the values 'code', 'id_token', 'token', 'id_token token', 'code id_token', 'code token', or 'code id_token token' but the values 'not_valid' are present",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidResponseModes",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
[]string{"not_valid"},
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{"not_valid"},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'response_modes' must only have the values 'form_post', 'query', or 'fragment' but the values 'not_valid' are present",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnDuplicateResponseModes",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
[]string{oidc.ResponseModeQuery, oidc.ResponseModeQuery},
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeQuery, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'response_modes' must have unique values but the values 'query' are duplicated",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidGrantTypes",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
[]string{"invalid"},
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{"invalid"},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'grant_types' must only have the values 'implicit', 'refresh_token', or 'authorization_code' but the values 'invalid' are present",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnDuplicateGrantTypes",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'grant_types' must have unique values but the values 'authorization_code' are duplicated",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnGrantTypeRefreshTokenWithoutScopeOfflineAccess",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeRefreshToken},
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeRefreshToken},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'grant_types' should only have the 'refresh_token' value if the client is also configured with the 'offline_access' scope",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnGrantTypeAuthorizationCodeWithoutAuthorizationCodeOrHybridFlow",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeImplicitFlowBoth},
|
|
nil,
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeImplicitFlowBoth},
|
|
[]string{"form_post", "fragment"},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'grant_types' should only have grant type values which are valid with the configured 'response_types' for the client but 'authorization_code' expects a response type for either the authorization code or hybrid flow such as 'code', 'code id_token', 'code token', or 'code id_token token' but the response types are 'id_token token'",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnGrantTypeImplicitWithoutImplicitOrHybridFlow",
|
|
nil,
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
nil,
|
|
[]string{oidc.GrantTypeImplicit},
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeImplicit},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'grant_types' should only have grant type values which are valid with the configured 'response_types' for the client but 'implicit' expects a response type for either the implicit or hybrid flow such as 'id_token', 'token', 'id_token token', 'code id_token', 'code token', or 'code id_token token' but the response types are 'code'",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldValidateCorrectRedirectURIsConfidentialClientType",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].RedirectURIs = []string{
|
|
"https://google.com",
|
|
}
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, []string{"https://google.com"}, have.Clients[0].RedirectURIs)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldValidateCorrectRedirectURIsPublicClientType",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].Public = true
|
|
have.Clients[0].Secret = nil
|
|
have.Clients[0].RedirectURIs = []string{
|
|
oauth2InstalledApp,
|
|
}
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, []string{oauth2InstalledApp}, have.Clients[0].RedirectURIs)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidRedirectURIsPublicOnly",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].RedirectURIs = []string{
|
|
"urn:ietf:wg:oauth:2.0:oob",
|
|
}
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, []string{oauth2InstalledApp}, have.Clients[0].RedirectURIs)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'redirect_uris' has the redirect uri 'urn:ietf:wg:oauth:2.0:oob' when option 'public' is false but this is invalid as this uri is not valid for the openid connect confidential client type",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidRedirectURIsMalformedURI",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].RedirectURIs = []string{
|
|
"http://abc@%two",
|
|
}
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, []string{"http://abc@%two"}, have.Clients[0].RedirectURIs)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'redirect_uris' has an invalid value: redirect uri 'http://abc@%two' could not be parsed: parse \"http://abc@%two\": invalid URL escape \"%tw\"",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidRedirectURIsNotAbsolute",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].RedirectURIs = []string{
|
|
"google.com",
|
|
}
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, []string{"google.com"}, have.Clients[0].RedirectURIs)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'redirect_uris' has an invalid value: redirect uri 'google.com' must have a scheme but it's absent",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnDuplicateRedirectURI",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].RedirectURIs = []string{
|
|
"https://google.com",
|
|
"https://google.com",
|
|
}
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, []string{"https://google.com", "https://google.com"}, have.Clients[0].RedirectURIs)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'redirect_uris' must have unique values but the values 'https://google.com' are duplicated",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldNotSetDefaultTokenEndpointClientAuthMethodConfidentialClientType",
|
|
nil,
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "", have.Clients[0].TokenEndpointAuthMethod)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldNotOverrideValidClientAuthMethod",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = oidc.ClientAuthMethodClientSecretPost
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, oidc.ClientAuthMethodClientSecretPost, have.Clients[0].TokenEndpointAuthMethod)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidClientAuthMethod",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = "client_credentials"
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "client_credentials", have.Clients[0].TokenEndpointAuthMethod)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'token_endpoint_auth_method' must be one of 'none', 'client_secret_post', 'client_secret_basic', or 'client_secret_jwt' but it's configured as 'client_credentials'",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidClientAuthMethodForPublicClientType",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = oidc.ClientAuthMethodClientSecretBasic
|
|
have.Clients[0].Public = true
|
|
have.Clients[0].Secret = nil
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, oidc.ClientAuthMethodClientSecretBasic, have.Clients[0].TokenEndpointAuthMethod)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'token_endpoint_auth_method' must be 'none' when configured as the public client type but it's configured as 'client_secret_basic'",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidClientAuthMethodForConfidentialClientTypeAuthorizationCodeFlow",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = oidc.ClientAuthMethodNone
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, oidc.ClientAuthMethodNone, have.Clients[0].TokenEndpointAuthMethod)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'token_endpoint_auth_method' must be one of 'client_secret_post' or 'client_secret_basic' when configured as the confidential client type unless it only includes implicit flow response types such as 'id_token', 'token', and 'id_token token' but it's configured as 'none'",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidClientAuthMethodForConfidentialClientTypeHybridFlow",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = oidc.ClientAuthMethodNone
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, oidc.ClientAuthMethodNone, have.Clients[0].TokenEndpointAuthMethod)
|
|
},
|
|
tcv{
|
|
nil,
|
|
[]string{oidc.ResponseTypeHybridFlowToken},
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeHybridFlowToken},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeFragment},
|
|
[]string{oidc.GrantTypeAuthorizationCode, oidc.GrantTypeImplicit},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'token_endpoint_auth_method' must be one of 'client_secret_post' or 'client_secret_basic' when configured as the confidential client type unless it only includes implicit flow response types such as 'id_token', 'token', and 'id_token token' but it's configured as 'none'",
|
|
},
|
|
},
|
|
{
|
|
"ShouldSetDefaultUserInfoAlg",
|
|
nil,
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, oidc.SigningAlgNone, have.Clients[0].UserinfoSigningAlgorithm)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldNotOverrideUserInfoAlg",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].UserinfoSigningAlgorithm = oidc.SigningAlgRSAUsingSHA256
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, oidc.SigningAlgRSAUsingSHA256, have.Clients[0].UserinfoSigningAlgorithm)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidUserInfoAlg",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].UserinfoSigningAlgorithm = "rs256"
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "rs256", have.Clients[0].UserinfoSigningAlgorithm)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'userinfo_signing_algorithm' must be one of 'none' or 'RS256' but it's configured as 'rs256'",
|
|
},
|
|
},
|
|
{
|
|
"ShouldSetDefaultConsentMode",
|
|
nil,
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "explicit", have.Clients[0].ConsentMode)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultConsentModeAuto",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].ConsentMode = auto
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "explicit", have.Clients[0].ConsentMode)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultConsentModePreConfigured",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
d := time.Minute
|
|
|
|
have.Clients[0].ConsentMode = ""
|
|
have.Clients[0].ConsentPreConfiguredDuration = &d
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "pre-configured", have.Clients[0].ConsentMode)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultConsentModeAutoPreConfigured",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
d := time.Minute
|
|
|
|
have.Clients[0].ConsentMode = auto
|
|
have.Clients[0].ConsentPreConfiguredDuration = &d
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "pre-configured", have.Clients[0].ConsentMode)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldNotOverrideConsentMode",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].ConsentMode = "implicit"
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "implicit", have.Clients[0].ConsentMode)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSentConsentPreConfiguredDefaultDuration",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].ConsentMode = "pre-configured"
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "pre-configured", have.Clients[0].ConsentMode)
|
|
assert.Equal(t, schema.DefaultOpenIDConnectClientConfiguration.ConsentPreConfiguredDuration, have.Clients[0].ConsentPreConfiguredDuration)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnIncorrectlyConfiguredTokenEndpointClientAuthMethodClientSecretJWT",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = oidc.ClientAuthMethodClientSecretJWT
|
|
have.Clients[0].Secret = MustDecodeSecret("$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng")
|
|
},
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'secret' must be plaintext with option 'token_endpoint_auth_method' with a value of 'client_secret_jwt'",
|
|
},
|
|
},
|
|
{
|
|
"ShouldNotRaiseWarningOrErrorOnCorrectlyConfiguredTokenEndpointClientAuthMethodClientSecretJWT",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = oidc.ClientAuthMethodClientSecretJWT
|
|
have.Clients[0].Secret = MustDecodeSecret("$plaintext$abc123")
|
|
},
|
|
nil,
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldSetDefaultTokenEndpointAuthSigAlg",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = oidc.ClientAuthMethodClientSecretJWT
|
|
have.Clients[0].Secret = MustDecodeSecret("$plaintext$abc123")
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, oidc.SigningAlgHMACUsingSHA256, have.Clients[0].TokenEndpointAuthSigningAlg)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidPublicTokenAuthAlg",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = oidc.ClientAuthMethodClientSecretJWT
|
|
have.Clients[0].TokenEndpointAuthSigningAlg = oidc.SigningAlgHMACUsingSHA256
|
|
have.Clients[0].Secret = nil
|
|
have.Clients[0].Public = true
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, oidc.SigningAlgHMACUsingSHA256, have.Clients[0].TokenEndpointAuthSigningAlg)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'token_endpoint_auth_method' must be 'none' when configured as the public client type but it's configured as 'client_secret_jwt'",
|
|
},
|
|
},
|
|
{
|
|
"ShouldRaiseErrorOnInvalidTokenAuthAlgClientTypeConfidential",
|
|
func(have *schema.OpenIDConnectConfiguration) {
|
|
have.Clients[0].TokenEndpointAuthMethod = oidc.ClientAuthMethodClientSecretJWT
|
|
have.Clients[0].TokenEndpointAuthSigningAlg = "abc"
|
|
have.Clients[0].Secret = MustDecodeSecret("$plaintext$abc123")
|
|
},
|
|
func(t *testing.T, have *schema.OpenIDConnectConfiguration) {
|
|
assert.Equal(t, "abc", have.Clients[0].TokenEndpointAuthSigningAlg)
|
|
},
|
|
tcv{
|
|
nil,
|
|
nil,
|
|
nil,
|
|
nil,
|
|
},
|
|
tcv{
|
|
[]string{oidc.ScopeOpenID, oidc.ScopeGroups, oidc.ScopeProfile, oidc.ScopeEmail},
|
|
[]string{oidc.ResponseTypeAuthorizationCodeFlow},
|
|
[]string{oidc.ResponseModeFormPost, oidc.ResponseModeQuery},
|
|
[]string{oidc.GrantTypeAuthorizationCode},
|
|
},
|
|
nil,
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'token_endpoint_auth_signing_alg' must be 'HS256', 'HS384', or 'HS512' when option 'token_endpoint_auth_method' is client_secret_jwt",
|
|
},
|
|
},
|
|
}
|
|
|
|
errDeprecatedFunc := func() {}
|
|
|
|
for _, tc := range testCasses {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
have := &schema.OpenIDConnectConfiguration{
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "test",
|
|
Secret: MustDecodeSecret("$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng"),
|
|
Scopes: tc.have.Scopes,
|
|
ResponseModes: tc.have.ResponseModes,
|
|
ResponseTypes: tc.have.ResponseTypes,
|
|
GrantTypes: tc.have.GrantTypes,
|
|
},
|
|
},
|
|
}
|
|
|
|
if tc.setup != nil {
|
|
tc.setup(have)
|
|
}
|
|
|
|
val := schema.NewStructValidator()
|
|
|
|
validateOIDCClient(0, have, val, errDeprecatedFunc)
|
|
|
|
t.Run("General", func(t *testing.T) {
|
|
assert.Equal(t, tc.expected.Scopes, have.Clients[0].Scopes)
|
|
assert.Equal(t, tc.expected.ResponseTypes, have.Clients[0].ResponseTypes)
|
|
assert.Equal(t, tc.expected.ResponseModes, have.Clients[0].ResponseModes)
|
|
assert.Equal(t, tc.expected.GrantTypes, have.Clients[0].GrantTypes)
|
|
|
|
if tc.validate != nil {
|
|
tc.validate(t, have)
|
|
}
|
|
})
|
|
|
|
t.Run("Warnings", func(t *testing.T) {
|
|
require.Len(t, val.Warnings(), len(tc.serrs))
|
|
for i, err := range tc.serrs {
|
|
assert.EqualError(t, val.Warnings()[i], err)
|
|
}
|
|
})
|
|
|
|
t.Run("Errors", func(t *testing.T) {
|
|
require.Len(t, val.Errors(), len(tc.errs))
|
|
for i, err := range tc.errs {
|
|
assert.EqualError(t, val.Errors()[i], err)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateOIDCClientTokenEndpointAuthMethod(t *testing.T) {
|
|
testCasses := []struct {
|
|
name string
|
|
have string
|
|
public bool
|
|
expected string
|
|
errs []string
|
|
}{
|
|
{"ShouldSetDefaultValueConfidential", "", false, "", nil},
|
|
{"ShouldErrorOnInvalidValue", "abc", false, "abc",
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'token_endpoint_auth_method' must be one of 'none', 'client_secret_post', 'client_secret_basic', or 'client_secret_jwt' but it's configured as 'abc'",
|
|
},
|
|
},
|
|
{"ShouldErrorOnInvalidValueForPublicClient", "client_secret_post", true, "client_secret_post",
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'token_endpoint_auth_method' must be 'none' when configured as the public client type but it's configured as 'client_secret_post'",
|
|
},
|
|
},
|
|
{"ShouldErrorOnInvalidValueForConfidentialClient", "none", false, "none",
|
|
[]string{
|
|
"identity_providers: oidc: client 'test': option 'token_endpoint_auth_method' must be one of 'client_secret_post' or 'client_secret_basic' when configured as the confidential client type unless it only includes implicit flow response types such as 'id_token', 'token', and 'id_token token' but it's configured as 'none'",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCasses {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
have := &schema.OpenIDConnectConfiguration{
|
|
Clients: []schema.OpenIDConnectClientConfiguration{
|
|
{
|
|
ID: "test",
|
|
Public: tc.public,
|
|
TokenEndpointAuthMethod: tc.have,
|
|
},
|
|
},
|
|
}
|
|
|
|
val := schema.NewStructValidator()
|
|
|
|
validateOIDCClientTokenEndpointAuth(0, have, val)
|
|
|
|
assert.Equal(t, tc.expected, have.Clients[0].TokenEndpointAuthMethod)
|
|
assert.Len(t, val.Warnings(), 0)
|
|
require.Len(t, val.Errors(), len(tc.errs))
|
|
|
|
if tc.errs != nil {
|
|
for i, err := range tc.errs {
|
|
assert.EqualError(t, val.Errors()[i], err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func MustDecodeSecret(value string) *schema.PasswordDigest {
|
|
if secret, err := schema.DecodePasswordDigest(value); err != nil {
|
|
panic(err)
|
|
} else {
|
|
return secret
|
|
}
|
|
}
|
|
|
|
func MustParseRSAPrivateKey(data string) *rsa.PrivateKey {
|
|
block, _ := pem.Decode([]byte(data))
|
|
if block == nil || block.Bytes == nil || len(block.Bytes) == 0 {
|
|
panic("not pem encoded")
|
|
}
|
|
|
|
if block.Type != "RSA PRIVATE KEY" {
|
|
panic("not private key")
|
|
}
|
|
|
|
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return key
|
|
}
|
|
|
|
func MustParseX509CertificateChain(data string) schema.X509CertificateChain {
|
|
chain, err := schema.NewX509CertificateChain(data)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return *chain
|
|
}
|
|
|
|
var (
|
|
testCert1 = `
|
|
-----BEGIN CERTIFICATE-----
|
|
MIIC5jCCAc6gAwIBAgIRAJZ+6KrHw95zIDgm2arCTCgwDQYJKoZIhvcNAQELBQAw
|
|
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNMjIwOTA4MDIyNDQyWhcNMjMwOTA4MDIy
|
|
NDQyWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
|
ADCCAQoCggEBAMAE7muDAJtLsV3WgOpjrZ1JD1RlhuSOa3V+4zo2NYFQSdZW18SZ
|
|
fYYgUwLOleEy3VQ3N9MEFh/rWNHYHdsBjDvz/Q1EzAlXqthGd0Sic/UDYtrahrko
|
|
jCSkZCQ5YVO9ivMRth6XdUlu7RHVYY3aSOWPx2wiw9cdN+e4p73W6KwyzT7ezbUD
|
|
0Nng0Z7CNQTLHv3LBsLUODc4aVOvp2B4aAaw6cn990buKMvUuo2ge9gh0c5gIOM5
|
|
dU7xOGAt7RzwCIHnG4CGAWPFuuS215ZeelgQr/9/fhtzDqSuBZw5f10vXnAyBwei
|
|
vN6Kffj2RXB+koFwBguT84A6cfmxWllGNF0CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
|
|
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
|
|
AQELBQADggEBAFvORjj7RGoIc3q0fv6QjuncZ0Mu1/24O0smCr6tq5d6RQBRpb1M
|
|
jEsbTMLZErrHbyw/DWC75eJhW6T+6HiVTo6brBXkmDL+QGkLgRNOkZla6cnmIpmL
|
|
bf9iPmmcThscQERgYZzNg19zqK8JAQU/6PgU/N6OXTL/mQQoB972ET9dUl7lGx1Q
|
|
2l8XBe8t4QTp4t1xd3c4azxWvFNpzWBjC5eBWiVHLJmFXr4xpcnPFYFETOkvEqwt
|
|
pMQ2x895BoLrep6b+g0xeF4pmmIQwA9KrUVr++gpYaRzytaOIYwcIPMzt9iLWKQe
|
|
6ZSOrTVi8pPugYXp+LhVk/WI7r8EWtyADu0=
|
|
-----END CERTIFICATE-----`
|
|
|
|
testKey1 = `
|
|
-----BEGIN RSA PRIVATE KEY-----
|
|
MIIEpAIBAAKCAQEAwATua4MAm0uxXdaA6mOtnUkPVGWG5I5rdX7jOjY1gVBJ1lbX
|
|
xJl9hiBTAs6V4TLdVDc30wQWH+tY0dgd2wGMO/P9DUTMCVeq2EZ3RKJz9QNi2tqG
|
|
uSiMJKRkJDlhU72K8xG2Hpd1SW7tEdVhjdpI5Y/HbCLD1x0357invdborDLNPt7N
|
|
tQPQ2eDRnsI1BMse/csGwtQ4NzhpU6+nYHhoBrDpyf33Ru4oy9S6jaB72CHRzmAg
|
|
4zl1TvE4YC3tHPAIgecbgIYBY8W65LbXll56WBCv/39+G3MOpK4FnDl/XS9ecDIH
|
|
B6K83op9+PZFcH6SgXAGC5PzgDpx+bFaWUY0XQIDAQABAoIBAQClcdpHcglMxOwe
|
|
kRpkWdwWAAQgUJXoSbnW86wu1NRHBfmInyyrrSBVN3aunXbQITZIQIdt3kB94haW
|
|
P6KBt5Svd2saSqOOjSWb0SMkVOCaQ/+h19VqpcASNj4+Y94y+8ZD5ofHVfJtghDr
|
|
Y7H5OhHDEZ3e0xlwODGaCyUkUY4KBv/oIlILoh4phbDYHkZH8AzDnEiyVE1JAWlN
|
|
voAQysgSU7eEnNCi1S07jl5bY+MD3XpJkAfQsJYhqYT/qetStZ12PuXjpbIr3y53
|
|
qjCrKeWTyDN+gOznyIGuiR6nvXeQAw/o9hZiah4RuHXTPs/3GAcRXcuMR0pbgJ+B
|
|
yfX6eLK1AoGBAPKkJKPYJD2NHukAelNbT2OgeDIgJmfOIvLa73/x2hXvWwa4VwIC
|
|
POuKXtT/a02J4pYMGlaKXfHgLmaW2HPObOIjpxqgRIswsiKS1AbaDtkWnhaS1/SJ
|
|
oZ7Fk8DdX+1QT4J/fj/2uxRT0GhXdMxDpK7ekpmRE+APPCGhmOMgmWszAoGBAMqX
|
|
Ts1RdGWgDxLi15rDqdqRBARJG7Om/xC2voXVmbAb4Q+QoNrNeiIAM2usuhrVuj5V
|
|
c16m9fxswRNYqQBYyShDi5wp5a8UjfqDpzJdku2bmrBaL+XVq8PY+oTK6KS3ss8U
|
|
CGQ8P6Phz5JGavn/nDMRZ4EwEWqbEMUqJAJlpmIvAoGAQ9Wj8LJyn0qew6FAkaFL
|
|
dpzcPZdDZW35009l+a0RvWQnXJ+Yo5UglvEeRgoKY6kS0cQccOlKDl8QWdn+NZIW
|
|
WrqA8y6vOwKoKoZGBIxd7k8mb0UqXtFDf/HYtuis8tmrAN7H2vYNo0czUphwrNKU
|
|
bdcHwSsQFWns87IL3iO1AIUCgYBzmBX8jOePPN6c9hXzVoVKEshp8ZT+0uBilwLq
|
|
tk/07lNiYDGH5woy8E5mt62QtjaIbpVfgoCEwUEBWutDKWXNtYypVDabyWyhbhEu
|
|
abn2HX0L9smxqFNTcjCvKF/J7I74HQQUvVPKnIOlgMx1TOXBNcMLMXQekc/lz/+v
|
|
5nQjPQKBgQDjdJABeiy9tU0tzLWUVc5QoQKnlfSJoFLis46REb1yHwU9OjTc05Wx
|
|
5lAXdTjDmnelDdGWNWHjWOiKSkTxhvQD3jXriI5y8Sdxe3zS3ikYvbMbi97GJz0O
|
|
5oyNJo6/froW1dLkJJWR8hg2PQbtoOo6l9HHSd91BnJJ4qFbq9ZrXQ==
|
|
-----END RSA PRIVATE KEY-----`
|
|
|
|
testKey2 = `
|
|
-----BEGIN RSA PRIVATE KEY-----
|
|
MIIEpAIBAAKCAQEA6z1LOg1ZCqb0lytXWZ+MRBpMHEXOoTOLYgfZXt1IYyE3Z758
|
|
cyalk0NYQhY5cZDsXPYWPvAHiPMUxutWkoxFwby56S+AbIMa3/Is+ILrHRJs8Exn
|
|
ZkpyrYFxPX12app2kErdmAkHSx0Z5/kuXiz96PHs8S8/ZbyZolLHzdfLtSzjvRm5
|
|
Zue5iFzsf19NJz5CIBfv8g5lRwtE8wNJoRSpn1xq7fqfuA0weDNFPzjlNWRLy6aa
|
|
rK7qJexRkmkCs4sLgyl+9NODYJpvmN8E1yhyC27E0joI6rBFVW7Ihv+cSPCdDzGp
|
|
EWe81x3AeqAa3mjVqkiq4u4Z2i8JDgBaPboqJwIDAQABAoIBAAFdLZ58jVOefDSU
|
|
L8F5R1rtvBs93GDa56f926jNJ6pLewLC+/2+757W+SAI+PRLntM7Kg3bXm/Q2QH+
|
|
Q1Y+MflZmspbWCdI61L5GIGoYKyeers59i+FpvySj5GHtLQRiTZ0+Kv1AXHSDWBm
|
|
9XneUOqU3IbZe0ifu1RRno72/VtjkGXbW8Mkkw+ohyGbIeTx/0/JQ6sSNZTT3Vk7
|
|
8i4IXptq3HSF0/vqZuah8rShoeNq72pD1YLM9YPdL5by1QkDLnqATDiCpLBTCaNV
|
|
I8sqYEun+HYbQzBj8ZACG2JVZpEEidONWQHw5BPWO95DSZYrVnEkuCqeH+u5vYt7
|
|
CHuJ3AECgYEA+W3v5z+j91w1VPHS0VB3SCDMouycAMIUnJPAbt+0LPP0scUFsBGE
|
|
hPAKddC54pmMZRQ2KIwBKiyWfCrJ8Xz8Yogn7fJgmwTHidJBr2WQpIEkNGlK3Dzi
|
|
jXL2sh0yC7sHvn0DqiQ79l/e7yRbSnv2wrTJEczOOH2haD7/tBRyCYECgYEA8W+q
|
|
E9YyGvEltnPFaOxofNZ8LHVcZSsQI5b6fc0iE7fjxFqeXPXEwGSOTwqQLQRiHn9b
|
|
CfPmIG4Vhyq0otVmlPvUnfBZ2OK+tl5X2/mQFO3ROMdvpi0KYa994uqfJdSTaqLn
|
|
jjoKFB906UFHnDQDLZUNiV1WwnkTglgLc+xrd6cCgYEAqqthyv6NyBTM3Tm2gcio
|
|
Ra9Dtntl51LlXZnvwy3IkDXBCd6BHM9vuLKyxZiziGx+Vy90O1xI872cnot8sINQ
|
|
Am+dur/tAEVN72zxyv0Y8qb2yfH96iKy9gxi5s75TnOEQgAygLnYWaWR2lorKRUX
|
|
bHTdXBOiS58S0UzCFEslGIECgYBqkO4SKWYeTDhoKvuEj2yjRYyzlu28XeCWxOo1
|
|
otiauX0YSyNBRt2cSgYiTzhKFng0m+QUJYp63/wymB/5C5Zmxi0XtWIDADpLhqLj
|
|
HmmBQ2Mo26alQ5YkffBju0mZyhVzaQop1eZi8WuKFV1FThPlB7hc3E0SM5zv2Grd
|
|
tQnOWwKBgQC40yZY0PcjuILhy+sIc0Wvh7LUA7taSdTye149kRvbvsCDN7Jh75lM
|
|
USjhLXY0Nld2zBm9r8wMb81mXH29uvD+tDqqsICvyuKlA/tyzXR+QTr7dCVKVwu0
|
|
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
|
-----END RSA PRIVATE KEY-----`
|
|
|
|
testKey3 = `-----BEGIN RSA PRIVATE KEY-----
|
|
MIICXgIBAAKBgQDBi7fdmUmlpWklpgAvNUdhDrpsDVqAHuEzVApK6f6ohYAi0/q2
|
|
+YmOwyPKDSrOc6Sy1myJtV3FbZGvYaQhnokc4bnkS9DH0lY+6Hk2vKps5PrhRY/q
|
|
1EjnfwXvzhAzb25rGFwKcSvfvndMTVvxgqXVob+3pRt9maD6HFHAh2/NCQIDAQAB
|
|
AoGACT2bfLgJ3R/FomeHkLlxe//RBMGqdX2D8QhtKWB8qR0engsS6FOHrspAVjBE
|
|
v/Cjh2pXake/f2KY1w/JX1WLZEFXja2RFPeeDiiC/4S7pKCySUVeHO9rQ4SY5Frg
|
|
/s/QWWtmq7+1iu2DXhdGJA6fIurzSoDgUXo3NGFCYqIFaAECQQDUi9AAgEljmc2q
|
|
dAUQD0KNTcJFkpTafhfPiYc2GT1vS/bArtXRmvJmbIiRfVuGbM8z5ES7JGd5FyYL
|
|
i2WCCzUBAkEA6R14GVhN8NIPWEUrzjgOvjKlc2ZHskT3dYb3djpm69TK7GjLtHyq
|
|
qO7l4VJowsXI+o/6YucagF6+rH0O0VrwCQJBAM8twYDbi63knA8MrGqtFUg7haTf
|
|
bu1Tf84y1nOrQrEcMNg9E/sOuD2SicSXlwF/SrHgTgbFQ39LSzBxnm6WkgECQQCh
|
|
AQmB98tdGLggbyXiODV2h+Rd37aFGb0QHzerIIsVNtMwlPCcp733D4kWJqTUYWZ+
|
|
KBL3XEahgs6Os5EYZ4aBAkEAjKE+2/nBYUdHVusjMXeNsE5rqwJND5zvYzmToG7+
|
|
xhv4RUAe4dHL4IDQoQRjhr3Nw+JYvtzBx0Iq/178xMnGKg==
|
|
-----END RSA PRIVATE KEY-----`
|
|
|
|
goodOpenIDConnectClientSecret = "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng" //nolint:gosec
|
|
)
|