From 406153a4f40bd8700d78a7b5e158a15189045f3b Mon Sep 17 00:00:00 2001 From: Hugo Hromic Date: Fri, 23 Jun 2023 08:19:58 +0100 Subject: [PATCH] fix(client/rs): do not error when issuer discovery has no introspection endpoint (#414) * chore(tests): add basic unit tests for `pkg/client/rs/resource_server.go` * fix: do not error when issuer discovery has no introspection endpoint --- pkg/client/rs/resource_server.go | 15 +- pkg/client/rs/resource_server_test.go | 219 ++++++++++++++++++++++++++ 2 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 pkg/client/rs/resource_server_test.go diff --git a/pkg/client/rs/resource_server.go b/pkg/client/rs/resource_server.go index 4e0353c..c641940 100644 --- a/pkg/client/rs/resource_server.go +++ b/pkg/client/rs/resource_server.go @@ -77,11 +77,15 @@ func newResourceServer(issuer string, authorizer func() (interface{}, error), op if err != nil { return nil, err } - rs.tokenURL = config.TokenEndpoint - rs.introspectURL = config.IntrospectionEndpoint + if rs.tokenURL == "" { + rs.tokenURL = config.TokenEndpoint + } + if rs.introspectURL == "" { + rs.introspectURL = config.IntrospectionEndpoint + } } - if rs.introspectURL == "" || rs.tokenURL == "" { - return nil, errors.New("introspectURL and/or tokenURL is empty: please provide with either `WithStaticEndpoints` or a discovery url") + if rs.tokenURL == "" { + return nil, errors.New("tokenURL is empty: please provide with either `WithStaticEndpoints` or a discovery url") } rs.authFn = authorizer return rs, nil @@ -113,6 +117,9 @@ func WithStaticEndpoints(tokenURL, introspectURL string) Option { } func Introspect(ctx context.Context, rp ResourceServer, token string) (*oidc.IntrospectionResponse, error) { + if rp.IntrospectionURL() == "" { + return nil, errors.New("resource server: introspection URL is empty") + } authFn, err := rp.AuthFn() if err != nil { return nil, err diff --git a/pkg/client/rs/resource_server_test.go b/pkg/client/rs/resource_server_test.go new file mode 100644 index 0000000..b5fb496 --- /dev/null +++ b/pkg/client/rs/resource_server_test.go @@ -0,0 +1,219 @@ +package rs + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewResourceServer(t *testing.T) { + type args struct { + issuer string + authorizer func() (interface{}, error) + options []Option + } + type wantFields struct { + issuer string + tokenURL string + introspectURL string + authFn func() (interface{}, error) + } + tests := []struct { + name string + args args + wantFields *wantFields + wantErr bool + }{ + { + name: "spotify-full-discovery", + args: args{ + issuer: "https://accounts.spotify.com", + authorizer: nil, + options: []Option{}, + }, + wantFields: &wantFields{ + issuer: "https://accounts.spotify.com", + tokenURL: "https://accounts.spotify.com/api/token", + introspectURL: "", + authFn: nil, + }, + wantErr: false, + }, + { + name: "spotify-with-static-tokenurl", + args: args{ + issuer: "https://accounts.spotify.com", + authorizer: nil, + options: []Option{ + WithStaticEndpoints( + "https://some.host/token-url", + "", + ), + }, + }, + wantFields: &wantFields{ + issuer: "https://accounts.spotify.com", + tokenURL: "https://some.host/token-url", + introspectURL: "", + authFn: nil, + }, + wantErr: false, + }, + { + name: "spotify-with-static-introspecturl", + args: args{ + issuer: "https://accounts.spotify.com", + authorizer: nil, + options: []Option{ + WithStaticEndpoints( + "", + "https://some.host/instrospect-url", + ), + }, + }, + wantFields: &wantFields{ + issuer: "https://accounts.spotify.com", + tokenURL: "https://accounts.spotify.com/api/token", + introspectURL: "https://some.host/instrospect-url", + authFn: nil, + }, + wantErr: false, + }, + { + name: "spotify-with-all-static-endpoints", + args: args{ + issuer: "https://accounts.spotify.com", + authorizer: nil, + options: []Option{ + WithStaticEndpoints( + "https://some.host/token-url", + "https://some.host/instrospect-url", + ), + }, + }, + wantFields: &wantFields{ + issuer: "https://accounts.spotify.com", + tokenURL: "https://some.host/token-url", + introspectURL: "https://some.host/instrospect-url", + authFn: nil, + }, + wantErr: false, + }, + { + name: "bad-discovery", + args: args{ + issuer: "https://127.0.0.1:65535", + authorizer: nil, + options: []Option{}, + }, + wantFields: nil, + wantErr: true, + }, + { + name: "bad-discovery-with-static-tokenurl", + args: args{ + issuer: "https://127.0.0.1:65535", + authorizer: nil, + options: []Option{ + WithStaticEndpoints( + "https://some.host/token-url", + "", + ), + }, + }, + wantFields: nil, + wantErr: true, + }, + { + name: "bad-discovery-with-static-introspecturl", + args: args{ + issuer: "https://127.0.0.1:65535", + authorizer: nil, + options: []Option{ + WithStaticEndpoints( + "", + "https://some.host/instrospect-url", + ), + }, + }, + wantFields: nil, + wantErr: true, + }, + { + name: "bad-discovery-with-all-static-endpoints", + args: args{ + issuer: "https://127.0.0.1:65535", + authorizer: nil, + options: []Option{ + WithStaticEndpoints( + "https://some.host/token-url", + "https://some.host/instrospect-url", + ), + }, + }, + wantFields: &wantFields{ + issuer: "https://127.0.0.1:65535", + tokenURL: "https://some.host/token-url", + introspectURL: "https://some.host/instrospect-url", + authFn: nil, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := newResourceServer(tt.args.issuer, tt.args.authorizer, tt.args.options...) + if tt.wantErr { + assert.Error(t, err) + return + } + require.NoError(t, err) + if tt.wantFields == nil { + return + } + assert.Equal(t, tt.wantFields.issuer, got.issuer) + assert.Equal(t, tt.wantFields.tokenURL, got.tokenURL) + assert.Equal(t, tt.wantFields.introspectURL, got.introspectURL) + }) + } +} + +func TestIntrospect(t *testing.T) { + type args struct { + ctx context.Context + rp ResourceServer + token string + } + rp, err := newResourceServer( + "https://accounts.spotify.com", + nil, + ) + require.NoError(t, err) + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "missing-introspect-url", + args: args{ + ctx: nil, + rp: rp, + token: "my-token", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := Introspect(tt.args.ctx, tt.args.rp, tt.args.token) + if tt.wantErr { + assert.Error(t, err) + return + } + require.NoError(t, err) + }) + } +}