2021-05-05 05:06:05 +07:00
|
|
|
package oidc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"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-04 06:44:30 +07:00
|
|
|
"github.com/ory/fosite"
|
2021-05-05 05:06:05 +07:00
|
|
|
"github.com/stretchr/testify/assert"
|
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-04 06:44:30 +07:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-05-05 05:06:05 +07:00
|
|
|
|
|
|
|
"github.com/authelia/authelia/internal/authentication"
|
|
|
|
"github.com/authelia/authelia/internal/authorization"
|
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-04 06:44:30 +07:00
|
|
|
"github.com/authelia/authelia/internal/configuration/schema"
|
|
|
|
"github.com/authelia/authelia/internal/session"
|
2021-05-05 05:06:05 +07: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-04 06:44:30 +07:00
|
|
|
func TestNewClient(t *testing.T) {
|
|
|
|
blankConfig := schema.OpenIDConnectClientConfiguration{}
|
|
|
|
blankClient := NewClient(blankConfig)
|
|
|
|
assert.Equal(t, "", blankClient.ID)
|
|
|
|
assert.Equal(t, "", blankClient.Description)
|
|
|
|
assert.Equal(t, "", blankClient.Description)
|
|
|
|
require.Len(t, blankClient.ResponseModes, 1)
|
|
|
|
assert.Equal(t, fosite.ResponseModeDefault, blankClient.ResponseModes[0])
|
|
|
|
|
|
|
|
exampleConfig := schema.OpenIDConnectClientConfiguration{
|
|
|
|
ID: "myapp",
|
|
|
|
Description: "My App",
|
|
|
|
Policy: "two_factor",
|
|
|
|
Secret: "abcdef",
|
|
|
|
RedirectURIs: []string{"https://google.com/callback"},
|
|
|
|
Scopes: schema.DefaultOpenIDConnectClientConfiguration.Scopes,
|
|
|
|
ResponseTypes: schema.DefaultOpenIDConnectClientConfiguration.ResponseTypes,
|
|
|
|
GrantTypes: schema.DefaultOpenIDConnectClientConfiguration.GrantTypes,
|
|
|
|
ResponseModes: schema.DefaultOpenIDConnectClientConfiguration.ResponseModes,
|
|
|
|
}
|
|
|
|
|
|
|
|
exampleClient := NewClient(exampleConfig)
|
|
|
|
assert.Equal(t, "myapp", exampleClient.ID)
|
|
|
|
require.Len(t, exampleClient.ResponseModes, 4)
|
|
|
|
assert.Equal(t, fosite.ResponseModeDefault, exampleClient.ResponseModes[0])
|
|
|
|
assert.Equal(t, fosite.ResponseModeFormPost, exampleClient.ResponseModes[1])
|
|
|
|
assert.Equal(t, fosite.ResponseModeQuery, exampleClient.ResponseModes[2])
|
|
|
|
assert.Equal(t, fosite.ResponseModeFragment, exampleClient.ResponseModes[3])
|
|
|
|
}
|
|
|
|
|
2021-05-05 05:06:05 +07:00
|
|
|
func TestIsAuthenticationLevelSufficient(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
c.Policy = authorization.Bypass
|
|
|
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated))
|
|
|
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor))
|
|
|
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor))
|
|
|
|
|
|
|
|
c.Policy = authorization.OneFactor
|
|
|
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated))
|
|
|
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor))
|
|
|
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor))
|
|
|
|
|
|
|
|
c.Policy = authorization.TwoFactor
|
|
|
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated))
|
|
|
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor))
|
|
|
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor))
|
|
|
|
|
|
|
|
c.Policy = authorization.Denied
|
|
|
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated))
|
|
|
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor))
|
|
|
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor))
|
|
|
|
}
|
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-04 06:44:30 +07:00
|
|
|
|
|
|
|
func TestInternalClient_GetConsentResponseBody(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
consentRequestBody := c.GetConsentResponseBody(nil)
|
|
|
|
assert.Equal(t, "", consentRequestBody.ClientID)
|
|
|
|
assert.Equal(t, "", consentRequestBody.ClientDescription)
|
|
|
|
assert.Equal(t, []Scope(nil), consentRequestBody.Scopes)
|
|
|
|
assert.Equal(t, []Audience(nil), consentRequestBody.Audience)
|
|
|
|
|
|
|
|
c.ID = "myclient"
|
|
|
|
c.Description = "My Client"
|
|
|
|
|
|
|
|
workflow := &session.OIDCWorkflowSession{
|
|
|
|
RequestedAudience: []string{"https://example.com"},
|
|
|
|
RequestedScopes: []string{"openid", "groups"},
|
|
|
|
}
|
|
|
|
expectedScopes := []Scope{
|
|
|
|
{"openid", "Use OpenID to verify your identity"},
|
|
|
|
{"groups", "Access your group membership"},
|
|
|
|
}
|
|
|
|
expectedAudiences := []Audience{
|
|
|
|
{"https://example.com", "https://example.com"},
|
|
|
|
}
|
|
|
|
|
|
|
|
consentRequestBody = c.GetConsentResponseBody(workflow)
|
|
|
|
assert.Equal(t, "myclient", consentRequestBody.ClientID)
|
|
|
|
assert.Equal(t, "My Client", consentRequestBody.ClientDescription)
|
|
|
|
assert.Equal(t, expectedScopes, consentRequestBody.Scopes)
|
|
|
|
assert.Equal(t, expectedAudiences, consentRequestBody.Audience)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalClient_GetAudience(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
audience := c.GetAudience()
|
|
|
|
assert.Len(t, audience, 0)
|
|
|
|
|
|
|
|
c.Audience = []string{"https://example.com"}
|
|
|
|
|
|
|
|
audience = c.GetAudience()
|
|
|
|
require.Len(t, audience, 1)
|
|
|
|
assert.Equal(t, "https://example.com", audience[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalClient_GetScopes(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
scopes := c.GetScopes()
|
|
|
|
assert.Len(t, scopes, 0)
|
|
|
|
|
|
|
|
c.Scopes = []string{"openid"}
|
|
|
|
|
|
|
|
scopes = c.GetScopes()
|
|
|
|
require.Len(t, scopes, 1)
|
|
|
|
assert.Equal(t, "openid", scopes[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalClient_GetGrantTypes(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
grantTypes := c.GetGrantTypes()
|
|
|
|
require.Len(t, grantTypes, 1)
|
|
|
|
assert.Equal(t, "authorization_code", grantTypes[0])
|
|
|
|
|
|
|
|
c.GrantTypes = []string{"device_code"}
|
|
|
|
|
|
|
|
grantTypes = c.GetGrantTypes()
|
|
|
|
require.Len(t, grantTypes, 1)
|
|
|
|
assert.Equal(t, "device_code", grantTypes[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalClient_GetHashedSecret(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
hashedSecret := c.GetHashedSecret()
|
|
|
|
assert.Equal(t, []byte(nil), hashedSecret)
|
|
|
|
|
|
|
|
c.Secret = []byte("a_bad_secret")
|
|
|
|
|
|
|
|
hashedSecret = c.GetHashedSecret()
|
|
|
|
assert.Equal(t, []byte("a_bad_secret"), hashedSecret)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalClient_GetID(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
id := c.GetID()
|
|
|
|
assert.Equal(t, "", id)
|
|
|
|
|
|
|
|
c.ID = "myid"
|
|
|
|
|
|
|
|
id = c.GetID()
|
|
|
|
assert.Equal(t, "myid", id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalClient_GetRedirectURIs(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
redirectURIs := c.GetRedirectURIs()
|
|
|
|
require.Len(t, redirectURIs, 0)
|
|
|
|
|
|
|
|
c.RedirectURIs = []string{"https://example.com/oauth2/callback"}
|
|
|
|
|
|
|
|
redirectURIs = c.GetRedirectURIs()
|
|
|
|
require.Len(t, redirectURIs, 1)
|
|
|
|
assert.Equal(t, "https://example.com/oauth2/callback", redirectURIs[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalClient_GetResponseModes(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
responseModes := c.GetResponseModes()
|
|
|
|
require.Len(t, responseModes, 0)
|
|
|
|
|
|
|
|
c.ResponseModes = []fosite.ResponseModeType{
|
|
|
|
fosite.ResponseModeDefault, fosite.ResponseModeFormPost,
|
|
|
|
fosite.ResponseModeQuery, fosite.ResponseModeFragment,
|
|
|
|
}
|
|
|
|
|
|
|
|
responseModes = c.GetResponseModes()
|
|
|
|
require.Len(t, responseModes, 4)
|
|
|
|
assert.Equal(t, fosite.ResponseModeDefault, responseModes[0])
|
|
|
|
assert.Equal(t, fosite.ResponseModeFormPost, responseModes[1])
|
|
|
|
assert.Equal(t, fosite.ResponseModeQuery, responseModes[2])
|
|
|
|
assert.Equal(t, fosite.ResponseModeFragment, responseModes[3])
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalClient_GetResponseTypes(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
responseTypes := c.GetResponseTypes()
|
|
|
|
require.Len(t, responseTypes, 1)
|
|
|
|
assert.Equal(t, "code", responseTypes[0])
|
|
|
|
|
|
|
|
c.ResponseTypes = []string{"code", "id_token"}
|
|
|
|
|
|
|
|
responseTypes = c.GetResponseTypes()
|
|
|
|
require.Len(t, responseTypes, 2)
|
|
|
|
assert.Equal(t, "code", responseTypes[0])
|
|
|
|
assert.Equal(t, "id_token", responseTypes[1])
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInternalClient_IsPublic(t *testing.T) {
|
|
|
|
c := InternalClient{}
|
|
|
|
|
|
|
|
assert.False(t, c.IsPublic())
|
|
|
|
|
|
|
|
c.Public = true
|
|
|
|
assert.True(t, c.IsPublic())
|
|
|
|
}
|