Skip to content

Commit

Permalink
feat: added support for ES256 token strategy and client authentication (
Browse files Browse the repository at this point in the history
#439)

I added to `DefaultOpenIDConnectClient` a field `TokenEndpointAuthSigningAlgorithm` to be able to configure what `GetTokenEndpointAuthSigningAlgorithm` returns. I also cleaned some other places where there were assumptions about only RSA keys.

Closes #429
  • Loading branch information
mitar authored May 28, 2020
1 parent a840a62 commit 36eb661
Show file tree
Hide file tree
Showing 7 changed files with 326 additions and 131 deletions.
12 changes: 6 additions & 6 deletions authorize_request_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,21 @@ func (f *Fosite) authorizeRequestParametersFromOpenIDConnectRequest(request *Aut

switch t.Method.(type) {
case *jwt.SigningMethodRSA:
key, err := f.findClientPublicJWK(oidcClient, t)
key, err := f.findClientPublicJWK(oidcClient, t, true)
if err != nil {
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve signing key from OAuth 2.0 Client because %s.", err))
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve RSA signing key from OAuth 2.0 Client because %s.", err))
}
return key, nil
case *jwt.SigningMethodECDSA:
key, err := f.findClientPublicJWK(oidcClient, t)
key, err := f.findClientPublicJWK(oidcClient, t, false)
if err != nil {
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve signing key from OAuth 2.0 Client because %s.", err))
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve ECDSA signing key from OAuth 2.0 Client because %s.", err))
}
return key, nil
case *jwt.SigningMethodRSAPSS:
key, err := f.findClientPublicJWK(oidcClient, t)
key, err := f.findClientPublicJWK(oidcClient, t, true)
if err != nil {
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve signing key from OAuth 2.0 Client because %s.", err))
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve RSA signing key from OAuth 2.0 Client because %s.", err))
}
return key, nil
default:
Expand Down
17 changes: 11 additions & 6 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@ type DefaultClient struct {

type DefaultOpenIDConnectClient struct {
*DefaultClient
JSONWebKeysURI string `json:"jwks_uri"`
JSONWebKeys *jose.JSONWebKeySet `json:"jwks"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method"`
RequestURIs []string `json:"request_uris"`
RequestObjectSigningAlgorithm string `json:"request_object_signing_alg"`
JSONWebKeysURI string `json:"jwks_uri"`
JSONWebKeys *jose.JSONWebKeySet `json:"jwks"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method"`
RequestURIs []string `json:"request_uris"`
RequestObjectSigningAlgorithm string `json:"request_object_signing_alg"`
TokenEndpointAuthSigningAlgorithm string `json:"token_endpoint_auth_signing_alg"`
}

func (c *DefaultClient) GetID() string {
Expand Down Expand Up @@ -158,7 +159,11 @@ func (c *DefaultOpenIDConnectClient) GetJSONWebKeys() *jose.JSONWebKeySet {
}

func (c *DefaultOpenIDConnectClient) GetTokenEndpointAuthSigningAlgorithm() string {
return "RS256"
if c.TokenEndpointAuthSigningAlgorithm == "" {
return "RS256"
} else {
return c.TokenEndpointAuthSigningAlgorithm
}
}

func (c *DefaultOpenIDConnectClient) GetRequestObjectSigningAlgorithm() string {
Expand Down
33 changes: 22 additions & 11 deletions client_authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package fosite

import (
"context"
"crypto/ecdsa"
"crypto/rsa"
"encoding/json"
"fmt"
Expand All @@ -37,9 +38,9 @@ import (

const clientAssertionJWTBearerType = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"

func (f *Fosite) findClientPublicJWK(oidcClient OpenIDConnectClient, t *jwt.Token) (interface{}, error) {
func (f *Fosite) findClientPublicJWK(oidcClient OpenIDConnectClient, t *jwt.Token, expectsRSAKey bool) (interface{}, error) {
if set := oidcClient.GetJSONWebKeys(); set != nil {
return findPublicKey(t, set)
return findPublicKey(t, set, expectsRSAKey)
}

if location := oidcClient.GetJSONWebKeysURI(); len(location) > 0 {
Expand All @@ -48,7 +49,7 @@ func (f *Fosite) findClientPublicJWK(oidcClient OpenIDConnectClient, t *jwt.Toke
return nil, err
}

if key, err := findPublicKey(t, keys); err == nil {
if key, err := findPublicKey(t, keys, expectsRSAKey); err == nil {
return key, nil
}

Expand All @@ -57,7 +58,7 @@ func (f *Fosite) findClientPublicJWK(oidcClient OpenIDConnectClient, t *jwt.Toke
return nil, err
}

return findPublicKey(t, keys)
return findPublicKey(t, keys, expectsRSAKey)
}

return nil, errors.WithStack(ErrInvalidClient.WithHint("The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request."))
Expand Down Expand Up @@ -115,11 +116,11 @@ func (f *Fosite) AuthenticateClient(ctx context.Context, r *http.Request, form u
}

if _, ok := t.Method.(*jwt.SigningMethodRSA); ok {
return f.findClientPublicJWK(oidcClient, t)
return f.findClientPublicJWK(oidcClient, t, true)
} else if _, ok := t.Method.(*jwt.SigningMethodECDSA); ok {
return f.findClientPublicJWK(oidcClient, t)
return f.findClientPublicJWK(oidcClient, t, false)
} else if _, ok := t.Method.(*jwt.SigningMethodRSAPSS); ok {
return f.findClientPublicJWK(oidcClient, t)
return f.findClientPublicJWK(oidcClient, t, true)
} else if _, ok := t.Method.(*jwt.SigningMethodHMAC); ok {
return nil, errors.WithStack(ErrInvalidClient.WithHint("This authorization server does not support client authentication method \"client_secret_jwt\"."))
}
Expand Down Expand Up @@ -231,7 +232,7 @@ func (f *Fosite) AuthenticateClient(ctx context.Context, r *http.Request, form u
return client, nil
}

func findPublicKey(t *jwt.Token, set *jose.JSONWebKeySet) (*rsa.PublicKey, error) {
func findPublicKey(t *jwt.Token, set *jose.JSONWebKeySet, expectsRSAKey bool) (interface{}, error) {
kid, ok := t.Header["kid"].(string)
if !ok {
return nil, errors.WithStack(ErrInvalidRequest.WithHint("The JSON Web Token must contain a kid header value but did not."))
Expand All @@ -246,12 +247,22 @@ func findPublicKey(t *jwt.Token, set *jose.JSONWebKeySet) (*rsa.PublicKey, error
if key.Use != "sig" {
continue
}
if k, ok := key.Key.(*rsa.PublicKey); ok {
return k, nil
if expectsRSAKey {
if k, ok := key.Key.(*rsa.PublicKey); ok {
return k, nil
}
} else {
if k, ok := key.Key.(*ecdsa.PublicKey); ok {
return k, nil
}
}
}

return nil, errors.WithStack(ErrInvalidRequest.WithHintf("Unable to find RSA public key with use=\"sig\" for kid \"%s\" in JSON Web Key Set.", kid))
if expectsRSAKey {
return nil, errors.WithStack(ErrInvalidRequest.WithHintf("Unable to find RSA public key with use=\"sig\" for kid \"%s\" in JSON Web Key Set.", kid))
} else {
return nil, errors.WithStack(ErrInvalidRequest.WithHintf("Unable to find ECDSA public key with use=\"sig\" for kid \"%s\" in JSON Web Key Set.", kid))
}
}

func clientCredentialsFromRequest(r *http.Request, form url.Values) (clientID, clientSecret string, err error) {
Expand Down
Loading

0 comments on commit 36eb661

Please sign in to comment.