authelia/internal/handlers/handler_oidc_token_test.go

1510 lines
56 KiB
Go
Raw Normal View History

package handlers
import (
"context"
"crypto/ecdsa"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"database/sql"
"encoding/base64"
"encoding/pem"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"testing"
"time"
"github.com/golang-jwt/jwt/v4"
"github.com/golang/mock/gomock"
"github.com/google/uuid"
"github.com/ory/fosite"
"github.com/stretchr/testify/suite"
"github.com/valyala/fasthttp"
"github.com/authelia/authelia/v4/internal/authorization"
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/mocks"
"github.com/authelia/authelia/v4/internal/model"
"github.com/authelia/authelia/v4/internal/oidc"
)
func TestClientAuthenticationStrategySuite(t *testing.T) {
suite.Run(t, &ClientAuthenticationStrategySuite{})
}
type ClientAuthenticationStrategySuite struct {
suite.Suite
issuerURL *url.URL
ctrl *gomock.Controller
store *mocks.MockStorage
provider *oidc.OpenIDConnectProvider
}
func (s *ClientAuthenticationStrategySuite) GetIssuerURL() *url.URL {
if s.issuerURL == nil {
s.issuerURL = MustParseRequestURI("https://auth.example.com")
}
return s.issuerURL
}
func (s *ClientAuthenticationStrategySuite) GetTokenURL() *url.URL {
return s.GetIssuerURL().JoinPath(oidc.EndpointPathToken)
}
func (s *ClientAuthenticationStrategySuite) GetBaseRequest(body io.Reader) (r *http.Request) {
var err error
r, err = http.NewRequest(http.MethodPost, s.GetTokenURL().String(), body)
s.Require().NoError(err)
s.Require().NotNil(r)
r.Header.Set(fasthttp.HeaderContentType, "application/x-www-form-urlencoded")
return r
}
func (s *ClientAuthenticationStrategySuite) GetRequest(values *url.Values) (r *http.Request) {
var body io.Reader
if values != nil {
body = strings.NewReader(values.Encode())
}
r = s.GetBaseRequest(body)
s.Require().NoError(r.ParseForm())
return r
}
func (s *ClientAuthenticationStrategySuite) GetAssertionValues(token string) *url.Values {
values := &url.Values{}
values.Set(oidc.FormParameterClientAssertionType, oidc.ClientAssertionJWTBearerType)
if token != "" {
values.Set(oidc.FormParameterClientAssertion, token)
}
return values
}
func (s *ClientAuthenticationStrategySuite) GetClientValues(id string) *url.Values {
values := &url.Values{}
values.Set(oidc.FormParameterClientID, id)
return values
}
func (s *ClientAuthenticationStrategySuite) GetClientValuesPost(id, secret string) *url.Values {
values := s.GetClientValues(id)
values.Set(oidc.FormParameterClientSecret, secret)
return values
}
func (s *ClientAuthenticationStrategySuite) GetClientSecretBasicRequest(id, secret string) (r *http.Request) {
values := s.GetClientValues(id)
r = s.GetRequest(values)
r.SetBasicAuth(id, secret)
return r
}
func (s *ClientAuthenticationStrategySuite) GetClientSecretPostRequest(id, secret string) (r *http.Request) {
values := s.GetClientValuesPost(id, secret)
return s.GetRequest(values)
}
func (s *ClientAuthenticationStrategySuite) GetAssertionRequest(token string) (r *http.Request) {
values := s.GetAssertionValues(token)
return s.GetRequest(values)
}
func (s *ClientAuthenticationStrategySuite) GetCtx() oidc.OpenIDConnectContext {
return &oidc.MockOpenIDConnectContext{
Context: context.Background(),
MockIssuerURL: s.GetIssuerURL(),
}
}
func (s *ClientAuthenticationStrategySuite) SetupTest() {
s.ctrl = gomock.NewController(s.T())
s.store = mocks.NewMockStorage(s.ctrl)
secret := MustDecodeSecret("$plaintext$client-secret")
s.provider = oidc.NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{
IssuerJWKS: []schema.JWK{},
IssuerCertificateChain: schema.X509CertificateChain{},
IssuerPrivateKey: MustParseRSAPrivateKey(exampleRSAPrivateKey),
HMACSecret: "abc123",
Clients: []schema.OpenIDConnectClientConfiguration{
{
ID: "hs256",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgHMACUsingSHA256,
},
{
ID: "hs384",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgHMACUsingSHA384,
},
{
ID: "hs512",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgHMACUsingSHA512,
},
{
ID: "rs256",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAUsingSHA256,
},
{
ID: "rs384",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAUsingSHA384,
},
{
ID: "rs512",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAUsingSHA512,
},
{
ID: "ps256",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAPSSUsingSHA256,
},
{
ID: "ps384",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAPSSUsingSHA384,
},
{
ID: "ps512",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgRSAPSSUsingSHA512,
},
{
ID: "es256",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgECDSAUsingP256AndSHA256,
},
{
ID: "es384",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgECDSAUsingP384AndSHA384,
},
{
ID: "es512",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgECDSAUsingP521AndSHA512,
},
{
ID: "hs5122",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgHMACUsingSHA512,
},
{
ID: "hashed",
Secret: MustDecodeSecret("$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng"),
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretJWT,
TokenEndpointAuthSigningAlg: oidc.SigningAlgHMACUsingSHA512,
},
{
ID: oidc.ClientAuthMethodClientSecretBasic,
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretBasic,
TokenEndpointAuthSigningAlg: oidc.SigningAlgNone,
},
{
ID: oidc.ClientAuthMethodNone,
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodNone,
TokenEndpointAuthSigningAlg: oidc.SigningAlgNone,
},
{
ID: oidc.ClientAuthMethodClientSecretPost,
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretPost,
TokenEndpointAuthSigningAlg: oidc.SigningAlgNone,
},
{
ID: "bad_method",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
TokenEndpointAuthMethod: "bad_method",
TokenEndpointAuthSigningAlg: oidc.SigningAlgNone,
},
{
ID: "base",
Secret: secret,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
},
{
ID: "public",
Public: true,
Policy: authorization.OneFactor.String(),
TokenEndpointAuthMethod: oidc.ClientAuthMethodNone,
RedirectURIs: []string{
"https://client.example.com",
},
},
{
ID: "public-nomethod",
Public: true,
Policy: authorization.OneFactor.String(),
RedirectURIs: []string{
"https://client.example.com",
},
},
{
ID: "public-basic",
Public: true,
Policy: authorization.OneFactor.String(),
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretBasic,
RedirectURIs: []string{
"https://client.example.com",
},
},
},
}, s.store, nil)
}
func (s *ClientAuthenticationStrategySuite) TestShouldValidateAssertionHS256() {
assertion := NewAssertion("hs256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS256, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
ctx := s.GetCtx()
gomock.InOrder(
s.store.
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
Return(nil, sql.ErrNoRows),
s.store.
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
Return(nil),
)
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.NoError(ErrorToRFC6749ErrorTest(err))
s.Require().NotNil(client)
s.Equal("hs256", client.GetID())
}
func (s *ClientAuthenticationStrategySuite) TestShouldValidateAssertionHS384() {
assertion := NewAssertion("hs384", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS384, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
ctx := s.GetCtx()
gomock.InOrder(
s.store.
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
Return(nil, sql.ErrNoRows),
s.store.
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
Return(nil),
)
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.NoError(ErrorToRFC6749ErrorTest(err))
s.Require().NotNil(client)
s.Equal("hs384", client.GetID())
}
func (s *ClientAuthenticationStrategySuite) TestShouldValidateAssertionHS512() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
ctx := s.GetCtx()
gomock.InOrder(
s.store.
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
Return(nil, sql.ErrNoRows),
s.store.
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
Return(nil),
)
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.NoError(ErrorToRFC6749ErrorTest(err))
s.Require().NotNil(client)
s.Equal("hs512", client.GetID())
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnMismatchedAlg() {
assertion := NewAssertion("rs256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The 'client_assertion' uses signing algorithm 'HS512' but the requested OAuth 2.0 Client enforces signing algorithm 'RS256'.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnMismatchedAlgSameMethod() {
assertion := NewAssertion("hs256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The 'client_assertion' uses signing algorithm 'HS512' but the requested OAuth 2.0 Client enforces signing algorithm 'HS256'.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysRS256() {
assertion := NewAssertion("rs256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS256, assertion)
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysRS384() {
assertion := NewAssertion("rs384", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS384, assertion)
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysRS512() {
assertion := NewAssertion("rs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodRS512, assertion)
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysPS256() {
assertion := NewAssertion("ps256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS256, assertion)
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysPS384() {
assertion := NewAssertion("ps384", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS384, assertion)
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysPS512() {
assertion := NewAssertion("ps512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodPS512, assertion)
token, err := assertionJWT.SignedString(MustParseRSAPrivateKey(exampleRSAPrivateKey))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysES256() {
assertion := NewAssertion("es256", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES256, assertion)
token, err := assertionJWT.SignedString(MustParseECPrivateKey(exampleECP256PrivateKey))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysES384() {
assertion := NewAssertion("es384", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES384, assertion)
token, err := assertionJWT.SignedString(MustParseECPrivateKey(exampleECP384PrivateKey))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnUnregisteredKeysES512() {
assertion := NewAssertion("es512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodES512, assertion)
token, err := assertionJWT.SignedString(MustParseECPrivateKey(exampleECP521PrivateKey))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnJTIKnown() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
ctx := s.GetCtx()
gomock.InOrder(
s.store.
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
Return(nil, sql.ErrNoRows),
s.store.
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
Return(fosite.ErrJTIKnown),
)
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "The jti was already used.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldValidateJWTWithArbitraryClaims() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
a := assertion.ToMapClaims()
a["aaa"] = "abc"
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, a)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
ctx := s.GetCtx()
gomock.InOrder(
s.store.
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
Return(nil, sql.ErrNoRows),
s.store.
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
Return(nil),
)
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.NoError(ErrorToRFC6749ErrorTest(err))
s.Require().NotNil(client)
s.Equal("hs512", client.GetID())
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithMissingSubClaim() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
a := assertion.ToMapClaims()
delete(a, oidc.ClaimSubject)
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, a)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The claim 'sub' from the client_assertion JSON Web Token is undefined.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithInvalidExpClaim() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
a := assertion.ToMapClaims()
a[oidc.ClaimExpirationTime] = "not a number"
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, a)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Unable to verify the integrity of the 'client_assertion' value. The token is expired.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithMissingIssClaim() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
a := assertion.ToMapClaims()
delete(a, oidc.ClaimIssuer)
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, a)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Claim 'iss' from 'client_assertion' must match the 'client_id' of the OAuth 2.0 Client.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithInvalidAudClaim() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertion.Audience = []string{"notvalid"}
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
sig := fmt.Sprintf("%x", sha256.Sum256([]byte(assertion.ID)))
ctx := s.GetCtx()
gomock.InOrder(
s.store.
EXPECT().LoadOAuth2BlacklistedJTI(ctx, sig).
Return(nil, sql.ErrNoRows),
s.store.
EXPECT().SaveOAuth2BlacklistedJTI(ctx, model.OAuth2BlacklistedJTI{Signature: sig, ExpiresAt: assertion.ExpiresAt.Time}).
Return(nil),
)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Claim 'audience' from 'client_assertion' must match the authorization server's token endpoint 'https://auth.example.com/api/oidc/token'.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithInvalidAssertionType() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
v := s.GetAssertionValues(token)
v.Set(oidc.FormParameterClientAssertionType, "not_valid")
r := s.GetRequest(v)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Unknown client_assertion_type 'not_valid'.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithMissingJTIClaim() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
a := assertion.ToMapClaims()
delete(a, oidc.ClaimJWTID)
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, a)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Claim 'jti' from 'client_assertion' must be set but is not.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithMismatchedIssClaim() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertion.Issuer = "hs256"
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Claim 'iss' from 'client_assertion' must match the 'client_id' of the OAuth 2.0 Client.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldValidateClientSecretPost() {
r := s.GetClientSecretPostRequest(oidc.ClientAuthMethodClientSecretPost, "client-secret")
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.NoError(err)
s.Require().NotNil(client)
s.Equal(oidc.ClientAuthMethodClientSecretPost, client.GetID())
}
func (s *ClientAuthenticationStrategySuite) TestShouldErrorClientSecretPostOnClientSecretBasicClient() {
r := s.GetClientSecretPostRequest(oidc.ClientAuthMethodClientSecretBasic, "client-secret")
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client supports client authentication method 'client_secret_basic', but method 'client_secret_post' was requested. You must configure the OAuth 2.0 client's 'token_endpoint_auth_method' value to accept 'client_secret_post'.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldErrorClientSecretPostWrongSecret() {
r := s.GetClientSecretPostRequest(oidc.ClientAuthMethodClientSecretPost, "client-secret-bad")
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The provided client secret did not match the registered client secret.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldValidateClientSecretBasic() {
r := s.GetClientSecretBasicRequest(oidc.ClientAuthMethodClientSecretBasic, "client-secret")
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.NoError(err)
s.Require().NotNil(client)
s.Equal(oidc.ClientAuthMethodClientSecretBasic, client.GetID())
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnClientSecretPostWithoutClientID() {
r := s.GetRequest(&url.Values{oidc.FormParameterClientSecret: []string{"client-secret"}})
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_request")
s.EqualError(ErrorToRFC6749ErrorTest(err), "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Client credentials missing or malformed in both HTTP Authorization header and HTTP POST body.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnClientSecretBasicWithMalformedClientID() {
r := s.GetRequest(&url.Values{oidc.FormParameterRequestURI: []string{"not applicable"}})
r.Header.Set(fasthttp.HeaderAuthorization, fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte("abc@#%!@#(*%)#@!:client-secret"))))
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_request")
s.EqualError(ErrorToRFC6749ErrorTest(err), "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. The client id in the HTTP authorization header could not be decoded from 'application/x-www-form-urlencoded'. invalid URL escape '%!@'")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldRaiseErrorOnClientSecretBasicWithMalformedClientSecret() {
r := s.GetRequest(&url.Values{oidc.FormParameterRequestURI: []string{"not applicable"}})
r.Header.Set(fasthttp.HeaderAuthorization, fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte("hs512:abc@#%!@#(*%)#@!"))))
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_request")
s.EqualError(ErrorToRFC6749ErrorTest(err), "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. The client secret in the HTTP authorization header could not be decoded from 'application/x-www-form-urlencoded'. invalid URL escape '%!@'")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldErrorClientSecretBasicOnClientSecretPostClient() {
r := s.GetClientSecretBasicRequest(oidc.ClientAuthMethodClientSecretPost, "client-secret")
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client supports client authentication method 'client_secret_post', but method 'client_secret_basic' was requested. You must configure the OAuth 2.0 client's 'token_endpoint_auth_method' value to accept 'client_secret_basic'.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldErrorClientSecretBasicWrongSecret() {
r := s.GetClientSecretBasicRequest(oidc.ClientAuthMethodClientSecretBasic, "client-secret-bad")
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The provided client secret did not match the registered client secret.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldErrorClientSecretBasicOnPublic() {
r := s.GetClientSecretBasicRequest("public", "client-secret")
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client supports client authentication method 'none', but method 'client_secret_basic' was requested. You must configure the OAuth 2.0 client's 'token_endpoint_auth_method' value to accept 'client_secret_basic'.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldErrorClientSecretBasicOnPublicWithBasic() {
r := s.GetClientSecretBasicRequest("public-basic", "client-secret")
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The OAuth 2.0 Client supports client authentication method 'client_secret_basic', but method 'none' was requested. You must configure the OAuth 2.0 client's 'token_endpoint_auth_method' value to accept 'none'.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldErrorClientSecretBasicOnInvalidClient() {
r := s.GetClientSecretBasicRequest("not-a-client", "client-secret")
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). invalid_client")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldValidatePublic() {
v := s.GetClientValues("public")
r := s.GetRequest(v)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.NoError(err)
s.Require().NotNil(client)
s.Equal("public", client.GetID())
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithMismatchedFormClientID() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertion.Issuer = "hs5122"
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
values := s.GetAssertionValues(token)
values.Set(oidc.FormParameterClientID, "hs5122")
r := s.GetRequest(values)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Claim 'sub' from 'client_assertion' must match the 'client_id' of the OAuth 2.0 Client.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithMismatchedFormClientIDWithIss() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
values := s.GetAssertionValues(token)
values.Set(oidc.FormParameterClientID, "hs5122")
r := s.GetRequest(values)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Claim 'iss' from 'client_assertion' must match the 'client_id' of the OAuth 2.0 Client.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailWithMissingClient() {
assertion := NewAssertion("noclient", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
client, err := s.provider.DefaultClientAuthenticationStrategy(s.GetCtx(), r, r.PostForm)
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). invalid_client")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailBadSecret() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret-wrong"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Unable to verify the integrity of the 'client_assertion' value. The signature is invalid.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailMethodNone() {
assertion := NewAssertion(oidc.ClientAuthMethodNone, s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). This requested OAuth 2.0 client does not support client authentication, however 'client_assertion' was provided in the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailAssertionMethodClientSecretPost() {
assertion := NewAssertion(oidc.ClientAuthMethodClientSecretPost, s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). This requested OAuth 2.0 client only supports client authentication method 'client_secret_post', however 'client_assertion' was provided in the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailAssertionMethodBad() {
assertion := NewAssertion("bad_method", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). This requested OAuth 2.0 client only supports client authentication method 'bad_method', however that method is not supported by this server.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailAssertionBaseClient() {
assertion := NewAssertion("base", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_request")
s.EqualError(ErrorToRFC6749ErrorTest(err), "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. The client configuration does not support OpenID Connect specific authentication methods.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailAssertionMethodClientSecretBasic() {
assertion := NewAssertion(oidc.ClientAuthMethodClientSecretBasic, s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). This requested OAuth 2.0 client only supports client authentication method 'client_secret_basic', however 'client_assertion' was provided in the request.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailHashedSecret() {
assertion := NewAssertion("hashed", s.GetTokenURL(), time.Now().Add(time.Second*-3), time.Unix(time.Now().Add(time.Minute).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). This client does not support authentication method 'client_secret_jwt' as the client secret is not in plaintext.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailExpiredToken() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Minute*-3), time.Unix(time.Now().Add(time.Minute*-1).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Unable to verify the integrity of the 'client_assertion' value. The token is expired.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailNotYetValid() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Minute*-3), time.Unix(time.Now().Add(time.Minute*1).Unix(), 0))
assertion.NotBefore = jwt.NewNumericDate(time.Now().Add(time.Second * 10))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
s.NoError(r.ParseForm())
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Unable to verify the integrity of the 'client_assertion' value. The token isn't valid yet.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailTokenUsedBeforeIssued() {
assertion := NewAssertion("hs512", s.GetTokenURL(), time.Now().Add(time.Minute*3), time.Unix(time.Now().Add(time.Minute*8).Unix(), 0))
assertionJWT := jwt.NewWithClaims(jwt.SigningMethodHS512, assertion)
token, err := assertionJWT.SignedString([]byte("client-secret"))
s.Require().NoError(err)
s.Require().NotEqual("", token)
r := s.GetAssertionRequest(token)
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Unable to verify the integrity of the 'client_assertion' value. The token was used before it was issued.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailMalformed() {
r := s.GetAssertionRequest("bad token")
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_client")
s.EqualError(ErrorToRFC6749ErrorTest(err), "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). Unable to verify the integrity of the 'client_assertion' value. The token is malformed.")
s.Nil(client)
}
func (s *ClientAuthenticationStrategySuite) TestShouldFailMissingAssertion() {
r := s.GetAssertionRequest("")
ctx := s.GetCtx()
client, err := s.provider.DefaultClientAuthenticationStrategy(ctx, r, r.PostForm)
s.EqualError(err, "invalid_request")
s.EqualError(ErrorToRFC6749ErrorTest(err), "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. The client_assertion request parameter must be set when using client_assertion_type of 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'.")
s.Nil(client)
}
type RegisteredClaims struct {
jwt.RegisteredClaims
}
func (r *RegisteredClaims) ToMapClaims() jwt.MapClaims {
claims := jwt.MapClaims{}
if r.ID != "" {
claims[oidc.ClaimJWTID] = r.ID
}
if r.Subject != "" {
claims[oidc.ClaimSubject] = r.Subject
}
if r.Issuer != "" {
claims[oidc.ClaimIssuer] = r.Issuer
}
if len(r.Audience) != 0 {
claims[oidc.ClaimAudience] = r.Audience
}
if r.NotBefore != nil {
claims[oidc.ClaimNotBefore] = r.NotBefore
}
if r.ExpiresAt != nil {
claims[oidc.ClaimExpirationTime] = r.ExpiresAt
}
if r.IssuedAt != nil {
claims[oidc.ClaimIssuedAt] = r.IssuedAt
}
return claims
}
func NewAssertion(clientID string, tokenURL *url.URL, iat, exp time.Time) RegisteredClaims {
return RegisteredClaims{
jwt.RegisteredClaims{
ID: uuid.Must(uuid.NewRandom()).String(),
Issuer: clientID,
Audience: []string{
tokenURL.String(),
},
Subject: clientID,
IssuedAt: jwt.NewNumericDate(iat),
ExpiresAt: jwt.NewNumericDate(exp),
},
}
}
type RFC6749ErrorTest struct {
*fosite.RFC6749Error
}
func (err *RFC6749ErrorTest) Error() string {
return err.WithExposeDebug(true).GetDescription()
}
func ErrorToRFC6749ErrorTest(err error) (rfc error) {
if err == nil {
return nil
}
ferr := fosite.ErrorToRFC6749Error(err)
return &RFC6749ErrorTest{ferr}
}
func MustDecodeSecret(value string) *schema.PasswordDigest {
if secret, err := schema.DecodePasswordDigest(value); err != nil {
panic(err)
} else {
return secret
}
}
func MustParseRequestURI(input string) *url.URL {
if requestURI, err := url.ParseRequestURI(input); err != nil {
panic(err)
} else {
return requestURI
}
}
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 MustParseECPrivateKey(data string) *ecdsa.PrivateKey {
block, _ := pem.Decode([]byte(data))
if block == nil || block.Bytes == nil || len(block.Bytes) == 0 {
panic("not pem encoded")
}
if block.Type != "EC PRIVATE KEY" {
panic("not private key")
}
key, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
panic(err)
}
return key
}
const exampleRSAPrivateKey = `
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA60Vuz1N1wUHiCDIlbz8gE0dWPCmHEWnXKchEEISqIJ6j5Eah
Q/GwX3WK0UV5ATRvWhg6o7/WfrLYcAsi4w79TgMjJHLWIY/jzAS3quEtzOLlLSWZ
9FR9SomQm3T/ETOS8IvSGrksIj0WgX35jB1NnbqSTRnYx7Cg/TBJjmiaqd0b9G/8
LlReaihwGf8tvPgnteWIdon3EI2MKDBkaesRjpL98Cz7VvD7dajseAlUh9jQWVge
sN8qnm8pNPFAYsgxf//Jf0RfsND6H70zKKybDmyct4T4o/8qjivw4ly0XkArDCUj
Qx2KUF7nN+Bo9wwnNppjdnsOPUbus8o1a9vY1QIDAQABAoIBAQDl1SBY3PlN36SF
yScUtCALdUbi4taVxkVxBbioQlFIKHGGkRD9JN/dgSApK6r36FdXNhAi40cQ4nnZ
iqd8FKqTSTFNa/mPM9ee+ITMI8nwOz8SiYcKTndPF2/yzapXDYDgCFcpz/czQ2X2
/i+IFyA5k4dUVomVGhFLBZ71xW5BvGUBMUH0XkeR5+c4gLvgR209BlpBHlkX4tUQ
+RQoxbKpkntl0mjqf91zcOe4LJVsXZFyN+NVSzLEbGC3lVSSiyjVQH3s7ExnTaHi
PpwSoXzu5QJj5xRit/1B3/LEGpIlPGFrkhMzBDTN+HYV/VLbCHJzjg5GVJawA82E
h2BY6YWJAoGBAPmGaZL5ggnTVR2XVBLDKbwL/sesqiPZk45B+I5eObHl+v236JH9
RPMjdE10jOR1TzfQdmE2/RboKhiVn+osS+2W6VXSo7sMsSM1bLBPYhnwrNIqzrX8
Vgi2bCl2S8ZhVo2R8c5WUaD0Gpxs6hwPIMOQWWwxDlsbg/UoLrhD3X4XAoGBAPFg
VSvaWQdDVAqjM42ObhZtWxeLfEAcxRQDMQq7btrTwBZSrtP3S3Egu66cp/4PT4VD
Hc8tYyT2rNETiqT6b2Rm1MgeoJ8wRqte6ZXSQVVQUOd42VG04O3aaleAGhXjEkM2
avctRdKHDhQdIt+riPgaNj4FdYpmQ5zIrcZtBr/zAoGBAOBXzBX7xMHmwxEe3NUd
qSlMM579C9+9oF/3ymzeJMtgtcBmGHEhoFtmVgvJrV8+ZaIOCFExam2tASQnaqbV
etK7q0ChaNok+CJqxzThupcN/6PaHw4aOJQOx8KjfE95dqNEQ367txqaPk7D0dy2
cUPDRdLzbC/X1lWV8iNzyPGzAoGBAN4R2epRpYz4Fa7/vWNkAcaib6c2zmaR0YN6
+Di+ftvW6yfehDhBkWgQTHv2ZtxoK6oYOKmuQUP1qsNkbi8gtTEzJlrDStWKbcom
tVMAsNkT3otHdPEmL7bFNwcvtVAjrF6oBztHrLBnTr2UnMwZnhdczkC7dwuQ0G3D
d5VSI16fAoGAY7eeVDkic73GbZmtZibuodvPJ/z85RIBOrzf3ColO4jGI6Ej/EnD
rMEe/mRC27CJzS9L9Jc0Kt66mGSvodDGl0nBsXGNfPog0cGwweCVN0Eo2VJZbRTT
UoU05/Pvu2h3/E8gGTBY0/WPSo06YUsICjVDWNuOIa/7IY7SyE6Xxn0=
-----END RSA PRIVATE KEY-----`
const exampleECP256PrivateKey = `
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEID1fSsJ8qyEqj2DVkrshaNiXqaSDX7qViASRkyGGJFbEoAoGCCqGSM49
AwEHoUQDQgAENnBG+bBJIaIa+bRlHaLiXD86RAy+Ef9CVdAfpPGoNRfkOTcrrIV7
2wv3Y5e0he63Tn9iVAFYRFexK1mjFw7TfA==
-----END EC PRIVATE KEY-----`
const exampleECP384PrivateKey = `
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDBPoOfapxtgZ8XNE7Wwdlw+9oDc6x4m57MITZyWzN62jkFUAYsvPJDF
9+g+e8CT5yqgBwYFK4EEACKhZANiAAQ2uZ0HIIxIavyjGyX13tIZVOaRB4+D64dF
s3DXDrpXcuDTSohw9xBW5sLDqRVu2LkBsCUFXtEJUHgC+O7wToNw8nh+KdDrcu/J
miNqbvEHuvlSlHWyx9HH8kAEuu1+SZg=
-----END EC PRIVATE KEY-----`
const exampleECP521PrivateKey = `
-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIBT07AnitDd1Z01bl5W5VW8/vTWyu7w3MSqEmCeKcM19p/TAJAeS8L
6UOig2fTUeuMeA2PoOUjI2Bid927VsWcxE2gBwYFK4EEACOhgYkDgYYABAGnV9mu
xY0E7/k8b+glOOMaN0+Qt70H9OmSz6tC8tU3EayRwFlNPch9TlvEpbCS3MsDE9dN
78EpFx45MUqzzdZcOgAu+EUC9Zas1YVK+WMo0GFy+XtFq3kxubOclBb52M/63mcd
zZnA8aAu9iTK9YPfcw1YWTJliNdKUoxmGVV5Ca1W4w==
-----END EC PRIVATE KEY-----`