diff --git a/cmd/command/transcribe.go b/cmd/command/transcribe.go index 8eec70e0..78d73e4b 100644 --- a/cmd/command/transcribe.go +++ b/cmd/command/transcribe.go @@ -174,8 +174,12 @@ func applyAuth(cfg *gateway.Config, auth *options.Auth) { return } if strings.TrimSpace(auth.RSA) != "" { - cfg.JWTValidator = &verifier.Config{RSA: getScyResources(auth.RSA)} - cfg.JwtSigner = &signer.Config{RSA: getScyResource(strings.Split(auth.RSA, ";")[0])} + publicRes, privateRes := splitAuthResourcePair(auth.RSA) + cfg.JWTValidator = &verifier.Config{RSA: getScyResources(publicRes)} + if privateRes == "" { + privateRes = publicRes + } + cfg.JwtSigner = &signer.Config{RSA: getScyResource(privateRes)} } if strings.TrimSpace(auth.HMAC) != "" { cfg.JWTValidator = &verifier.Config{HMAC: getScyResource(auth.HMAC)} @@ -195,7 +199,7 @@ func getScyResource(location string) *scy.Resource { func getScyResources(location string) []*scy.Resource { var result []*scy.Resource - for _, item := range strings.Split(location, "-") { + for _, item := range strings.Split(location, ";") { item = strings.TrimSpace(item) if item == "" { continue @@ -205,6 +209,19 @@ func getScyResources(location string) []*scy.Resource { return result } +func splitAuthResourcePair(location string) (string, string) { + location = strings.TrimSpace(location) + if location == "" { + return "", "" + } + parts := strings.SplitN(location, ";", 2) + publicRes := strings.TrimSpace(parts[0]) + if len(parts) == 1 { + return publicRes, "" + } + return publicRes, strings.TrimSpace(parts[1]) +} + func existingBootstrapSources(ctx context.Context, fs afs.Service, cfgURL string) []string { data, err := fs.DownloadWithURL(ctx, cfgURL) if err != nil { diff --git a/cmd/command/transcribe_auth_test.go b/cmd/command/transcribe_auth_test.go new file mode 100644 index 00000000..92e2afee --- /dev/null +++ b/cmd/command/transcribe_auth_test.go @@ -0,0 +1,36 @@ +package command + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/viant/datly/cmd/options" + "github.com/viant/datly/gateway" +) + +func TestApplyAuth_RSAUsesSemicolonSeparatedKeys(t *testing.T) { + cfg := &gateway.Config{} + auth := &options.Auth{ + RSA: "./github.com/viant-internal/public.pem|pubKey;./github.com/viant-internal/private.pem|privKey", + } + + applyAuth(cfg, auth) + + require.NotNil(t, cfg.JWTValidator) + require.Len(t, cfg.JWTValidator.RSA, 1) + assert.True(t, strings.HasSuffix(cfg.JWTValidator.RSA[0].URL, "/github.com/viant-internal/public.pem"), cfg.JWTValidator.RSA[0].URL) + assert.Equal(t, "pubKey", cfg.JWTValidator.RSA[0].Key) + require.NotNil(t, cfg.JwtSigner) + require.NotNil(t, cfg.JwtSigner.RSA) + assert.True(t, strings.HasSuffix(cfg.JwtSigner.RSA.URL, "/github.com/viant-internal/private.pem"), cfg.JwtSigner.RSA.URL) + assert.Equal(t, "privKey", cfg.JwtSigner.RSA.Key) +} + +func TestGetScyResources_PreservesHyphenatedPaths(t *testing.T) { + resources := getScyResources("./github.com/viant-internal/public.pem|pubKey") + require.Len(t, resources, 1) + assert.True(t, strings.HasSuffix(resources[0].URL, "/github.com/viant-internal/public.pem"), resources[0].URL) + assert.Equal(t, "pubKey", resources[0].Key) +} diff --git a/internal/translator/oauth.go b/internal/translator/oauth.go index aa512075..04e3abc9 100644 --- a/internal/translator/oauth.go +++ b/internal/translator/oauth.go @@ -88,7 +88,7 @@ func getScyResource(location string) *scy.Resource { func getScyResources(location string) []*scy.Resource { var result []*scy.Resource - for _, location := range strings.Split(location, "-") { + for _, location := range strings.Split(location, ";") { if strings.TrimSpace(location) == "" { continue } diff --git a/internal/translator/oauth_test.go b/internal/translator/oauth_test.go new file mode 100644 index 00000000..3d66ba82 --- /dev/null +++ b/internal/translator/oauth_test.go @@ -0,0 +1,42 @@ +package translator + +import ( + "context" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/viant/datly/cmd/options" + "github.com/viant/datly/gateway" + "github.com/viant/datly/gateway/runtime/standalone" +) + +func TestConfig_updateAuth_RSAUsesSemicolonSeparatedKeys(t *testing.T) { + cfg := &Config{ + repository: &options.Repository{ + Auth: options.Auth{ + RSA: "./github.com/viant-internal/public.pem|pubKey;./github.com/viant-internal/private.pem|privKey", + }, + }, + Config: &standalone.Config{Config: &gateway.Config{}}, + } + + err := cfg.updateAuth(context.Background()) + require.NoError(t, err) + require.NotNil(t, cfg.Config.Config.JWTValidator) + require.Len(t, cfg.Config.Config.JWTValidator.RSA, 1) + assert.True(t, strings.HasSuffix(cfg.Config.Config.JWTValidator.RSA[0].URL, "/github.com/viant-internal/public.pem"), cfg.Config.Config.JWTValidator.RSA[0].URL) + assert.Equal(t, "pubKey", cfg.Config.Config.JWTValidator.RSA[0].Key) + require.NotNil(t, cfg.Config.Config.JwtSigner) + require.NotNil(t, cfg.Config.Config.JwtSigner.RSA) + assert.True(t, strings.HasSuffix(cfg.Config.Config.JwtSigner.RSA.URL, "/github.com/viant-internal/private.pem"), cfg.Config.Config.JwtSigner.RSA.URL) + assert.Equal(t, "privKey", cfg.Config.Config.JwtSigner.RSA.Key) +} + +func TestGetScyResources_PreservesHyphenatedPaths(t *testing.T) { + resources := getScyResources("./github.com/viant-internal/public.pem|pubKey") + require.Len(t, resources, 1) + assert.True(t, strings.HasSuffix(resources[0].URL, "/github.com/viant-internal/public.pem"), resources[0].URL) + assert.Equal(t, "pubKey", resources[0].Key) +}