From 50ab51bb4633fa1e2896f5376c4c3456213dd2b8 Mon Sep 17 00:00:00 2001 From: Livio Amstutz Date: Thu, 28 Jan 2021 08:41:36 +0100 Subject: [PATCH] introspect and client assertion --- example/internal/mock/storage.go | 12 ++++----- pkg/oidc/discovery.go | 43 +++++++++++++++++++------------ pkg/oidc/introspection.go | 9 +++---- pkg/oidc/token_request.go | 16 ++++++++---- pkg/op/client.go | 2 +- pkg/op/config.go | 1 + pkg/op/discovery.go | 12 ++++++--- pkg/op/mock/client.mock.go | 4 +-- pkg/op/mock/configuration.mock.go | 28 ++++++++++++++++++++ pkg/op/mock/storage.mock.go | 28 ++++++++++++++++++++ pkg/op/mock/storage.mock.impl.go | 12 ++++----- pkg/op/op.go | 12 ++++++--- pkg/op/storage.go | 1 + pkg/op/tokenrequest.go | 43 ++++++++++++++++++++++++++----- pkg/op/verifier_jwt_profile.go | 8 +++--- 15 files changed, 171 insertions(+), 60 deletions(-) diff --git a/example/internal/mock/storage.go b/example/internal/mock/storage.go index 8c1ab38..40a1f86 100644 --- a/example/internal/mock/storage.go +++ b/example/internal/mock/storage.go @@ -184,22 +184,22 @@ func (s *AuthStorage) GetClientByClientID(_ context.Context, id string) (op.Clie return nil, errors.New("not found") } var appType op.ApplicationType - var authMethod op.AuthMethod + var authMethod oidc.AuthMethod var accessTokenType op.AccessTokenType var responseTypes []oidc.ResponseType if id == "web" { appType = op.ApplicationTypeWeb - authMethod = op.AuthMethodBasic + authMethod = oidc.AuthMethodBasic accessTokenType = op.AccessTokenTypeBearer responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode} } else if id == "native" { appType = op.ApplicationTypeNative - authMethod = op.AuthMethodNone + authMethod = oidc.AuthMethodNone accessTokenType = op.AccessTokenTypeBearer responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode} } else { appType = op.ApplicationTypeUserAgent - authMethod = op.AuthMethodNone + authMethod = oidc.AuthMethodNone accessTokenType = op.AccessTokenTypeJWT responseTypes = []oidc.ResponseType{oidc.ResponseTypeIDToken, oidc.ResponseTypeIDTokenOnly} } @@ -229,7 +229,7 @@ func (s *AuthStorage) GetPrivateClaimsFromScopes(_ context.Context, _, _ string, type ConfClient struct { applicationType op.ApplicationType - authMethod op.AuthMethod + authMethod oidc.AuthMethod responseTypes []oidc.ResponseType ID string accessTokenType op.AccessTokenType @@ -262,7 +262,7 @@ func (c *ConfClient) ApplicationType() op.ApplicationType { return c.applicationType } -func (c *ConfClient) AuthMethod() op.AuthMethod { +func (c *ConfClient) AuthMethod() oidc.AuthMethod { return c.authMethod } diff --git a/pkg/oidc/discovery.go b/pkg/oidc/discovery.go index 9333ca9..4621a1f 100644 --- a/pkg/oidc/discovery.go +++ b/pkg/oidc/discovery.go @@ -5,21 +5,30 @@ const ( ) type DiscoveryConfiguration struct { - Issuer string `json:"issuer,omitempty"` - AuthorizationEndpoint string `json:"authorization_endpoint,omitempty"` - TokenEndpoint string `json:"token_endpoint,omitempty"` - IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"` - UserinfoEndpoint string `json:"userinfo_endpoint,omitempty"` - EndSessionEndpoint string `json:"end_session_endpoint,omitempty"` - CheckSessionIframe string `json:"check_session_iframe,omitempty"` - JwksURI string `json:"jwks_uri,omitempty"` - ScopesSupported []string `json:"scopes_supported,omitempty"` - ResponseTypesSupported []string `json:"response_types_supported,omitempty"` - ResponseModesSupported []string `json:"response_modes_supported,omitempty"` - GrantTypesSupported []string `json:"grant_types_supported,omitempty"` - SubjectTypesSupported []string `json:"subject_types_supported,omitempty"` - IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"` - TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"` - CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"` - ClaimsSupported []string `json:"claims_supported,omitempty"` + Issuer string `json:"issuer,omitempty"` + AuthorizationEndpoint string `json:"authorization_endpoint,omitempty"` + TokenEndpoint string `json:"token_endpoint,omitempty"` + IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"` + UserinfoEndpoint string `json:"userinfo_endpoint,omitempty"` + EndSessionEndpoint string `json:"end_session_endpoint,omitempty"` + CheckSessionIframe string `json:"check_session_iframe,omitempty"` + JwksURI string `json:"jwks_uri,omitempty"` + ScopesSupported []string `json:"scopes_supported,omitempty"` + ResponseTypesSupported []string `json:"response_types_supported,omitempty"` + ResponseModesSupported []string `json:"response_modes_supported,omitempty"` + GrantTypesSupported []string `json:"grant_types_supported,omitempty"` + SubjectTypesSupported []string `json:"subject_types_supported,omitempty"` + IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"` + TokenEndpointAuthMethodsSupported []AuthMethod `json:"token_endpoint_auth_methods_supported,omitempty"` + CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"` + ClaimsSupported []string `json:"claims_supported,omitempty"` } + +type AuthMethod string + +const ( + AuthMethodBasic AuthMethod = "client_secret_basic" + AuthMethodPost AuthMethod = "client_secret_post" + AuthMethodNone AuthMethod = "none" + AuthMethodPrivateKeyJWT AuthMethod = "private_key_jwt" +) diff --git a/pkg/oidc/introspection.go b/pkg/oidc/introspection.go index 7fa13de..6414bef 100644 --- a/pkg/oidc/introspection.go +++ b/pkg/oidc/introspection.go @@ -207,9 +207,9 @@ func (i *introspectionResponse) MarshalJSON() ([]byte, error) { type Alias introspectionResponse a := &struct { *Alias - Locale interface{} `json:"locale,omitempty"` - UpdatedAt int64 `json:"updated_at,omitempty"` - PreferredUsername string `json:"username,omitempty"` + Locale interface{} `json:"locale,omitempty"` + UpdatedAt int64 `json:"updated_at,omitempty"` + Username string `json:"username,omitempty"` }{ Alias: (*Alias)(i), } @@ -219,8 +219,7 @@ func (i *introspectionResponse) MarshalJSON() ([]byte, error) { if !time.Time(i.UpdatedAt).IsZero() { a.UpdatedAt = time.Time(i.UpdatedAt).Unix() } - a.PreferredUsername = i.PreferredUsername - i.PreferredUsername = "" + a.Username = i.PreferredUsername b, err := json.Marshal(a) if err != nil { diff --git a/pkg/oidc/token_request.go b/pkg/oidc/token_request.go index 1312b18..0c5b70b 100644 --- a/pkg/oidc/token_request.go +++ b/pkg/oidc/token_request.go @@ -15,6 +15,10 @@ const ( //GrantTypeTokenExchange defines the grant_type `urn:ietf:params:oauth:grant-type:token-exchange` used for the OAuth Token Exchange Grant GrantTypeTokenExchange GrantType = "urn:ietf:params:oauth:grant-type:token-exchange" + + //ClientAssertionTypeJWTAssertion defines the client_assertion_type `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` + //used for the OAuth JWT Profile Client Authentication + ClientAssertionTypeJWTAssertion = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" ) type GrantType string @@ -27,11 +31,13 @@ type TokenRequest interface { type TokenRequestType GrantType type AccessTokenRequest struct { - Code string `schema:"code"` - RedirectURI string `schema:"redirect_uri"` - ClientID string `schema:"client_id"` - ClientSecret string `schema:"client_secret"` - CodeVerifier string `schema:"code_verifier"` + Code string `schema:"code"` + RedirectURI string `schema:"redirect_uri"` + ClientID string `schema:"client_id"` + ClientSecret string `schema:"client_secret"` + CodeVerifier string `schema:"code_verifier"` + ClientAssertion string `schema:"client_assertion"` + ClientAssertionType string `schema:"client_assertion_type"` } func (a *AccessTokenRequest) GrantType() GrantType { diff --git a/pkg/op/client.go b/pkg/op/client.go index 6d0891c..79715b0 100644 --- a/pkg/op/client.go +++ b/pkg/op/client.go @@ -28,7 +28,7 @@ type Client interface { RedirectURIs() []string PostLogoutRedirectURIs() []string ApplicationType() ApplicationType - AuthMethod() AuthMethod + AuthMethod() oidc.AuthMethod ResponseTypes() []oidc.ResponseType LoginURL(string) string AccessTokenType() AccessTokenType diff --git a/pkg/op/config.go b/pkg/op/config.go index f4fbb97..7cb522a 100644 --- a/pkg/op/config.go +++ b/pkg/op/config.go @@ -20,6 +20,7 @@ type Configuration interface { AuthMethodPostSupported() bool CodeMethodS256Supported() bool + AuthMethodPrivateKeyJWTSupported() bool GrantTypeTokenExchangeSupported() bool GrantTypeJWTAuthorizationSupported() bool } diff --git a/pkg/op/discovery.go b/pkg/op/discovery.go index 3bec79b..8708fbb 100644 --- a/pkg/op/discovery.go +++ b/pkg/op/discovery.go @@ -108,12 +108,16 @@ func SubjectTypes(c Configuration) []string { return []string{"public"} //TODO: config } -func AuthMethods(c Configuration) []string { - authMethods := []string{ - string(AuthMethodBasic), +func AuthMethods(c Configuration) []oidc.AuthMethod { + authMethods := []oidc.AuthMethod{ + oidc.AuthMethodNone, + oidc.AuthMethodBasic, } if c.AuthMethodPostSupported() { - authMethods = append(authMethods, string(AuthMethodPost)) + authMethods = append(authMethods, oidc.AuthMethodPost) + } + if c.AuthMethodPrivateKeyJWTSupported() { + authMethods = append(authMethods, oidc.AuthMethodPrivateKeyJWT) } return authMethods } diff --git a/pkg/op/mock/client.mock.go b/pkg/op/mock/client.mock.go index 1a15624..9d5fe41 100644 --- a/pkg/op/mock/client.mock.go +++ b/pkg/op/mock/client.mock.go @@ -64,10 +64,10 @@ func (mr *MockClientMockRecorder) ApplicationType() *gomock.Call { } // AuthMethod mocks base method -func (m *MockClient) AuthMethod() op.AuthMethod { +func (m *MockClient) AuthMethod() oidc.AuthMethod { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AuthMethod") - ret0, _ := ret[0].(op.AuthMethod) + ret0, _ := ret[0].(oidc.AuthMethod) return ret0 } diff --git a/pkg/op/mock/configuration.mock.go b/pkg/op/mock/configuration.mock.go index ece747c..4f83f35 100644 --- a/pkg/op/mock/configuration.mock.go +++ b/pkg/op/mock/configuration.mock.go @@ -47,6 +47,20 @@ func (mr *MockConfigurationMockRecorder) AuthMethodPostSupported() *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthMethodPostSupported", reflect.TypeOf((*MockConfiguration)(nil).AuthMethodPostSupported)) } +// AuthMethodPrivateKeyJWTSupported mocks base method +func (m *MockConfiguration) AuthMethodPrivateKeyJWTSupported() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AuthMethodPrivateKeyJWTSupported") + ret0, _ := ret[0].(bool) + return ret0 +} + +// AuthMethodPrivateKeyJWTSupported indicates an expected call of AuthMethodPrivateKeyJWTSupported +func (mr *MockConfigurationMockRecorder) AuthMethodPrivateKeyJWTSupported() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthMethodPrivateKeyJWTSupported", reflect.TypeOf((*MockConfiguration)(nil).AuthMethodPrivateKeyJWTSupported)) +} + // AuthorizationEndpoint mocks base method func (m *MockConfiguration) AuthorizationEndpoint() op.Endpoint { m.ctrl.T.Helper() @@ -117,6 +131,20 @@ func (mr *MockConfigurationMockRecorder) GrantTypeTokenExchangeSupported() *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypeTokenExchangeSupported", reflect.TypeOf((*MockConfiguration)(nil).GrantTypeTokenExchangeSupported)) } +// IntrospectionEndpoint mocks base method +func (m *MockConfiguration) IntrospectionEndpoint() op.Endpoint { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IntrospectionEndpoint") + ret0, _ := ret[0].(op.Endpoint) + return ret0 +} + +// IntrospectionEndpoint indicates an expected call of IntrospectionEndpoint +func (mr *MockConfigurationMockRecorder) IntrospectionEndpoint() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntrospectionEndpoint", reflect.TypeOf((*MockConfiguration)(nil).IntrospectionEndpoint)) +} + // Issuer mocks base method func (m *MockConfiguration) Issuer() string { m.ctrl.T.Helper() diff --git a/pkg/op/mock/storage.mock.go b/pkg/op/mock/storage.mock.go index 9e4963a..b9adcec 100644 --- a/pkg/op/mock/storage.mock.go +++ b/pkg/op/mock/storage.mock.go @@ -270,6 +270,34 @@ func (mr *MockStorageMockRecorder) SaveNewKeyPair(arg0 interface{}) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveNewKeyPair", reflect.TypeOf((*MockStorage)(nil).SaveNewKeyPair), arg0) } +// SetUserinfoFromScopes mocks base method +func (m *MockStorage) SetUserinfoFromScopes(arg0 context.Context, arg1 oidc.UserInfoSetter, arg2, arg3 string, arg4 []string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetUserinfoFromScopes", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetUserinfoFromScopes indicates an expected call of SetUserinfoFromScopes +func (mr *MockStorageMockRecorder) SetUserinfoFromScopes(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUserinfoFromScopes", reflect.TypeOf((*MockStorage)(nil).SetUserinfoFromScopes), arg0, arg1, arg2, arg3, arg4) +} + +// SetUserinfoFromToken mocks base method +func (m *MockStorage) SetUserinfoFromToken(arg0 context.Context, arg1 oidc.UserInfoSetter, arg2, arg3, arg4 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetUserinfoFromToken", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetUserinfoFromToken indicates an expected call of SetUserinfoFromToken +func (mr *MockStorageMockRecorder) SetUserinfoFromToken(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUserinfoFromToken", reflect.TypeOf((*MockStorage)(nil).SetUserinfoFromToken), arg0, arg1, arg2, arg3, arg4) +} + // TerminateSession mocks base method func (m *MockStorage) TerminateSession(arg0 context.Context, arg1, arg2 string) error { m.ctrl.T.Helper() diff --git a/pkg/op/mock/storage.mock.impl.go b/pkg/op/mock/storage.mock.impl.go index 29d0d15..2788c39 100644 --- a/pkg/op/mock/storage.mock.impl.go +++ b/pkg/op/mock/storage.mock.impl.go @@ -65,23 +65,23 @@ func ExpectValidClientID(s op.Storage) { mockS.EXPECT().GetClientByClientID(gomock.Any(), gomock.Any()).DoAndReturn( func(_ context.Context, id string) (op.Client, error) { var appType op.ApplicationType - var authMethod op.AuthMethod + var authMethod oidc.AuthMethod var accessTokenType op.AccessTokenType var responseTypes []oidc.ResponseType switch id { case "web_client": appType = op.ApplicationTypeWeb - authMethod = op.AuthMethodBasic + authMethod = oidc.AuthMethodBasic accessTokenType = op.AccessTokenTypeBearer responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode} case "native_client": appType = op.ApplicationTypeNative - authMethod = op.AuthMethodNone + authMethod = oidc.AuthMethodNone accessTokenType = op.AccessTokenTypeBearer responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode} case "useragent_client": appType = op.ApplicationTypeUserAgent - authMethod = op.AuthMethodBasic + authMethod = oidc.AuthMethodBasic accessTokenType = op.AccessTokenTypeJWT responseTypes = []oidc.ResponseType{oidc.ResponseTypeIDToken} } @@ -119,7 +119,7 @@ func ExpectSigningKey(s op.Storage) { type ConfClient struct { id string appType op.ApplicationType - authMethod op.AuthMethod + authMethod oidc.AuthMethod accessTokenType op.AccessTokenType responseTypes []oidc.ResponseType devMode bool @@ -145,7 +145,7 @@ func (c *ConfClient) ApplicationType() op.ApplicationType { return c.appType } -func (c *ConfClient) AuthMethod() op.AuthMethod { +func (c *ConfClient) AuthMethod() oidc.AuthMethod { return c.authMethod } diff --git a/pkg/op/op.go b/pkg/op/op.go index 76d5fcc..fa32a23 100644 --- a/pkg/op/op.go +++ b/pkg/op/op.go @@ -26,9 +26,10 @@ const ( defaultEndSessionEndpoint = "end_session" defaultKeysEndpoint = "keys" - AuthMethodBasic AuthMethod = "client_secret_basic" - AuthMethodPost AuthMethod = "client_secret_post" - AuthMethodNone AuthMethod = "none" + AuthMethodBasic AuthMethod = "client_secret_basic" + AuthMethodPost AuthMethod = "client_secret_post" + AuthMethodNone AuthMethod = "none" + AuthMethodPrivateKeyJWT AuthMethod = "private_key_jwt" CodeMethodS256 = "S256" ) @@ -90,6 +91,7 @@ type Config struct { CryptoKey [32]byte DefaultLogoutRedirectURI string CodeMethodS256 bool + AuthMethodPrivateKeyJWT bool } type endpoints struct { @@ -191,6 +193,10 @@ func (o *openidProvider) CodeMethodS256Supported() bool { return o.config.CodeMethodS256 } +func (o *openidProvider) AuthMethodPrivateKeyJWTSupported() bool { + return o.config.AuthMethodPrivateKeyJWT +} + func (o *openidProvider) GrantTypeTokenExchangeSupported() bool { return false } diff --git a/pkg/op/storage.go b/pkg/op/storage.go index 0a0cec2..b5f1dfe 100644 --- a/pkg/op/storage.go +++ b/pkg/op/storage.go @@ -32,6 +32,7 @@ type OPStorage interface { SetUserinfoFromToken(ctx context.Context, userinfo oidc.UserInfoSetter, tokenID, subject, origin string) error GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (map[string]interface{}, error) GetKeyByIDAndUserID(ctx context.Context, keyID, userID string) (*jose.JSONWebKey, error) + //ValidateJWTProfileScopes(ctx context.Context, userID string, scope oidc.Scopes) (oidc.Scopes, error) //deprecated: use GetUserinfoFromScopes instead GetUserinfoFromScopes(ctx context.Context, userID, clientID string, scopes []string) (oidc.UserInfo, error) diff --git a/pkg/op/tokenrequest.go b/pkg/op/tokenrequest.go index c3860ff..0e295a3 100644 --- a/pkg/op/tokenrequest.go +++ b/pkg/op/tokenrequest.go @@ -18,6 +18,7 @@ type Exchanger interface { Signer() Signer Crypto() Crypto AuthMethodPostSupported() bool + AuthMethodPrivateKeyJWTSupported() bool GrantTypeTokenExchangeSupported() bool GrantTypeJWTAuthorizationSupported() bool } @@ -112,18 +113,30 @@ func ValidateAccessTokenRequest(ctx context.Context, tokenReq *oidc.AccessTokenR } func AuthorizeClient(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (AuthRequest, Client, error) { + if tokenReq.ClientAssertionType == oidc.ClientAssertionTypeJWTAssertion { + jwtExchanger, ok := exchanger.(JWTAuthorizationGrantExchanger) + if !ok || !exchanger.AuthMethodPrivateKeyJWTSupported() { + return nil, nil, errors.New("auth_method private_key_jwt not supported") + } + return AuthorizePrivateJWTKey(ctx, tokenReq, jwtExchanger) + } client, err := exchanger.Storage().GetClientByClientID(ctx, tokenReq.ClientID) if err != nil { return nil, nil, err } - if client.AuthMethod() == AuthMethodNone { + if client.AuthMethod() == oidc.AuthMethodNone { authReq, err := AuthorizeCodeChallenge(ctx, tokenReq, exchanger) return authReq, client, err } - if client.AuthMethod() == AuthMethodPost && !exchanger.AuthMethodPostSupported() { + if client.AuthMethod() == oidc.AuthMethodPost && !exchanger.AuthMethodPostSupported() { return nil, nil, errors.New("auth_method post not supported") } - err = AuthorizeClientIDSecret(ctx, tokenReq.ClientID, tokenReq.ClientSecret, exchanger.Storage()) + authReq, err := AuthorizeClientIDSecret(ctx, tokenReq.ClientID, tokenReq.ClientSecret, tokenReq.Code, exchanger.Storage()) + return authReq, client, err +} + +func AuthorizePrivateJWTKey(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger JWTAuthorizationGrantExchanger) (AuthRequest, Client, error) { + jwtReq, err := VerifyJWTAssertion(ctx, tokenReq.ClientAssertion, exchanger.JWTProfileVerifier()) if err != nil { return nil, nil, err } @@ -131,11 +144,26 @@ func AuthorizeClient(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exc if err != nil { return nil, nil, ErrInvalidRequest("invalid code") } + client, err := exchanger.Storage().GetClientByClientID(ctx, jwtReq.Issuer) + if err != nil { + return nil, nil, err + } + if client.AuthMethod() != oidc.AuthMethodPrivateKeyJWT { + return nil, nil, ErrInvalidRequest("invalid_client") + } return authReq, client, nil } -func AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string, storage OPStorage) error { - return storage.AuthorizeClientIDSecret(ctx, clientID, clientSecret) +func AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret, code string, storage Storage) (AuthRequest, error) { + err := storage.AuthorizeClientIDSecret(ctx, clientID, clientSecret) + if err != nil { + return nil, err + } + authReq, err := storage.AuthRequestByCode(ctx, code) + if err != nil { + return nil, ErrInvalidRequest("invalid code") + } + return authReq, nil } func AuthorizeCodeChallenge(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (AuthRequest, error) { @@ -158,12 +186,15 @@ func JWTProfile(w http.ResponseWriter, r *http.Request, exchanger JWTAuthorizati RequestError(w, r, err) } - tokenRequest, err := VerifyJWTAssertion(r.Context(), profileRequest, exchanger.JWTProfileVerifier()) + tokenRequest, err := VerifyJWTAssertion(r.Context(), profileRequest.Assertion, exchanger.JWTProfileVerifier()) if err != nil { RequestError(w, r, err) return } + //TODO: filter scopes + tokenRequest.Scopes = profileRequest.Scope + resp, err := CreateJWTTokenResponse(r.Context(), tokenRequest, exchanger) if err != nil { RequestError(w, r, err) diff --git a/pkg/op/verifier_jwt_profile.go b/pkg/op/verifier_jwt_profile.go index 8a31253..b30bdc5 100644 --- a/pkg/op/verifier_jwt_profile.go +++ b/pkg/op/verifier_jwt_profile.go @@ -8,7 +8,6 @@ import ( "gopkg.in/square/go-jose.v2" "github.com/caos/oidc/pkg/oidc" - "github.com/caos/oidc/pkg/oidc/grants/tokenexchange" ) type JWTProfileVerifier interface { @@ -48,9 +47,9 @@ func (v *jwtProfileVerifier) Offset() time.Duration { return v.offset } -func VerifyJWTAssertion(ctx context.Context, profileRequest *tokenexchange.JWTProfileRequest, v JWTProfileVerifier) (*oidc.JWTTokenRequest, error) { +func VerifyJWTAssertion(ctx context.Context, assertion string, v JWTProfileVerifier) (*oidc.JWTTokenRequest, error) { request := new(oidc.JWTTokenRequest) - payload, err := oidc.ParseToken(profileRequest.Assertion, request) + payload, err := oidc.ParseToken(assertion, request) if err != nil { return nil, err } @@ -73,10 +72,9 @@ func VerifyJWTAssertion(ctx context.Context, profileRequest *tokenexchange.JWTPr keySet := &jwtProfileKeySet{v.Storage(), request.Subject} - if err = oidc.CheckSignature(ctx, profileRequest.Assertion, payload, request, nil, keySet); err != nil { + if err = oidc.CheckSignature(ctx, assertion, payload, request, nil, keySet); err != nil { return nil, err } - request.Scopes = profileRequest.Scope return request, nil }