2021-05-04 22:06:05 +00:00
package validator
import (
2022-10-02 02:07:40 +00:00
"crypto/rsa"
"crypto/x509"
"encoding/pem"
2021-05-04 22:06:05 +00:00
"errors"
"fmt"
2022-04-07 06:13:01 +00:00
"net/url"
2021-05-04 22:06:05 +00:00
"testing"
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
"time"
2021-05-04 22:06:05 +00:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2021-08-11 01:04:35 +00:00
"github.com/authelia/authelia/v4/internal/configuration/schema"
2022-04-07 00:58:51 +00:00
"github.com/authelia/authelia/v4/internal/oidc"
"github.com/authelia/authelia/v4/internal/utils"
2021-05-04 22:06:05 +00:00
)
func TestShouldRaiseErrorWhenInvalidOIDCServerConfiguration ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
2022-10-02 02:07:40 +00:00
HMACSecret : "abc" ,
2021-05-04 22:06:05 +00:00
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 2 )
2023-04-13 10:58:18 +00:00
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" )
2021-05-04 22:06:05 +00:00
}
2022-04-07 00:58:51 +00:00
func TestShouldNotRaiseErrorWhenCORSEndpointsValid ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2022-04-07 00:58:51 +00:00
CORS : schema . OpenIDConnectCORSConfiguration {
2022-10-20 02:16:36 +00:00
Endpoints : [ ] string { oidc . EndpointAuthorization , oidc . EndpointToken , oidc . EndpointIntrospection , oidc . EndpointRevocation , oidc . EndpointUserinfo } ,
2022-04-07 00:58:51 +00:00
} ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "example" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$example" ) ,
2022-04-07 00:58:51 +00:00
} ,
} ,
} ,
}
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" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2022-04-07 00:58:51 +00:00
CORS : schema . OpenIDConnectCORSConfiguration {
2022-10-20 02:16:36 +00:00
Endpoints : [ ] string { oidc . EndpointAuthorization , oidc . EndpointToken , oidc . EndpointIntrospection , oidc . EndpointRevocation , oidc . EndpointUserinfo , "invalid_endpoint" } ,
2022-04-07 00:58:51 +00:00
} ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "example" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$example" ) ,
2022-04-07 00:58:51 +00:00
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
2023-04-13 10:58:18 +00:00
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'" )
2022-04-07 00:58:51 +00:00
}
2022-03-02 04:44:05 +00:00
func TestShouldRaiseErrorWhenOIDCPKCEEnforceValueInvalid ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2022-10-17 10:51:59 +00:00
EnforcePKCE : testInvalid ,
2022-03-02 04:44:05 +00:00
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 2 )
2023-04-13 10:58:18 +00:00
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" )
2022-03-02 04:44:05 +00:00
}
2022-04-07 00:58:51 +00:00
func TestShouldRaiseErrorWhenOIDCCORSOriginsHasInvalidValues ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2022-04-07 00:58:51 +00:00
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" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$jk12nb3klqwmnelqkwenm" ) ,
2022-04-07 00:58:51 +00:00
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 )
2022-11-21 00:52:27 +00:00
require . Len ( t , validator . Errors ( ) , 5 )
2022-04-07 00:58:51 +00:00
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 ) {
2021-05-04 22:06:05 +00:00
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2021-05-04 22:06:05 +00:00
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
2023-04-13 10:58:18 +00:00
assert . EqualError ( t , validator . Errors ( ) [ 0 ] , "identity_providers: oidc: option 'clients' must have one or more clients configured" )
2021-05-04 22:06:05 +00:00
}
func TestShouldRaiseErrorWhenOIDCServerClientBadValues ( t * testing . T ) {
2022-04-07 06:13:01 +00:00
mustParseURL := func ( u string ) url . URL {
out , err := url . Parse ( u )
if err != nil {
panic ( err )
}
return * out
}
2022-01-21 11:05:53 +00:00
testCases := [ ] struct {
Name string
Clients [ ] schema . OpenIDConnectClientConfiguration
2022-04-07 06:13:01 +00:00
Errors [ ] string
2022-01-21 11:05:53 +00:00
} {
{
2022-04-07 06:13:01 +00:00
Name : "EmptyIDAndSecret" ,
2021-05-04 22:06:05 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
2022-01-21 11:05:53 +00:00
ID : "" ,
2022-10-20 03:21:45 +00:00
Secret : nil ,
2022-01-21 11:05:53 +00:00
Policy : "" ,
RedirectURIs : [ ] string { } ,
2021-05-04 22:06:05 +00:00
} ,
2022-01-21 11:05:53 +00:00
} ,
2022-04-07 06:13:01 +00:00
Errors : [ ] string {
2023-03-09 07:26:52 +00:00
"identity_providers: oidc: client '': option 'secret' is required" ,
2023-04-13 10:58:18 +00:00
"identity_providers: oidc: clients: option 'id' is required but was absent on the clients in positions #1" ,
2022-01-21 11:05:53 +00:00
} ,
} ,
{
2022-04-07 06:13:01 +00:00
Name : "InvalidPolicy" ,
2022-01-21 11:05:53 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
2021-05-04 22:06:05 +00:00
{
2022-01-21 11:05:53 +00:00
ID : "client-1" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2021-05-04 22:06:05 +00:00
Policy : "a-policy" ,
RedirectURIs : [ ] string {
"https://google.com" ,
} ,
} ,
2022-01-21 11:05:53 +00:00
} ,
2023-04-13 10:58:18 +00:00
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'" ,
} ,
2022-01-21 11:05:53 +00:00
} ,
{
2022-04-07 06:13:01 +00:00
Name : "ClientIDDuplicated" ,
2022-01-21 11:05:53 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
2021-05-04 22:06:05 +00:00
{
2022-01-21 11:05:53 +00:00
ID : "client-x" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2022-01-21 11:05:53 +00:00
Policy : policyTwoFactor ,
RedirectURIs : [ ] string { } ,
} ,
{
ID : "client-x" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2022-01-21 11:05:53 +00:00
Policy : policyTwoFactor ,
RedirectURIs : [ ] string { } ,
2021-05-04 22:06:05 +00:00
} ,
2022-01-21 11:05:53 +00:00
} ,
2023-04-13 10:58:18 +00:00
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'" ,
} ,
2022-01-21 11:05:53 +00:00
} ,
{
2022-04-07 06:13:01 +00:00
Name : "RedirectURIInvalid" ,
2022-01-21 11:05:53 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
2021-05-04 22:06:05 +00:00
{
ID : "client-check-uri-parse" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2021-08-03 09:55:21 +00:00
Policy : policyTwoFactor ,
2021-05-04 22:06:05 +00:00
RedirectURIs : [ ] string {
"http://abc@%two" ,
} ,
} ,
2022-01-21 11:05:53 +00:00
} ,
2022-04-07 06:13:01 +00:00
Errors : [ ] string {
2023-04-13 10:58:18 +00:00
"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\"" ,
2022-01-21 11:05:53 +00:00
} ,
} ,
{
2022-04-07 06:13:01 +00:00
Name : "RedirectURINotAbsolute" ,
2022-01-21 11:05:53 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
2021-07-15 11:02:03 +00:00
{
ID : "client-check-uri-abs" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2021-08-03 09:55:21 +00:00
Policy : policyTwoFactor ,
2021-07-15 11:02:03 +00:00
RedirectURIs : [ ] string {
"google.com" ,
} ,
} ,
2021-05-04 22:06:05 +00:00
} ,
2022-04-07 06:13:01 +00:00
Errors : [ ] string {
2023-04-13 10:58:18 +00:00
"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" ,
2022-04-07 06:13:01 +00:00
} ,
} ,
2022-04-08 07:38:38 +00:00
{
Name : "ValidSectorIdentifier" ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "client-valid-sector" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2022-04-08 07:38:38 +00:00
Policy : policyTwoFactor ,
RedirectURIs : [ ] string {
"https://google.com" ,
} ,
2023-01-12 10:57:44 +00:00
SectorIdentifier : mustParseURL ( exampleDotCom ) ,
2022-04-08 07:38:38 +00:00
} ,
} ,
} ,
{
Name : "ValidSectorIdentifierWithPort" ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "client-valid-sector" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2022-04-08 07:38:38 +00:00
Policy : policyTwoFactor ,
RedirectURIs : [ ] string {
"https://google.com" ,
} ,
SectorIdentifier : mustParseURL ( "example.com:2000" ) ,
} ,
} ,
} ,
2022-04-07 06:13:01 +00:00
{
Name : "InvalidSectorIdentifierInvalidURL" ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "client-invalid-sector" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2022-04-07 06:13:01 +00:00
Policy : policyTwoFactor ,
RedirectURIs : [ ] string {
"https://google.com" ,
} ,
SectorIdentifier : mustParseURL ( "https://user:pass@example.com/path?query=abc#fragment" ) ,
} ,
} ,
Errors : [ ] string {
2023-04-13 10:58:18 +00:00
"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" ,
2022-04-07 06:13:01 +00:00
} ,
} ,
{
Name : "InvalidSectorIdentifierInvalidHost" ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "client-invalid-sector" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2022-04-07 06:13:01 +00:00
Policy : policyTwoFactor ,
RedirectURIs : [ ] string {
"https://google.com" ,
} ,
SectorIdentifier : mustParseURL ( "example.com/path?query=abc#fragment" ) ,
} ,
} ,
Errors : [ ] string {
2023-04-13 10:58:18 +00:00
"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" ,
2022-01-21 11:05:53 +00:00
} ,
2021-05-04 22:06:05 +00:00
} ,
2022-11-23 23:16:23 +00:00
{
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 {
2023-04-13 10:58:18 +00:00
"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'" ,
2022-11-23 23:16:23 +00:00
} ,
} ,
2023-01-03 15:03:23 +00:00
{
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 {
2023-04-13 10:58:18 +00:00
"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'" ,
2023-01-03 15:03:23 +00:00
} ,
} ,
{
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 {
2023-04-13 10:58:18 +00:00
"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'" ,
2023-01-03 15:03:23 +00:00
} ,
} ,
2021-05-04 22:06:05 +00:00
}
2022-01-21 11:05:53 +00:00
for _ , tc := range testCases {
t . Run ( tc . Name , func ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2022-01-21 11:05:53 +00:00
Clients : tc . Clients ,
} ,
}
2021-05-04 22:06:05 +00:00
2022-01-21 11:05:53 +00:00
ValidateIdentityProviders ( config , validator )
2022-04-07 06:13:01 +00:00
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 )
} )
}
2022-01-21 11:05:53 +00:00
} )
}
2021-05-04 22:06:05 +00:00
}
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadScopes ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$good_secret" ) ,
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
Policy : "two_factor" ,
Scopes : [ ] string { "openid" , "bad_scope" } ,
RedirectURIs : [ ] string {
"https://google.com/callback" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
2023-04-13 10:58:18 +00:00
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" )
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
}
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadGrantTypes ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
2023-03-09 07:26:52 +00:00
Secret : MustDecodeSecret ( goodOpenIDConnectClientSecret ) ,
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
Policy : "two_factor" ,
GrantTypes : [ ] string { "bad_grant_type" } ,
RedirectURIs : [ ] string {
"https://google.com/callback" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
2023-04-13 10:58:18 +00:00
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" )
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
}
2022-10-02 02:07:40 +00:00
func TestShouldNotErrorOnCertificateValid ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerCertificateChain : MustParseX509CertificateChain ( testCert1 ) ,
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2022-10-02 02:07:40 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
2023-03-09 07:26:52 +00:00
Secret : MustDecodeSecret ( goodOpenIDConnectClientSecret ) ,
2022-10-02 02:07:40 +00:00
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" ,
2022-10-20 02:16:36 +00:00
IssuerCertificateChain : MustParseX509CertificateChain ( testCert1 ) ,
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey2 ) ,
2022-10-02 02:07:40 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
2023-03-09 07:26:52 +00:00
Secret : MustDecodeSecret ( goodOpenIDConnectClientSecret ) ,
2022-10-02 02:07:40 +00:00
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'" )
}
2022-10-20 02:16:36 +00:00
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" ,
2023-03-09 07:26:52 +00:00
Secret : MustDecodeSecret ( goodOpenIDConnectClientSecret ) ,
2022-10-20 02:16:36 +00:00
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" )
}
2023-04-08 06:02:34 +00:00
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" )
}
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadResponseModes ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$good_secret" ) ,
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
Policy : "two_factor" ,
ResponseModes : [ ] string { "bad_responsemode" } ,
RedirectURIs : [ ] string {
"https://google.com/callback" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
2023-04-13 10:58:18 +00:00
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" )
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
}
2021-07-10 04:56:33 +00:00
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadUserinfoAlg ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2021-07-10 04:56:33 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$good_secret" ) ,
2021-07-10 04:56:33 +00:00
Policy : "two_factor" ,
UserinfoSigningAlgorithm : "rs256" ,
RedirectURIs : [ ] string {
"https://google.com/callback" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
2023-04-13 10:58:18 +00:00
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'" )
2021-07-10 04:56:33 +00:00
}
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
func TestValidateIdentityProvidersShouldRaiseWarningOnSecurityIssue ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "abc" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
MinimumParameterEntropy : 1 ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
2023-03-09 07:26:52 +00:00
Secret : MustDecodeSecret ( goodOpenIDConnectClientSecret ) ,
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
Policy : "two_factor" ,
RedirectURIs : [ ] string {
"https://google.com/callback" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
assert . Len ( t , validator . Errors ( ) , 0 )
require . Len ( t , validator . Warnings ( ) , 1 )
2021-08-03 09:55:21 +00:00
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" )
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
}
2021-07-15 11:02:03 +00:00
func TestValidateIdentityProvidersShouldRaiseErrorsOnInvalidClientTypes ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "hmac1" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2021-07-15 11:02:03 +00:00
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "client-with-invalid-secret" ,
2022-10-20 03:21:45 +00:00
Secret : MustDecodeSecret ( "$plaintext$a-secret" ) ,
2021-07-15 11:02:03 +00:00
Public : true ,
Policy : "two_factor" ,
RedirectURIs : [ ] string {
"https://localhost" ,
} ,
} ,
{
ID : "client-with-bad-redirect-uri" ,
2023-03-09 07:26:52 +00:00
Secret : MustDecodeSecret ( goodOpenIDConnectClientSecret ) ,
2021-07-15 11:02:03 +00:00
Public : false ,
Policy : "two_factor" ,
RedirectURIs : [ ] string {
oauth2InstalledApp ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 2 )
assert . Len ( t , validator . Warnings ( ) , 0 )
2023-04-13 10:58:18 +00:00
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" )
2021-07-15 11:02:03 +00:00
}
2023-01-03 15:03:23 +00:00
func TestValidateIdentityProvidersShouldNotRaiseErrorsOnValidClientOptions ( t * testing . T ) {
2021-07-15 11:02:03 +00:00
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "hmac1" ,
2022-10-20 02:16:36 +00:00
IssuerPrivateKey : MustParseRSAPrivateKey ( testKey1 ) ,
2021-07-15 11:02:03 +00:00
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" ,
} ,
} ,
2023-01-03 15:03:23 +00:00
{
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" ,
} ,
2021-07-15 11:02:03 +00:00
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
assert . Len ( t , validator . Errors ( ) , 0 )
assert . Len ( t , validator . Warnings ( ) , 0 )
}
2023-03-09 07:26:52 +00:00
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 )
2023-05-14 23:51:59 +00:00
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" )
2023-03-09 07:26:52 +00:00
}
2022-01-21 11:05:53 +00:00
// All valid schemes are supported as defined in https://datatracker.ietf.org/doc/html/rfc8252#section-7.1
func TestValidateOIDCClientRedirectURIsSupportingPrivateUseURISchemes ( t * testing . T ) {
2023-04-13 10:58:18 +00:00
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 ,
} ,
} ,
2022-01-21 11:05:53 +00:00
} ,
}
t . Run ( "public" , func ( t * testing . T ) {
validator := schema . NewStructValidator ( )
2023-04-13 10:58:18 +00:00
have . Clients [ 0 ] . Public = true
validateOIDCClientRedirectURIs ( 0 , have , validator , nil )
2022-01-21 11:05:53 +00:00
assert . Len ( t , validator . Warnings ( ) , 0 )
assert . Len ( t , validator . Errors ( ) , 0 )
} )
t . Run ( "not public" , func ( t * testing . T ) {
validator := schema . NewStructValidator ( )
2023-04-13 10:58:18 +00:00
have . Clients [ 0 ] . Public = false
validateOIDCClientRedirectURIs ( 0 , have , validator , nil )
2022-01-21 11:05:53 +00:00
assert . Len ( t , validator . Warnings ( ) , 0 )
2022-11-21 00:52:27 +00:00
assert . Len ( t , validator . Errors ( ) , 1 )
2022-01-21 11:05:53 +00:00
assert . ElementsMatch ( t , validator . Errors ( ) , [ ] error {
2022-11-21 00:52:27 +00:00
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" ) ,
2022-01-21 11:05:53 +00:00
} )
} )
}
2022-10-02 02:07:40 +00:00
2023-04-13 10:58:18 +00:00
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 {
2023-05-14 23:51:59 +00:00
"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'" ,
2023-04-13 10:58:18 +00:00
} ,
} ,
{
"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 ) {
2023-05-14 23:51:59 +00:00
assert . Equal ( t , oidc . SigningAlgNone , have . Clients [ 0 ] . UserinfoSigningAlgorithm )
2023-04-13 10:58:18 +00:00
} ,
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 ) {
2023-05-14 23:51:59 +00:00
have . Clients [ 0 ] . UserinfoSigningAlgorithm = oidc . SigningAlgRSAUsingSHA256
2023-04-13 10:58:18 +00:00
} ,
func ( t * testing . T , have * schema . OpenIDConnectConfiguration ) {
2023-05-14 23:51:59 +00:00
assert . Equal ( t , oidc . SigningAlgRSAUsingSHA256 , have . Clients [ 0 ] . UserinfoSigningAlgorithm )
2023-04-13 10:58:18 +00:00
} ,
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 ,
} ,
2023-05-14 23:51:59 +00:00
{
"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 = "abcinvalid"
have . Clients [ 0 ] . Secret = MustDecodeSecret ( "$plaintext$abc123" )
} ,
func ( t * testing . T , have * schema . OpenIDConnectConfiguration ) {
assert . Equal ( t , "abcinvalid" , 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" ,
} ,
} ,
2023-04-13 10:58:18 +00:00
}
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 {
2023-05-14 23:51:59 +00:00
"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'" ,
2023-04-13 10:58:18 +00:00
} ,
} ,
{ "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 ( )
2023-05-14 23:51:59 +00:00
validateOIDCClientTokenEndpointAuth ( 0 , have , val )
2023-04-13 10:58:18 +00:00
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 )
}
}
} )
}
}
2022-10-20 03:21:45 +00:00
func MustDecodeSecret ( value string ) * schema . PasswordDigest {
2022-12-04 22:37:08 +00:00
if secret , err := schema . DecodePasswordDigest ( value ) ; err != nil {
2022-10-20 03:21:45 +00:00
panic ( err )
} else {
return secret
}
}
2022-10-20 02:16:36 +00:00
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
}
2022-10-02 02:07:40 +00:00
var (
testCert1 = `
-- -- - BEGIN CERTIFICATE -- -- -
MIIC5jCCAc6gAwIBAgIRAJZ + 6 KrHw95zIDgm2arCTCgwDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNMjIwOTA4MDIyNDQyWhcNMjMwOTA4MDIy
NDQyWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAMAE7muDAJtLsV3WgOpjrZ1JD1RlhuSOa3V + 4 zo2NYFQSdZW18SZ
fYYgUwLOleEy3VQ3N9MEFh / rWNHYHdsBjDvz / Q1EzAlXqthGd0Sic / UDYtrahrko
jCSkZCQ5YVO9ivMRth6XdUlu7RHVYY3aSOWPx2wiw9cdN + e4p73W6KwyzT7ezbUD
0 Nng0Z7CNQTLHv3LBsLUODc4aVOvp2B4aAaw6cn990buKMvUuo2ge9gh0c5gIOM5
dU7xOGAt7RzwCIHnG4CGAWPFuuS215ZeelgQr / 9 / fhtzDqSuBZw5f10vXnAyBwei
vN6Kffj2RXB + koFwBguT84A6cfmxWllGNF0CAwEAAaM1MDMwDgYDVR0PAQH / BAQD
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB / wQCMAAwDQYJKoZIhvcN
AQELBQADggEBAFvORjj7RGoIc3q0fv6QjuncZ0Mu1 / 24 O0smCr6tq5d6RQBRpb1M
jEsbTMLZErrHbyw / DWC75eJhW6T + 6 HiVTo6brBXkmDL + QGkLgRNOkZla6cnmIpmL
bf9iPmmcThscQERgYZzNg19zqK8JAQU / 6 PgU / N6OXTL / mQQoB972ET9dUl7lGx1Q
2 l8XBe8t4QTp4t1xd3c4azxWvFNpzWBjC5eBWiVHLJmFXr4xpcnPFYFETOkvEqwt
pMQ2x895BoLrep6b + g0xeF4pmmIQwA9KrUVr ++ gpYaRzytaOIYwcIPMzt9iLWKQe
6 ZSOrTVi8pPugYXp + LhVk / WI7r8EWtyADu0 =
-- -- - END CERTIFICATE -- -- - `
testKey1 = `
-- -- - BEGIN RSA PRIVATE KEY -- -- -
MIIEpAIBAAKCAQEAwATua4MAm0uxXdaA6mOtnUkPVGWG5I5rdX7jOjY1gVBJ1lbX
xJl9hiBTAs6V4TLdVDc30wQWH + tY0dgd2wGMO / P9DUTMCVeq2EZ3RKJz9QNi2tqG
uSiMJKRkJDlhU72K8xG2Hpd1SW7tEdVhjdpI5Y / HbCLD1x0357invdborDLNPt7N
tQPQ2eDRnsI1BMse / csGwtQ4NzhpU6 + nYHhoBrDpyf33Ru4oy9S6jaB72CHRzmAg
4 zl1TvE4YC3tHPAIgecbgIYBY8W65LbXll56WBCv / 39 + G3MOpK4FnDl / XS9ecDIH
B6K83op9 + PZFcH6SgXAGC5PzgDpx + bFaWUY0XQIDAQABAoIBAQClcdpHcglMxOwe
kRpkWdwWAAQgUJXoSbnW86wu1NRHBfmInyyrrSBVN3aunXbQITZIQIdt3kB94haW
P6KBt5Svd2saSqOOjSWb0SMkVOCaQ / + h19VqpcASNj4 + Y94y + 8 ZD5ofHVfJtghDr
Y7H5OhHDEZ3e0xlwODGaCyUkUY4KBv / oIlILoh4phbDYHkZH8AzDnEiyVE1JAWlN
voAQysgSU7eEnNCi1S07jl5bY + MD3XpJkAfQsJYhqYT / qetStZ12PuXjpbIr3y53
qjCrKeWTyDN + gOznyIGuiR6nvXeQAw / o9hZiah4RuHXTPs / 3 GAcRXcuMR0pbgJ + B
yfX6eLK1AoGBAPKkJKPYJD2NHukAelNbT2OgeDIgJmfOIvLa73 / x2hXvWwa4VwIC
POuKXtT / a02J4pYMGlaKXfHgLmaW2HPObOIjpxqgRIswsiKS1AbaDtkWnhaS1 / SJ
oZ7Fk8DdX + 1 QT4J / fj / 2 uxRT0GhXdMxDpK7ekpmRE + APPCGhmOMgmWszAoGBAMqX
Ts1RdGWgDxLi15rDqdqRBARJG7Om / xC2voXVmbAb4Q + QoNrNeiIAM2usuhrVuj5V
c16m9fxswRNYqQBYyShDi5wp5a8UjfqDpzJdku2bmrBaL + XVq8PY + oTK6KS3ss8U
CGQ8P6Phz5JGavn / nDMRZ4EwEWqbEMUqJAJlpmIvAoGAQ9Wj8LJyn0qew6FAkaFL
dpzcPZdDZW35009l + a0RvWQnXJ + Yo5UglvEeRgoKY6kS0cQccOlKDl8QWdn + NZIW
WrqA8y6vOwKoKoZGBIxd7k8mb0UqXtFDf / HYtuis8tmrAN7H2vYNo0czUphwrNKU
bdcHwSsQFWns87IL3iO1AIUCgYBzmBX8jOePPN6c9hXzVoVKEshp8ZT + 0 uBilwLq
tk / 07 lNiYDGH5woy8E5mt62QtjaIbpVfgoCEwUEBWutDKWXNtYypVDabyWyhbhEu
abn2HX0L9smxqFNTcjCvKF / J7I74HQQUvVPKnIOlgMx1TOXBNcMLMXQekc / lz / + v
5 nQjPQKBgQDjdJABeiy9tU0tzLWUVc5QoQKnlfSJoFLis46REb1yHwU9OjTc05Wx
5 lAXdTjDmnelDdGWNWHjWOiKSkTxhvQD3jXriI5y8Sdxe3zS3ikYvbMbi97GJz0O
5 oyNJo6 / froW1dLkJJWR8hg2PQbtoOo6l9HHSd91BnJJ4qFbq9ZrXQ ==
-- -- - END RSA PRIVATE KEY -- -- - `
testKey2 = `
-- -- - BEGIN RSA PRIVATE KEY -- -- -
MIIEpAIBAAKCAQEA6z1LOg1ZCqb0lytXWZ + MRBpMHEXOoTOLYgfZXt1IYyE3Z758
cyalk0NYQhY5cZDsXPYWPvAHiPMUxutWkoxFwby56S + AbIMa3 / Is + ILrHRJs8Exn
ZkpyrYFxPX12app2kErdmAkHSx0Z5 / kuXiz96PHs8S8 / ZbyZolLHzdfLtSzjvRm5
Zue5iFzsf19NJz5CIBfv8g5lRwtE8wNJoRSpn1xq7fqfuA0weDNFPzjlNWRLy6aa
rK7qJexRkmkCs4sLgyl + 9 NODYJpvmN8E1yhyC27E0joI6rBFVW7Ihv + cSPCdDzGp
EWe81x3AeqAa3mjVqkiq4u4Z2i8JDgBaPboqJwIDAQABAoIBAAFdLZ58jVOefDSU
L8F5R1rtvBs93GDa56f926jNJ6pLewLC + / 2 + 757 W + SAI + PRLntM7Kg3bXm / Q2QH +
Q1Y + MflZmspbWCdI61L5GIGoYKyeers59i + FpvySj5GHtLQRiTZ0 + Kv1AXHSDWBm
9 XneUOqU3IbZe0ifu1RRno72 / VtjkGXbW8Mkkw + ohyGbIeTx / 0 / JQ6sSNZTT3Vk7
8i 4 IXptq3HSF0 / vqZuah8rShoeNq72pD1YLM9YPdL5by1QkDLnqATDiCpLBTCaNV
I8sqYEun + HYbQzBj8ZACG2JVZpEEidONWQHw5BPWO95DSZYrVnEkuCqeH + u5vYt7
CHuJ3AECgYEA + W3v5z + j91w1VPHS0VB3SCDMouycAMIUnJPAbt + 0 LPP0scUFsBGE
hPAKddC54pmMZRQ2KIwBKiyWfCrJ8Xz8Yogn7fJgmwTHidJBr2WQpIEkNGlK3Dzi
jXL2sh0yC7sHvn0DqiQ79l / e7yRbSnv2wrTJEczOOH2haD7 / tBRyCYECgYEA8W + q
E9YyGvEltnPFaOxofNZ8LHVcZSsQI5b6fc0iE7fjxFqeXPXEwGSOTwqQLQRiHn9b
CfPmIG4Vhyq0otVmlPvUnfBZ2OK + tl5X2 / mQFO3ROMdvpi0KYa994uqfJdSTaqLn
jjoKFB906UFHnDQDLZUNiV1WwnkTglgLc + xrd6cCgYEAqqthyv6NyBTM3Tm2gcio
Ra9Dtntl51LlXZnvwy3IkDXBCd6BHM9vuLKyxZiziGx + Vy90O1xI872cnot8sINQ
Am + dur / tAEVN72zxyv0Y8qb2yfH96iKy9gxi5s75TnOEQgAygLnYWaWR2lorKRUX
bHTdXBOiS58S0UzCFEslGIECgYBqkO4SKWYeTDhoKvuEj2yjRYyzlu28XeCWxOo1
otiauX0YSyNBRt2cSgYiTzhKFng0m + QUJYp63 / wymB / 5 C5Zmxi0XtWIDADpLhqLj
HmmBQ2Mo26alQ5YkffBju0mZyhVzaQop1eZi8WuKFV1FThPlB7hc3E0SM5zv2Grd
tQnOWwKBgQC40yZY0PcjuILhy + sIc0Wvh7LUA7taSdTye149kRvbvsCDN7Jh75lM
USjhLXY0Nld2zBm9r8wMb81mXH29uvD + tDqqsICvyuKlA / tyzXR + QTr7dCVKVwu0
1 YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw ==
-- -- - END RSA PRIVATE KEY -- -- - `
2022-10-20 02:16:36 +00:00
testKey3 = ` -- -- - BEGIN RSA PRIVATE KEY -- -- -
MIICXgIBAAKBgQDBi7fdmUmlpWklpgAvNUdhDrpsDVqAHuEzVApK6f6ohYAi0 / q2
+ YmOwyPKDSrOc6Sy1myJtV3FbZGvYaQhnokc4bnkS9DH0lY + 6 Hk2vKps5PrhRY / q
1 EjnfwXvzhAzb25rGFwKcSvfvndMTVvxgqXVob + 3 pRt9maD6HFHAh2 / NCQIDAQAB
AoGACT2bfLgJ3R / FomeHkLlxe //RBMGqdX2D8QhtKWB8qR0engsS6FOHrspAVjBE
v / Cjh2pXake / f2KY1w / JX1WLZEFXja2RFPeeDiiC / 4 S7pKCySUVeHO9rQ4SY5Frg
/ s / QWWtmq7 + 1i u2DXhdGJA6fIurzSoDgUXo3NGFCYqIFaAECQQDUi9AAgEljmc2q
dAUQD0KNTcJFkpTafhfPiYc2GT1vS / bArtXRmvJmbIiRfVuGbM8z5ES7JGd5FyYL
i2WCCzUBAkEA6R14GVhN8NIPWEUrzjgOvjKlc2ZHskT3dYb3djpm69TK7GjLtHyq
qO7l4VJowsXI + o / 6 YucagF6 + rH0O0VrwCQJBAM8twYDbi63knA8MrGqtFUg7haTf
bu1Tf84y1nOrQrEcMNg9E / sOuD2SicSXlwF / SrHgTgbFQ39LSzBxnm6WkgECQQCh
AQmB98tdGLggbyXiODV2h + Rd37aFGb0QHzerIIsVNtMwlPCcp733D4kWJqTUYWZ +
KBL3XEahgs6Os5EYZ4aBAkEAjKE + 2 / nBYUdHVusjMXeNsE5rqwJND5zvYzmToG7 +
xhv4RUAe4dHL4IDQoQRjhr3Nw + JYvtzBx0Iq / 178 xMnGKg ==
-- -- - END RSA PRIVATE KEY -- -- - `
2023-03-09 07:26:52 +00:00
goodOpenIDConnectClientSecret = "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng" //nolint:gosec
2022-10-20 02:16:36 +00:00
)