feat: Token Revocation, Request Object and OP Certification (#130)

FEATURES (and FIXES):
- support OAuth 2.0 Token Revocation [RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009)
- handle request object using `request` parameter [OIDC Core 1.0 Request Object](https://openid.net/specs/openid-connect-core-1_0.html#RequestObject)
- handle response mode
- added some information to the discovery endpoint:
  - revocation_endpoint (added with token revocation) 
  - revocation_endpoint_auth_methods_supported (added with token revocation)
  - revocation_endpoint_auth_signing_alg_values_supported (added with token revocation)
  - token_endpoint_auth_signing_alg_values_supported (was missing)
  - introspection_endpoint_auth_signing_alg_values_supported (was missing)
  - request_object_signing_alg_values_supported (added with request object)
  - request_parameter_supported (added with request object)
 - fixed `removeUserinfoScopes ` now returns the scopes without "userinfo" scopes (profile, email, phone, addedd) [source diff](https://github.com/caos/oidc/pull/130/files#diff-fad50c8c0f065d4dbc49d6c6a38f09c992c8f5d651a479ba00e31b500543559eL170-R171)
- improved error handling (pkg/oidc/error.go) and fixed some wrong OAuth errors (e.g. `invalid_grant` instead of `invalid_request`)
- improved MarshalJSON and added MarshalJSONWithStatus
- removed deprecated PEM decryption from `BytesToPrivateKey`  [source diff](https://github.com/caos/oidc/pull/130/files#diff-fe246e428e399ccff599627c71764de51387b60b4df84c67de3febd0954e859bL11-L19)
- NewAccessTokenVerifier now uses correct (internal) `accessTokenVerifier` [source diff](https://github.com/caos/oidc/pull/130/files#diff-3a01c7500ead8f35448456ef231c7c22f8d291710936cac91de5edeef52ffc72L52-R52)

BREAKING CHANGE:
- move functions from `utils` package into separate packages
- added various methods to the (OP) `Configuration` interface [source diff](https://github.com/caos/oidc/pull/130/files#diff-2538e0dfc772fdc37f057aecd6fcc2943f516c24e8be794cce0e368a26d20a82R19-R32)
- added revocationEndpoint to `WithCustomEndpoints ` [source diff](https://github.com/caos/oidc/pull/130/files#diff-19ae13a743eb7cebbb96492798b1bec556673eb6236b1387e38d722900bae1c3L355-R391)
- remove unnecessary context parameter from JWTProfileExchange [source diff](https://github.com/caos/oidc/pull/130/files#diff-4ed8f6affa4a9631fa8a034b3d5752fbb6a819107141aae00029014e950f7b4cL14)
This commit is contained in:
Livio Amstutz 2021-11-02 13:21:35 +01:00 committed by GitHub
parent 763d3334e7
commit eb10752e48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 1738 additions and 624 deletions

View file

@ -12,8 +12,8 @@ import (
"golang.org/x/text/language"
"gopkg.in/square/go-jose.v2"
httphelper "github.com/caos/oidc/pkg/http"
"github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/utils"
)
const (
@ -23,6 +23,7 @@ const (
defaultTokenEndpoint = "oauth/token"
defaultIntrospectEndpoint = "oauth/introspect"
defaultUserinfoEndpoint = "userinfo"
defaultRevocationEndpoint = "revoke"
defaultEndSessionEndpoint = "end_session"
defaultKeysEndpoint = "keys"
)
@ -33,6 +34,7 @@ var (
Token: NewEndpoint(defaultTokenEndpoint),
Introspection: NewEndpoint(defaultIntrospectEndpoint),
Userinfo: NewEndpoint(defaultUserinfoEndpoint),
Revocation: NewEndpoint(defaultRevocationEndpoint),
EndSession: NewEndpoint(defaultEndSessionEndpoint),
JwksURI: NewEndpoint(defaultKeysEndpoint),
}
@ -41,8 +43,8 @@ var (
type OpenIDProvider interface {
Configuration
Storage() Storage
Decoder() utils.Decoder
Encoder() utils.Encoder
Decoder() httphelper.Decoder
Encoder() httphelper.Encoder
IDTokenHintVerifier() IDTokenHintVerifier
AccessTokenVerifier() AccessTokenVerifier
Crypto() Crypto
@ -74,6 +76,7 @@ func CreateRouter(o OpenIDProvider, interceptors ...HttpInterceptor) *mux.Router
router.Handle(o.TokenEndpoint().Relative(), intercept(tokenHandler(o)))
router.HandleFunc(o.IntrospectionEndpoint().Relative(), introspectionHandler(o))
router.HandleFunc(o.UserinfoEndpoint().Relative(), userinfoHandler(o))
router.HandleFunc(o.RevocationEndpoint().Relative(), revocationHandler(o))
router.Handle(o.EndSessionEndpoint().Relative(), intercept(endSessionHandler(o)))
router.HandleFunc(o.KeysEndpoint().Relative(), keysHandler(o.Storage()))
return router
@ -84,8 +87,10 @@ type Config struct {
CryptoKey [32]byte
DefaultLogoutRedirectURI string
CodeMethodS256 bool
AuthMethodPost bool
AuthMethodPrivateKeyJWT bool
GrantTypeRefreshToken bool
RequestObjectSupported bool
SupportedUILocales []language.Tag
}
@ -94,6 +99,7 @@ type endpoints struct {
Token Endpoint
Introspection Endpoint
Userinfo Endpoint
Revocation Endpoint
EndSession Endpoint
CheckSessionIframe Endpoint
JwksURI Endpoint
@ -148,7 +154,6 @@ type openidProvider struct {
decoder *schema.Decoder
encoder *schema.Encoder
interceptors []HttpInterceptor
retry func(int) (bool, int)
timer <-chan time.Time
}
@ -172,6 +177,10 @@ func (o *openidProvider) UserinfoEndpoint() Endpoint {
return o.endpoints.Userinfo
}
func (o *openidProvider) RevocationEndpoint() Endpoint {
return o.endpoints.Revocation
}
func (o *openidProvider) EndSessionEndpoint() Endpoint {
return o.endpoints.EndSession
}
@ -181,7 +190,7 @@ func (o *openidProvider) KeysEndpoint() Endpoint {
}
func (o *openidProvider) AuthMethodPostSupported() bool {
return true //todo: config
return o.config.AuthMethodPost
}
func (o *openidProvider) CodeMethodS256Supported() bool {
@ -192,6 +201,10 @@ func (o *openidProvider) AuthMethodPrivateKeyJWTSupported() bool {
return o.config.AuthMethodPrivateKeyJWT
}
func (o *openidProvider) TokenEndpointSigningAlgorithmsSupported() []string {
return []string{"RS256"}
}
func (o *openidProvider) GrantTypeRefreshTokenSupported() bool {
return o.config.GrantTypeRefreshToken
}
@ -204,6 +217,30 @@ func (o *openidProvider) GrantTypeJWTAuthorizationSupported() bool {
return true
}
func (o *openidProvider) IntrospectionAuthMethodPrivateKeyJWTSupported() bool {
return true
}
func (o *openidProvider) IntrospectionEndpointSigningAlgorithmsSupported() []string {
return []string{"RS256"}
}
func (o *openidProvider) RevocationAuthMethodPrivateKeyJWTSupported() bool {
return true
}
func (o *openidProvider) RevocationEndpointSigningAlgorithmsSupported() []string {
return []string{"RS256"}
}
func (o *openidProvider) RequestObjectSupported() bool {
return o.config.RequestObjectSupported
}
func (o *openidProvider) RequestObjectSigningAlgorithmsSupported() []string {
return []string{"RS256"}
}
func (o *openidProvider) SupportedUILocales() []language.Tag {
return o.config.SupportedUILocales
}
@ -212,11 +249,11 @@ func (o *openidProvider) Storage() Storage {
return o.storage
}
func (o *openidProvider) Decoder() utils.Decoder {
func (o *openidProvider) Decoder() httphelper.Decoder {
return o.decoder
}
func (o *openidProvider) Encoder() utils.Encoder {
func (o *openidProvider) Encoder() httphelper.Encoder {
return o.encoder
}
@ -332,6 +369,16 @@ func WithCustomUserinfoEndpoint(endpoint Endpoint) Option {
}
}
func WithCustomRevocationEndpoint(endpoint Endpoint) Option {
return func(o *openidProvider) error {
if err := endpoint.Validate(); err != nil {
return err
}
o.endpoints.Revocation = endpoint
return nil
}
}
func WithCustomEndSessionEndpoint(endpoint Endpoint) Option {
return func(o *openidProvider) error {
if err := endpoint.Validate(); err != nil {
@ -352,11 +399,12 @@ func WithCustomKeysEndpoint(endpoint Endpoint) Option {
}
}
func WithCustomEndpoints(auth, token, userInfo, endSession, keys Endpoint) Option {
func WithCustomEndpoints(auth, token, userInfo, revocation, endSession, keys Endpoint) Option {
return func(o *openidProvider) error {
o.endpoints.Authorization = auth
o.endpoints.Token = token
o.endpoints.Userinfo = userInfo
o.endpoints.Revocation = revocation
o.endpoints.EndSession = endSession
o.endpoints.JwksURI = keys
return nil