2021-05-04 22:06:05 +00:00
package validator
import (
"errors"
"fmt"
"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"
"github.com/authelia/authelia/internal/configuration/schema"
)
func TestShouldRaiseErrorWhenInvalidOIDCServerConfiguration ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "abc" ,
IssuerPrivateKey : "" ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 2 )
assert . EqualError ( t , validator . Errors ( ) [ 0 ] , "OIDC Server issuer private key must be provided" )
assert . EqualError ( t , validator . Errors ( ) [ 1 ] , "OIDC Server has no clients defined" )
}
func TestShouldRaiseErrorWhenOIDCServerIssuerPrivateKeyPathInvalid ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
IssuerPrivateKey : "key-material" ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
assert . EqualError ( t , validator . Errors ( ) [ 0 ] , "OIDC Server has no clients defined" )
}
func TestShouldRaiseErrorWhenOIDCServerClientBadValues ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
IssuerPrivateKey : "key-material" ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "" ,
Secret : "" ,
Policy : "" ,
RedirectURIs : [ ] string {
"tcp://google.com" ,
} ,
} ,
{
ID : "a-client" ,
Secret : "a-secret" ,
Policy : "a-policy" ,
RedirectURIs : [ ] string {
"https://google.com" ,
} ,
} ,
{
ID : "a-client" ,
Secret : "a-secret" ,
Policy : "a-policy" ,
RedirectURIs : [ ] string {
"https://google.com" ,
} ,
} ,
{
ID : "client-check-uri-parse" ,
Secret : "a-secret" ,
Policy : twoFactorPolicy ,
RedirectURIs : [ ] string {
"http://abc@%two" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 7 )
assert . Equal ( t , schema . DefaultOpenIDConnectClientConfiguration . Policy , config . OIDC . Clients [ 0 ] . Policy )
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
assert . EqualError ( t , validator . Errors ( ) [ 0 ] , fmt . Sprintf ( errFmtOIDCServerClientInvalidSecret , "" ) )
assert . EqualError ( t , validator . Errors ( ) [ 1 ] , fmt . Sprintf ( errFmtOIDCServerClientRedirectURI , "" , "tcp://google.com" , "tcp" ) )
assert . EqualError ( t , validator . Errors ( ) [ 2 ] , fmt . Sprintf ( errFmtOIDCServerClientInvalidPolicy , "a-client" , "a-policy" ) )
assert . EqualError ( t , validator . Errors ( ) [ 3 ] , fmt . Sprintf ( errFmtOIDCServerClientInvalidPolicy , "a-client" , "a-policy" ) )
assert . EqualError ( t , validator . Errors ( ) [ 4 ] , fmt . Sprintf ( errFmtOIDCServerClientRedirectURICantBeParsed , "client-check-uri-parse" , "http://abc@%two" , errors . New ( "parse \"http://abc@%two\": invalid URL escape \"%tw\"" ) ) )
2021-05-04 22:06:05 +00:00
assert . EqualError ( t , validator . Errors ( ) [ 5 ] , "OIDC Server has one or more clients with an empty ID" )
assert . EqualError ( t , validator . Errors ( ) [ 6 ] , "OIDC Server has clients with duplicate ID's" )
}
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" ,
IssuerPrivateKey : "key-material" ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
Secret : "good_secret" ,
Policy : "two_factor" ,
Scopes : [ ] string { "openid" , "bad_scope" } ,
RedirectURIs : [ ] string {
"https://google.com/callback" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
assert . EqualError ( t , validator . Errors ( ) [ 0 ] , "OIDC Client with ID 'good_id' has an invalid scope " +
"'bad_scope', must be one of: 'openid', 'email', 'profile', 'groups', 'offline_access'" )
}
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadGrantTypes ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
IssuerPrivateKey : "key-material" ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
Secret : "good_secret" ,
Policy : "two_factor" ,
GrantTypes : [ ] string { "bad_grant_type" } ,
RedirectURIs : [ ] string {
"https://google.com/callback" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
assert . EqualError ( t , validator . Errors ( ) [ 0 ] , "OIDC Client with ID 'good_id' has an invalid grant type " +
"'bad_grant_type', must be one of: 'implicit', 'refresh_token', 'authorization_code', " +
"'password', 'client_credentials'" )
}
func TestShouldRaiseErrorWhenOIDCClientConfiguredWithBadResponseModes ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
IssuerPrivateKey : "key-material" ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
Secret : "good_secret" ,
Policy : "two_factor" ,
ResponseModes : [ ] string { "bad_responsemode" } ,
RedirectURIs : [ ] string {
"https://google.com/callback" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
require . Len ( t , validator . Errors ( ) , 1 )
assert . EqualError ( t , validator . Errors ( ) [ 0 ] , "OIDC Client with ID 'good_id' has an invalid response mode " +
"'bad_responsemode', must be one of: 'form_post', 'query', 'fragment'" )
}
func TestValidateIdentityProvidersShouldRaiseWarningOnSecurityIssue ( t * testing . T ) {
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "abc" ,
IssuerPrivateKey : "abc" ,
MinimumParameterEntropy : 1 ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "good_id" ,
Secret : "good_secret" ,
Policy : "two_factor" ,
RedirectURIs : [ ] string {
"https://google.com/callback" ,
} ,
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
assert . Len ( t , validator . Errors ( ) , 0 )
require . Len ( t , validator . Warnings ( ) , 1 )
assert . EqualError ( t , validator . Warnings ( ) [ 0 ] , "SECURITY ISSUE: OIDC minimum parameter entropy is configured to an unsafe value, it should be above 8 but it's configured to 1." )
}
func TestValidateIdentityProvidersShouldSetDefaultValues ( t * testing . T ) {
2021-05-04 22:06:05 +00:00
validator := schema . NewStructValidator ( )
config := & schema . IdentityProvidersConfiguration {
OIDC : & schema . OpenIDConnectConfiguration {
HMACSecret : "rLABDrx87et5KvRHVUgTm3pezWWd8LMN" ,
IssuerPrivateKey : "../../../README.md" ,
Clients : [ ] schema . OpenIDConnectClientConfiguration {
{
ID : "a-client" ,
Secret : "a-client-secret" ,
RedirectURIs : [ ] string {
"https://google.com" ,
} ,
} ,
{
ID : "b-client" ,
Description : "Normal Description" ,
Secret : "b-client-secret" ,
Policy : oneFactorPolicy ,
RedirectURIs : [ ] string {
"https://google.com" ,
} ,
Scopes : [ ] string {
"groups" ,
} ,
GrantTypes : [ ] string {
"refresh_token" ,
} ,
ResponseTypes : [ ] string {
"token" ,
"code" ,
} ,
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
ResponseModes : [ ] string {
"form_post" ,
"fragment" ,
} ,
2021-05-04 22:06:05 +00:00
} ,
} ,
} ,
}
ValidateIdentityProviders ( config , validator )
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
assert . Len ( t , validator . Warnings ( ) , 0 )
2021-05-04 22:06:05 +00:00
assert . Len ( t , validator . Errors ( ) , 0 )
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
// Assert Clients[0] Policy is set to the default, and the default doesn't override Clients[1]'s Policy.
assert . Equal ( t , config . OIDC . Clients [ 0 ] . Policy , twoFactorPolicy )
assert . Equal ( t , config . OIDC . Clients [ 1 ] . Policy , oneFactorPolicy )
// Assert Clients[0] Description is set to the Clients[0] ID, and Clients[1]'s Description is not overridden.
2021-05-04 22:06:05 +00:00
assert . Equal ( t , config . OIDC . Clients [ 0 ] . ID , config . OIDC . Clients [ 0 ] . Description )
assert . Equal ( t , "Normal Description" , config . OIDC . Clients [ 1 ] . Description )
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
// Assert Clients[0] ends up configured with the default Scopes.
2021-05-04 22:06:05 +00:00
require . Len ( t , config . OIDC . Clients [ 0 ] . Scopes , 4 )
assert . Equal ( t , "openid" , config . OIDC . Clients [ 0 ] . Scopes [ 0 ] )
assert . Equal ( t , "groups" , config . OIDC . Clients [ 0 ] . Scopes [ 1 ] )
assert . Equal ( t , "profile" , config . OIDC . Clients [ 0 ] . Scopes [ 2 ] )
assert . Equal ( t , "email" , config . OIDC . Clients [ 0 ] . Scopes [ 3 ] )
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
// Assert Clients[1] ends up configured with the configured Scopes and the openid Scope.
2021-05-04 22:06:05 +00:00
require . Len ( t , config . OIDC . Clients [ 1 ] . Scopes , 2 )
assert . Equal ( t , "groups" , config . OIDC . Clients [ 1 ] . Scopes [ 0 ] )
assert . Equal ( t , "openid" , config . OIDC . Clients [ 1 ] . Scopes [ 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
// Assert Clients[0] ends up configured with the default GrantTypes.
require . Len ( t , config . OIDC . Clients [ 0 ] . GrantTypes , 2 )
assert . Equal ( t , "refresh_token" , config . OIDC . Clients [ 0 ] . GrantTypes [ 0 ] )
assert . Equal ( t , "authorization_code" , config . OIDC . Clients [ 0 ] . GrantTypes [ 1 ] )
// Assert Clients[1] ends up configured with only the configured GrantTypes.
2021-05-04 22:06:05 +00:00
require . Len ( t , config . OIDC . Clients [ 1 ] . GrantTypes , 1 )
assert . Equal ( t , "refresh_token" , config . OIDC . Clients [ 1 ] . GrantTypes [ 0 ] )
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
// Assert Clients[0] ends up configured with the default ResponseTypes.
require . Len ( t , config . OIDC . Clients [ 0 ] . ResponseTypes , 1 )
assert . Equal ( t , "code" , config . OIDC . Clients [ 0 ] . ResponseTypes [ 0 ] )
// Assert Clients[1] ends up configured only with the configured ResponseTypes.
2021-05-04 22:06:05 +00:00
require . Len ( t , config . OIDC . Clients [ 1 ] . ResponseTypes , 2 )
assert . Equal ( t , "token" , config . OIDC . Clients [ 1 ] . ResponseTypes [ 0 ] )
assert . Equal ( t , "code" , config . OIDC . Clients [ 1 ] . ResponseTypes [ 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
// Assert Clients[0] ends up configured with the default ResponseModes.
require . Len ( t , config . OIDC . Clients [ 0 ] . ResponseModes , 3 )
assert . Equal ( t , "form_post" , config . OIDC . Clients [ 0 ] . ResponseModes [ 0 ] )
assert . Equal ( t , "query" , config . OIDC . Clients [ 0 ] . ResponseModes [ 1 ] )
assert . Equal ( t , "fragment" , config . OIDC . Clients [ 0 ] . ResponseModes [ 2 ] )
// Assert Clients[1] ends up configured only with the configured ResponseModes.
require . Len ( t , config . OIDC . Clients [ 1 ] . ResponseModes , 2 )
assert . Equal ( t , "form_post" , config . OIDC . Clients [ 1 ] . ResponseModes [ 0 ] )
assert . Equal ( t , "fragment" , config . OIDC . Clients [ 1 ] . ResponseModes [ 1 ] )
assert . Equal ( t , false , config . OIDC . EnableClientDebugMessages )
assert . Equal ( t , time . Hour , config . OIDC . AccessTokenLifespan )
assert . Equal ( t , time . Minute , config . OIDC . AuthorizeCodeLifespan )
assert . Equal ( t , time . Hour , config . OIDC . IDTokenLifespan )
assert . Equal ( t , time . Minute * 90 , config . OIDC . RefreshTokenLifespan )
2021-05-04 22:06:05 +00:00
}