fix: handle single aud string claim, extract en/decoder interface, comments (#51)

* en/decoding abstraction

* some comments

* fix token validation and error messages

* fix: audience mapping (single aud string)

* fix tests with VerifyIdToken

* reformat imports

* go mod tidy

* Update pkg/oidc/authorization.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update pkg/oidc/authorization.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update pkg/op/authrequest_test.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* fix capitalization

Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
Livio Amstutz 2020-09-07 12:32:35 +02:00 committed by GitHub
parent 822ffb581f
commit abd3b6f521
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 381 additions and 139 deletions

View file

@ -158,14 +158,8 @@ func (v *DefaultVerifier) Verify(ctx context.Context, accessToken, idTokenString
return idToken, nil
}
func (v *DefaultVerifier) now() time.Time {
if v.config.now.IsZero() {
v.config.now = time.Now().UTC().Round(time.Second)
}
return v.config.now
}
//VerifyIDToken: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
//Verify implements the `VerifyIDToken` method of the `Verifier` interface
//according to https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
func (v *DefaultVerifier) VerifyIDToken(ctx context.Context, idTokenString string) (*oidc.IDTokenClaims, error) {
//1. if encrypted --> decrypt
decrypted, err := v.decryptToken(idTokenString)
@ -227,6 +221,13 @@ func (v *DefaultVerifier) VerifyIDToken(ctx context.Context, idTokenString strin
return claims, nil
}
func (v *DefaultVerifier) now() time.Time {
if v.config.now.IsZero() {
v.config.now = time.Now().UTC().Round(time.Second)
}
return v.config.now
}
func (v *DefaultVerifier) parseToken(tokenString string) (*oidc.IDTokenClaims, []byte, error) {
parts := strings.Split(tokenString, ".")
if len(parts) != 3 {
@ -372,7 +373,7 @@ func (v *DefaultVerifier) decryptToken(tokenString string) (string, error) {
}
func (v *DefaultVerifier) verifyAccessToken(accessToken, atHash string, sigAlgorithm jose.SignatureAlgorithm) error {
if accessToken == "" {
if atHash == "" {
return nil
}

3
pkg/rp/mock/generate.go Normal file
View file

@ -0,0 +1,3 @@
package mock
//go:generate mockgen -package mock -destination ./verifier.mock.go github.com/caos/oidc/pkg/rp Verifier

View file

@ -0,0 +1,65 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/caos/oidc/pkg/rp (interfaces: Verifier)
// Package mock is a generated GoMock package.
package mock
import (
context "context"
oidc "github.com/caos/oidc/pkg/oidc"
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockVerifier is a mock of Verifier interface
type MockVerifier struct {
ctrl *gomock.Controller
recorder *MockVerifierMockRecorder
}
// MockVerifierMockRecorder is the mock recorder for MockVerifier
type MockVerifierMockRecorder struct {
mock *MockVerifier
}
// NewMockVerifier creates a new mock instance
func NewMockVerifier(ctrl *gomock.Controller) *MockVerifier {
mock := &MockVerifier{ctrl: ctrl}
mock.recorder = &MockVerifierMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockVerifier) EXPECT() *MockVerifierMockRecorder {
return m.recorder
}
// Verify mocks base method
func (m *MockVerifier) Verify(arg0 context.Context, arg1, arg2 string) (*oidc.IDTokenClaims, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Verify", arg0, arg1, arg2)
ret0, _ := ret[0].(*oidc.IDTokenClaims)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Verify indicates an expected call of Verify
func (mr *MockVerifierMockRecorder) Verify(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Verify", reflect.TypeOf((*MockVerifier)(nil).Verify), arg0, arg1, arg2)
}
// VerifyIDToken mocks base method
func (m *MockVerifier) VerifyIDToken(arg0 context.Context, arg1 string) (*oidc.IDTokenClaims, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "VerifyIDToken", arg0, arg1)
ret0, _ := ret[0].(*oidc.IDTokenClaims)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// VerifyIDToken indicates an expected call of VerifyIDToken
func (mr *MockVerifierMockRecorder) VerifyIDToken(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VerifyIDToken", reflect.TypeOf((*MockVerifier)(nil).VerifyIDToken), arg0, arg1)
}

View file

@ -0,0 +1,37 @@
package mock
import (
"errors"
"testing"
"github.com/golang/mock/gomock"
"github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/rp"
)
func NewVerifier(t *testing.T) rp.Verifier {
return NewMockVerifier(gomock.NewController(t))
}
func NewMockVerifierExpectInvalid(t *testing.T) rp.Verifier {
m := NewVerifier(t)
ExpectVerifyInvalid(m)
return m
}
func ExpectVerifyInvalid(v rp.Verifier) {
mock := v.(*MockVerifier)
mock.EXPECT().VerifyIDToken(gomock.Any(), gomock.Any()).Return(nil, errors.New("invalid"))
}
func NewMockVerifierExpectValid(t *testing.T) rp.Verifier {
m := NewVerifier(t)
ExpectVerifyValid(m)
return m
}
func ExpectVerifyValid(v rp.Verifier) {
mock := v.(*MockVerifier)
mock.EXPECT().VerifyIDToken(gomock.Any(), gomock.Any()).Return(&oidc.IDTokenClaims{Userinfo: oidc.Userinfo{Subject: "id"}}, nil)
}

View file

@ -12,4 +12,7 @@ type Verifier interface {
//Verify checks the access_token and id_token and returns the `id token claims`
Verify(ctx context.Context, accessToken, idTokenString string) (*oidc.IDTokenClaims, error)
//VerifyIDToken checks the id_token only and returns its `id token claims`
VerifyIDToken(ctx context.Context, idTokenString string) (*oidc.IDTokenClaims, error)
}