diff --git a/policy/config.go b/policy/config.go index 9189fdabce..eee988285e 100644 --- a/policy/config.go +++ b/policy/config.go @@ -18,17 +18,10 @@ package policy -import "crypto/tls" - type Config struct { // Directory is the directory where the policy files are stored // policy files include a scope to presentation definition mapping Directory string `koanf:"directory"` // Address is the address of the policy server Address string `koanf:"address"` - - // StrictMode is taken from the server config - StrictMode bool `koanf:"-"` - // TLSConfig is taken from the server config - TLSConfig *tls.Config `koanf:"-"` } diff --git a/policy/local_test.go b/policy/local_test.go index cd195f1d84..dfd738ae3d 100644 --- a/policy/local_test.go +++ b/policy/local_test.go @@ -20,9 +20,9 @@ package policy import ( "context" - "github.com/nuts-foundation/go-did/did" "testing" + "github.com/nuts-foundation/go-did/did" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -49,7 +49,7 @@ func TestStore_LoadFromFile(t *testing.T) { t.Run("returns an error if a presentation definition is invalid", func(t *testing.T) { store := localStore{} - err := store.loadFromFile("test/invalid_definition_mapping.json") + err := store.loadFromFile("test/invalid/invalid_definition_mapping.json") assert.ErrorContains(t, err, "missing properties: \"input_descriptors\"") }) diff --git a/policy/policy.go b/policy/policy.go index a75727a25f..2d5bfab785 100644 --- a/policy/policy.go +++ b/policy/policy.go @@ -21,16 +21,18 @@ package policy import ( "context" "errors" + "fmt" "github.com/nuts-foundation/go-did/did" "github.com/nuts-foundation/nuts-node/core" "github.com/nuts-foundation/nuts-node/pki" "github.com/nuts-foundation/nuts-node/policy/api/v1/client" "github.com/nuts-foundation/nuts-node/vcr/pe" + "net/url" "time" ) // NewRouter creates a new policy backend router that can forward requests to the correct backend -func NewRouter(pkiInstance *pki.PKI) Backend { +func NewRouter(pkiInstance pki.Provider) Backend { return &router{ pkiInstance: pkiInstance, } @@ -39,7 +41,7 @@ func NewRouter(pkiInstance *pki.PKI) Backend { type router struct { backend Backend config Config - pkiInstance *pki.PKI + pkiInstance pki.Provider } func (b *router) Name() string { @@ -47,10 +49,6 @@ func (b *router) Name() string { } func (b *router) Configure(config core.ServerConfig) error { - var err error - b.config.StrictMode = config.Strictmode - b.config.TLSConfig, err = b.pkiInstance.CreateTLSConfig(config.TLS) - // if both directory and address are set, return error if b.config.Directory != "" && b.config.Address != "" { return errors.New("both policy.directory and policy.address are set, please choose one") @@ -58,21 +56,29 @@ func (b *router) Configure(config core.ServerConfig) error { // if address is set use remote backend, otherwise use local backend if b.config.Address != "" { + _, err := url.Parse(b.config.Address) + if err != nil { + return fmt.Errorf("failed to parse policy.address: %w", err) + } + tlsConfig, err := b.pkiInstance.CreateTLSConfig(config.TLS) + if err != nil { + return err + } b.backend = &remote{ address: b.config.Address, // todo client timeout - client: client.NewHTTPClient(config.Strictmode, 30*time.Second, b.config.TLSConfig), + client: client.NewHTTPClient(config.Strictmode, 30*time.Second, tlsConfig), } } if b.config.Directory != "" { backend := &localStore{} if err := backend.loadFromDirectory(b.config.Directory); err != nil { - return err + return fmt.Errorf("failed to load policy from directory: %w", err) } b.backend = backend } - return err + return nil } func (b *router) Config() interface{} { diff --git a/policy/policy_test.go b/policy/policy_test.go new file mode 100644 index 0000000000..cc26c682c1 --- /dev/null +++ b/policy/policy_test.go @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2023 Nuts community + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package policy + +import ( + "context" + "github.com/nuts-foundation/go-did/did" + "github.com/nuts-foundation/nuts-node/pki" + "github.com/nuts-foundation/nuts-node/policy/api/v1/client" + "github.com/nuts-foundation/nuts-node/vcr/pe" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + "testing" + + "github.com/nuts-foundation/nuts-node/core" + "github.com/stretchr/testify/assert" +) + +func TestRouter_Configure(t *testing.T) { + t.Run("ok - directory is set", func(t *testing.T) { + router := router{} + + cfg := router.Config().(*Config) + cfg.Directory = "test" + err := router.Configure(core.ServerConfig{}) + + assert.NoError(t, err) + _, ok := router.backend.(*localStore) + assert.True(t, ok) + }) + t.Run("ok - address is set", func(t *testing.T) { + ctrl := gomock.NewController(t) + pki := pki.NewMockProvider(ctrl) + pki.EXPECT().CreateTLSConfig(gomock.Any()).Return(nil, nil) + router := router{ + pkiInstance: pki, + } + + cfg := router.Config().(*Config) + cfg.Address = "http://localhost:8080" + err := router.Configure(core.ServerConfig{}) + + assert.NoError(t, err) + _, ok := router.backend.(*remote) + assert.True(t, ok) + }) + t.Run("err - both directory and address are set", func(t *testing.T) { + router := router{} + + cfg := router.Config().(*Config) + cfg.Directory = "test" + cfg.Address = "test" + err := router.Configure(core.ServerConfig{}) + + assert.EqualError(t, err, "both policy.directory and policy.address are set, please choose one") + }) + + t.Run("err - directory doesn't exist", func(t *testing.T) { + router := router{} + + cfg := router.Config().(*Config) + cfg.Directory = "unknown" + err := router.Configure(core.ServerConfig{}) + + assert.EqualError(t, err, "failed to load policy from directory: open unknown: no such file or directory") + }) + + t.Run("err - address is invalid", func(t *testing.T) { + router := router{} + + cfg := router.Config().(*Config) + cfg.Address = "://" + err := router.Configure(core.ServerConfig{}) + + assert.EqualError(t, err, "failed to parse policy.address: parse \"://\": missing protocol scheme") + }) +} + +func TestRouter_Name(t *testing.T) { + router := router{} + + assert.Equal(t, ModuleName, router.Name()) +} + +func TestRouterForwarding(t *testing.T) { + ctrl := gomock.NewController(t) + ctx := context.Background() + testDID := did.MustParseDID("did:web:example.com:test") + presentationDefinition := pe.PresentationDefinition{} + router := router{ + backend: NewMockBackend(ctrl), + } + + t.Run("Authorized", func(t *testing.T) { + router.backend.(*MockBackend).EXPECT().Authorized(ctx, gomock.Any()).Return(true, nil) + + result, err := router.Authorized(ctx, client.AuthorizedRequest{}) + + require.NoError(t, err) + assert.True(t, result) + }) + + t.Run("PresentationDefinition", func(t *testing.T) { + router.backend.(*MockBackend).EXPECT().PresentationDefinition(ctx, testDID, "test").Return(&presentationDefinition, nil) + + result, err := router.PresentationDefinition(ctx, testDID, "test") + + require.NoError(t, err) + assert.Equal(t, presentationDefinition, *result) + }) +} diff --git a/policy/test/invalid_definition_mapping.json b/policy/test/invalid/invalid_definition_mapping.json similarity index 100% rename from policy/test/invalid_definition_mapping.json rename to policy/test/invalid/invalid_definition_mapping.json