diff --git a/pkg/cmd/grafana-cli/runner/wire.go b/pkg/cmd/grafana-cli/runner/wire.go index d23f46d6369..f95db61c9a6 100644 --- a/pkg/cmd/grafana-cli/runner/wire.go +++ b/pkg/cmd/grafana-cli/runner/wire.go @@ -12,6 +12,8 @@ import ( "github.com/grafana/grafana/pkg/infra/localcache" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/infra/usagestats" + "github.com/grafana/grafana/pkg/services/encryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/hooks" "github.com/grafana/grafana/pkg/services/secrets" @@ -34,6 +36,8 @@ var wireSet = wire.NewSet( sqlstore.ProvideService, wire.InterfaceValue(new(usagestats.Service), noOpUsageStats{}), wire.InterfaceValue(new(routing.RouteRegister), noOpRouteRegister{}), + encryptionservice.ProvideEncryptionService, + wire.Bind(new(encryption.Internal), new(*encryptionservice.Service)), secretsDatabase.ProvideSecretsStore, wire.Bind(new(secrets.Store), new(*secretsDatabase.SecretsStoreImpl)), secretsManager.ProvideSecretsService, diff --git a/pkg/cmd/grafana-cli/runner/wireexts_oss.go b/pkg/cmd/grafana-cli/runner/wireexts_oss.go index 79eb840185e..2941d1c4de8 100644 --- a/pkg/cmd/grafana-cli/runner/wireexts_oss.go +++ b/pkg/cmd/grafana-cli/runner/wireexts_oss.go @@ -8,7 +8,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/registry" "github.com/grafana/grafana/pkg/services/encryption" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionprovider "github.com/grafana/grafana/pkg/services/encryption/provider" "github.com/grafana/grafana/pkg/services/kmsproviders" "github.com/grafana/grafana/pkg/services/kmsproviders/osskmsproviders" "github.com/grafana/grafana/pkg/services/licensing" @@ -26,6 +26,6 @@ var wireExtsSet = wire.NewSet( wire.Bind(new(setting.Provider), new(*setting.OSSImpl)), osskmsproviders.ProvideService, wire.Bind(new(kmsproviders.Service), new(osskmsproviders.Service)), - ossencryption.ProvideService, - wire.Bind(new(encryption.Internal), new(*ossencryption.Service)), + encryptionprovider.ProvideEncryptionProvider, + wire.Bind(new(encryption.Provider), new(encryptionprovider.Provider)), ) diff --git a/pkg/server/wire.go b/pkg/server/wire.go index b811979a99b..592e95c152a 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -59,6 +59,8 @@ import ( "github.com/grafana/grafana/pkg/services/datasourceproxy" "github.com/grafana/grafana/pkg/services/datasources" datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service" + "github.com/grafana/grafana/pkg/services/encryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/export" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" @@ -231,6 +233,8 @@ var wireBasicSet = wire.NewSet( graphite.ProvideService, prometheus.ProvideService, elasticsearch.ProvideService, + encryptionservice.ProvideEncryptionService, + wire.Bind(new(encryption.Internal), new(*encryptionservice.Service)), secretsManager.ProvideSecretsService, wire.Bind(new(secrets.Service), new(*secretsManager.SecretsService)), secretsDatabase.ProvideSecretsStore, diff --git a/pkg/server/wireexts_oss.go b/pkg/server/wireexts_oss.go index 3551ae5b563..8f7fe3fb088 100644 --- a/pkg/server/wireexts_oss.go +++ b/pkg/server/wireexts_oss.go @@ -21,7 +21,7 @@ import ( "github.com/grafana/grafana/pkg/services/datasources/permissions" datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service" "github.com/grafana/grafana/pkg/services/encryption" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionprovider "github.com/grafana/grafana/pkg/services/encryption/provider" "github.com/grafana/grafana/pkg/services/kmsproviders" "github.com/grafana/grafana/pkg/services/kmsproviders/osskmsproviders" "github.com/grafana/grafana/pkg/services/ldap" @@ -63,8 +63,8 @@ var wireExtsBasicSet = wire.NewSet( wire.Bind(new(registry.DatabaseMigrator), new(*migrations.OSSMigrations)), authinfoservice.ProvideOSSUserProtectionService, wire.Bind(new(login.UserProtectionService), new(*authinfoservice.OSSUserProtectionImpl)), - ossencryption.ProvideService, - wire.Bind(new(encryption.Internal), new(*ossencryption.Service)), + encryptionprovider.ProvideEncryptionProvider, + wire.Bind(new(encryption.Provider), new(encryptionprovider.Provider)), filters.ProvideOSSSearchUserFilter, wire.Bind(new(models.SearchUserFilter), new(*filters.OSSSearchUserFilter)), searchusers.ProvideUsersService, diff --git a/pkg/services/alerting/engine_integration_test.go b/pkg/services/alerting/engine_integration_test.go index 47e28e94b1d..2ef21f1bf22 100644 --- a/pkg/services/alerting/engine_integration_test.go +++ b/pkg/services/alerting/engine_integration_test.go @@ -11,9 +11,9 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/infra/usagestats" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionprovider "github.com/grafana/grafana/pkg/services/encryption/provider" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/setting" - "github.com/stretchr/testify/require" ) @@ -21,9 +21,18 @@ func TestIntegrationEngineTimeouts(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } + usMock := &usagestats.UsageStatsMock{T: t} + + encProvider := encryptionprovider.ProvideEncryptionProvider() + cfg := setting.NewCfg() + settings := &setting.OSSImpl{Cfg: cfg} + + encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, settings) + require.NoError(t, err) + tracer := tracing.InitializeTracerForTest() - engine := ProvideAlertEngine(nil, nil, nil, usMock, ossencryption.ProvideService(), nil, tracer, nil, setting.NewCfg(), nil, nil) + engine := ProvideAlertEngine(nil, nil, nil, usMock, encService, nil, tracer, nil, cfg, nil, nil) setting.AlertingNotificationTimeout = 30 * time.Second setting.AlertingMaxAttempts = 3 engine.resultHandler = &FakeResultHandler{} diff --git a/pkg/services/alerting/engine_test.go b/pkg/services/alerting/engine_test.go index e206b106779..f3d57b2cb7e 100644 --- a/pkg/services/alerting/engine_test.go +++ b/pkg/services/alerting/engine_test.go @@ -7,15 +7,15 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" - "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/infra/usagestats" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/datasources" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionprovider "github.com/grafana/grafana/pkg/services/encryption/provider" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/setting" + "github.com/stretchr/testify/require" ) type FakeEvalHandler struct { @@ -101,10 +101,17 @@ func (a *AlertStoreMock) SetAlertState(_ context.Context, _ *models.SetAlertStat func TestEngineProcessJob(t *testing.T) { usMock := &usagestats.UsageStatsMock{T: t} + + encProvider := encryptionprovider.ProvideEncryptionProvider() + cfg := setting.NewCfg() + settings := &setting.OSSImpl{Cfg: cfg} + + encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, settings) + require.NoError(t, err) tracer := tracing.InitializeTracerForTest() store := &AlertStoreMock{} - engine := ProvideAlertEngine(nil, nil, nil, usMock, ossencryption.ProvideService(), nil, tracer, store, setting.NewCfg(), nil, nil) + engine := ProvideAlertEngine(nil, nil, nil, usMock, encService, nil, tracer, store, cfg, nil, nil) setting.AlertingEvaluationTimeout = 30 * time.Second setting.AlertingNotificationTimeout = 30 * time.Second setting.AlertingMaxAttempts = 3 diff --git a/pkg/services/alerting/notifiers/alertmanager_test.go b/pkg/services/alerting/notifiers/alertmanager_test.go index 9e4b028422f..578bb8a86a9 100644 --- a/pkg/services/alerting/notifiers/alertmanager_test.go +++ b/pkg/services/alerting/notifiers/alertmanager_test.go @@ -8,7 +8,7 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/validations" "github.com/stretchr/testify/assert" @@ -81,6 +81,8 @@ func TestWhenAlertManagerShouldNotify(t *testing.T) { //nolint:goconst func TestAlertmanagerNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -92,7 +94,7 @@ func TestAlertmanagerNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewAlertmanagerNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -106,7 +108,7 @@ func TestAlertmanagerNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewAlertmanagerNotifier(model, encryptionService.GetDecryptedValue, nil) alertmanagerNotifier := not.(*AlertmanagerNotifier) require.NoError(t, err) @@ -125,7 +127,7 @@ func TestAlertmanagerNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewAlertmanagerNotifier(model, encryptionService.GetDecryptedValue, nil) alertmanagerNotifier := not.(*AlertmanagerNotifier) require.NoError(t, err) diff --git a/pkg/services/alerting/notifiers/dingding_test.go b/pkg/services/alerting/notifiers/dingding_test.go index 5ea3e27ffed..64aba4fa618 100644 --- a/pkg/services/alerting/notifiers/dingding_test.go +++ b/pkg/services/alerting/notifiers/dingding_test.go @@ -7,13 +7,15 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/validations" "github.com/stretchr/testify/require" ) func TestDingDingNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -24,7 +26,7 @@ func TestDingDingNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := newDingDingNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := newDingDingNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) t.Run("settings should trigger incident", func(t *testing.T) { @@ -37,7 +39,7 @@ func TestDingDingNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := newDingDingNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := newDingDingNotifier(model, encryptionService.GetDecryptedValue, nil) notifier := not.(*DingDingNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/discord_test.go b/pkg/services/alerting/notifiers/discord_test.go index 60b13788f56..1b70ed36923 100644 --- a/pkg/services/alerting/notifiers/discord_test.go +++ b/pkg/services/alerting/notifiers/discord_test.go @@ -5,12 +5,14 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/stretchr/testify/require" ) func TestDiscordNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -22,7 +24,7 @@ func TestDiscordNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := newDiscordNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := newDiscordNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -41,7 +43,7 @@ func TestDiscordNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := newDiscordNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := newDiscordNotifier(model, encryptionService.GetDecryptedValue, nil) discordNotifier := not.(*DiscordNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/email_test.go b/pkg/services/alerting/notifiers/email_test.go index 27dff78d9fc..8c018aa85df 100644 --- a/pkg/services/alerting/notifiers/email_test.go +++ b/pkg/services/alerting/notifiers/email_test.go @@ -5,12 +5,14 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/stretchr/testify/require" ) func TestEmailNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -22,7 +24,7 @@ func TestEmailNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewEmailNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -39,7 +41,7 @@ func TestEmailNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewEmailNotifier(model, encryptionService.GetDecryptedValue, nil) emailNotifier := not.(*EmailNotifier) require.Nil(t, err) @@ -63,7 +65,7 @@ func TestEmailNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewEmailNotifier(model, encryptionService.GetDecryptedValue, nil) emailNotifier := not.(*EmailNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/googlechat_test.go b/pkg/services/alerting/notifiers/googlechat_test.go index 6447f7dbe5e..a78ced6dc73 100644 --- a/pkg/services/alerting/notifiers/googlechat_test.go +++ b/pkg/services/alerting/notifiers/googlechat_test.go @@ -5,12 +5,14 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/stretchr/testify/require" ) func TestGoogleChatNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -22,7 +24,7 @@ func TestGoogleChatNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := newGoogleChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := newGoogleChatNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -39,7 +41,7 @@ func TestGoogleChatNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := newGoogleChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := newGoogleChatNotifier(model, encryptionService.GetDecryptedValue, nil) webhookNotifier := not.(*GoogleChatNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/hipchat_test.go b/pkg/services/alerting/notifiers/hipchat_test.go index 51b1e2d9e62..1834d92e507 100644 --- a/pkg/services/alerting/notifiers/hipchat_test.go +++ b/pkg/services/alerting/notifiers/hipchat_test.go @@ -5,13 +5,15 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/stretchr/testify/require" ) //nolint:goconst func TestHipChatNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -23,7 +25,7 @@ func TestHipChatNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewHipChatNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -39,7 +41,7 @@ func TestHipChatNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewHipChatNotifier(model, encryptionService.GetDecryptedValue, nil) hipchatNotifier := not.(*HipChatNotifier) require.Nil(t, err) @@ -65,7 +67,7 @@ func TestHipChatNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewHipChatNotifier(model, encryptionService.GetDecryptedValue, nil) hipchatNotifier := not.(*HipChatNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/kafka_test.go b/pkg/services/alerting/notifiers/kafka_test.go index 18dc7b7e1af..bc8e854c9fe 100644 --- a/pkg/services/alerting/notifiers/kafka_test.go +++ b/pkg/services/alerting/notifiers/kafka_test.go @@ -5,12 +5,14 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/stretchr/testify/require" ) func TestKafkaNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -22,7 +24,7 @@ func TestKafkaNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewKafkaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewKafkaNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -40,7 +42,7 @@ func TestKafkaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewKafkaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewKafkaNotifier(model, encryptionService.GetDecryptedValue, nil) kafkaNotifier := not.(*KafkaNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/line_test.go b/pkg/services/alerting/notifiers/line_test.go index 1720002b2fc..547897bf044 100644 --- a/pkg/services/alerting/notifiers/line_test.go +++ b/pkg/services/alerting/notifiers/line_test.go @@ -5,12 +5,14 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/stretchr/testify/require" ) func TestLineNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -21,7 +23,7 @@ func TestLineNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewLINENotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewLINENotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) t.Run("settings should trigger incident", func(t *testing.T) { @@ -36,7 +38,7 @@ func TestLineNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewLINENotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewLINENotifier(model, encryptionService.GetDecryptedValue, nil) lineNotifier := not.(*LineNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/opsgenie_test.go b/pkg/services/alerting/notifiers/opsgenie_test.go index da871304bff..23474a159a6 100644 --- a/pkg/services/alerting/notifiers/opsgenie_test.go +++ b/pkg/services/alerting/notifiers/opsgenie_test.go @@ -9,7 +9,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/validations" @@ -17,6 +17,8 @@ import ( ) func TestOpsGenieNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -28,7 +30,7 @@ func TestOpsGenieNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -45,7 +47,7 @@ func TestOpsGenieNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, nil) opsgenieNotifier := not.(*OpsGenieNotifier) require.Nil(t, err) @@ -69,7 +71,7 @@ func TestOpsGenieNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) require.Equal(t, reflect.TypeOf(err), reflect.TypeOf(alerting.ValidationError{})) require.True(t, strings.HasSuffix(err.Error(), "Invalid value for sendTagsAs: \"not_a_valid_value\"")) @@ -93,7 +95,7 @@ func TestOpsGenieNotifier(t *testing.T) { } notificationService := notifications.MockNotificationService() - notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, notificationService) // unhandled error + notifier, notifierErr := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, notificationService) // unhandled error opsgenieNotifier := notifier.(*OpsGenieNotifier) @@ -142,7 +144,7 @@ func TestOpsGenieNotifier(t *testing.T) { } notificationService := notifications.MockNotificationService() - notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, notificationService) // unhandled error + notifier, notifierErr := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, notificationService) // unhandled error opsgenieNotifier := notifier.(*OpsGenieNotifier) @@ -191,7 +193,7 @@ func TestOpsGenieNotifier(t *testing.T) { } notificationService := notifications.MockNotificationService() - notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, notificationService) // unhandled error + notifier, notifierErr := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, notificationService) // unhandled error opsgenieNotifier := notifier.(*OpsGenieNotifier) diff --git a/pkg/services/alerting/notifiers/pagerduty_test.go b/pkg/services/alerting/notifiers/pagerduty_test.go index 5231d394c08..9f31f91bdd9 100644 --- a/pkg/services/alerting/notifiers/pagerduty_test.go +++ b/pkg/services/alerting/notifiers/pagerduty_test.go @@ -11,7 +11,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/validations" "github.com/stretchr/testify/require" @@ -28,6 +28,8 @@ func presenceComparer(a, b string) bool { } func TestPagerdutyNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -40,7 +42,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - _, err = NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err = NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -56,7 +58,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) pagerdutyNotifier := not.(*PagerdutyNotifier) require.Nil(t, err) @@ -79,7 +81,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) pagerdutyNotifier := not.(*PagerdutyNotifier) require.Nil(t, err) @@ -106,7 +108,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) pagerdutyNotifier := not.(*PagerdutyNotifier) require.Nil(t, err) @@ -131,7 +133,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -188,7 +190,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -245,7 +247,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -315,7 +317,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -395,7 +397,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -474,7 +476,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) diff --git a/pkg/services/alerting/notifiers/pushover_test.go b/pkg/services/alerting/notifiers/pushover_test.go index b9726dd3b7d..d2de17dd6ed 100644 --- a/pkg/services/alerting/notifiers/pushover_test.go +++ b/pkg/services/alerting/notifiers/pushover_test.go @@ -8,13 +8,15 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/validations" "github.com/stretchr/testify/require" ) func TestPushoverNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -26,7 +28,7 @@ func TestPushoverNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewPushoverNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewPushoverNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -48,7 +50,7 @@ func TestPushoverNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPushoverNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewPushoverNotifier(model, encryptionService.GetDecryptedValue, nil) pushoverNotifier := not.(*PushoverNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/sensu_test.go b/pkg/services/alerting/notifiers/sensu_test.go index dc4376b9f9c..ad0717f9e8c 100644 --- a/pkg/services/alerting/notifiers/sensu_test.go +++ b/pkg/services/alerting/notifiers/sensu_test.go @@ -5,12 +5,14 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/stretchr/testify/require" ) func TestSensuNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -22,7 +24,7 @@ func TestSensuNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewSensuNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewSensuNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -41,7 +43,7 @@ func TestSensuNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSensuNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewSensuNotifier(model, encryptionService.GetDecryptedValue, nil) sensuNotifier := not.(*SensuNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/sensugo_test.go b/pkg/services/alerting/notifiers/sensugo_test.go index 2e95208a516..72d1e6e3112 100644 --- a/pkg/services/alerting/notifiers/sensugo_test.go +++ b/pkg/services/alerting/notifiers/sensugo_test.go @@ -5,7 +5,8 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -21,7 +22,9 @@ func TestSensuGoNotifier(t *testing.T) { Settings: settingsJSON, } - _, err = NewSensuGoNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + encryptionService := encryptionservice.SetupTestService(t) + + _, err = NewSensuGoNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) json = ` @@ -42,7 +45,7 @@ func TestSensuGoNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSensuGoNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewSensuGoNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) sensuGoNotifier := not.(*SensuGoNotifier) diff --git a/pkg/services/alerting/notifiers/slack_test.go b/pkg/services/alerting/notifiers/slack_test.go index 59244765c25..316999607da 100644 --- a/pkg/services/alerting/notifiers/slack_test.go +++ b/pkg/services/alerting/notifiers/slack_test.go @@ -9,13 +9,15 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSlackNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -27,7 +29,7 @@ func TestSlackNotifier(t *testing.T) { Settings: settingsJSON, } - _, err = NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err = NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) assert.EqualError(t, err, "alert validation error: recipient must be specified when using the Slack chat API") }) @@ -45,7 +47,7 @@ func TestSlackNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) assert.Equal(t, "ops", slackNotifier.Name) @@ -83,7 +85,7 @@ func TestSlackNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) assert.Equal(t, "ops", slackNotifier.Name) @@ -116,7 +118,7 @@ func TestSlackNotifier(t *testing.T) { settingsJSON, err := simplejson.NewJson([]byte(json)) require.NoError(t, err) - encryptionService := ossencryption.ProvideService() + encryptionService := encryptionService securedSettingsJSON, err := encryptionService.EncryptJsonData( context.Background(), map[string]string{ @@ -131,7 +133,7 @@ func TestSlackNotifier(t *testing.T) { SecureSettings: securedSettingsJSON, } - not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) assert.Equal(t, "ops", slackNotifier.Name) @@ -162,7 +164,7 @@ func TestSlackNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) assert.Equal(t, "1ABCDE", slackNotifier.recipient) @@ -253,7 +255,9 @@ func TestSendSlackRequest(t *testing.T) { Settings: settingsJSON, } - not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + encryptionService := encryptionservice.SetupTestService(t) + + not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) diff --git a/pkg/services/alerting/notifiers/teams_test.go b/pkg/services/alerting/notifiers/teams_test.go index 9bd9a6a14ff..aa864a35af8 100644 --- a/pkg/services/alerting/notifiers/teams_test.go +++ b/pkg/services/alerting/notifiers/teams_test.go @@ -5,12 +5,14 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/stretchr/testify/require" ) func TestTeamsNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -22,7 +24,7 @@ func TestTeamsNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewTeamsNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -39,7 +41,7 @@ func TestTeamsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewTeamsNotifier(model, encryptionService.GetDecryptedValue, nil) teamsNotifier := not.(*TeamsNotifier) require.Nil(t, err) @@ -61,7 +63,7 @@ func TestTeamsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewTeamsNotifier(model, encryptionService.GetDecryptedValue, nil) teamsNotifier := not.(*TeamsNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/telegram_test.go b/pkg/services/alerting/notifiers/telegram_test.go index fc0918fd47d..30fe1cbc8b0 100644 --- a/pkg/services/alerting/notifiers/telegram_test.go +++ b/pkg/services/alerting/notifiers/telegram_test.go @@ -7,13 +7,15 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/validations" "github.com/stretchr/testify/require" ) func TestTelegramNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -25,7 +27,7 @@ func TestTelegramNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewTelegramNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewTelegramNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -43,7 +45,7 @@ func TestTelegramNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewTelegramNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewTelegramNotifier(model, encryptionService.GetDecryptedValue, nil) telegramNotifier := not.(*TelegramNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/threema_test.go b/pkg/services/alerting/notifiers/threema_test.go index 974ad20eeaf..fba57eca41c 100644 --- a/pkg/services/alerting/notifiers/threema_test.go +++ b/pkg/services/alerting/notifiers/threema_test.go @@ -7,12 +7,14 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/stretchr/testify/require" ) func TestThreemaNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -24,7 +26,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -43,7 +45,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) threemaNotifier := not.(*ThreemaNotifier) @@ -70,7 +72,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) require.Nil(t, not) var valErr alerting.ValidationError require.True(t, errors.As(err, &valErr)) @@ -92,7 +94,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) require.Nil(t, not) var valErr alerting.ValidationError require.True(t, errors.As(err, &valErr)) @@ -114,7 +116,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) require.Nil(t, not) var valErr alerting.ValidationError require.True(t, errors.As(err, &valErr)) diff --git a/pkg/services/alerting/notifiers/victorops_test.go b/pkg/services/alerting/notifiers/victorops_test.go index e35fac7ca46..f975be9bae2 100644 --- a/pkg/services/alerting/notifiers/victorops_test.go +++ b/pkg/services/alerting/notifiers/victorops_test.go @@ -9,7 +9,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/validations" "github.com/stretchr/testify/require" @@ -25,6 +25,8 @@ func presenceComparerInt(a, b int64) bool { return a == b } func TestVictoropsNotifier(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Parsing alert notification from settings", func(t *testing.T) { t.Run("empty settings should return error", func(t *testing.T) { json := `{ }` @@ -36,7 +38,7 @@ func TestVictoropsNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err := NewVictoropsNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -53,7 +55,7 @@ func TestVictoropsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewVictoropsNotifier(model, encryptionService.GetDecryptedValue, nil) victoropsNotifier := not.(*VictoropsNotifier) require.Nil(t, err) @@ -77,7 +79,7 @@ func TestVictoropsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewVictoropsNotifier(model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) victoropsNotifier := not.(*VictoropsNotifier) @@ -125,7 +127,7 @@ func TestVictoropsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewVictoropsNotifier(model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) victoropsNotifier := not.(*VictoropsNotifier) diff --git a/pkg/services/alerting/notifiers/webhook_test.go b/pkg/services/alerting/notifiers/webhook_test.go index 39ed35c6395..391f3fa7ff2 100644 --- a/pkg/services/alerting/notifiers/webhook_test.go +++ b/pkg/services/alerting/notifiers/webhook_test.go @@ -5,12 +5,15 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestWebhookNotifier_parsingFromSettings(t *testing.T) { + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Empty settings should cause error", func(t *testing.T) { const json = `{}` @@ -22,7 +25,7 @@ func TestWebhookNotifier_parsingFromSettings(t *testing.T) { Settings: settingsJSON, } - _, err = NewWebHookNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + _, err = NewWebHookNotifier(model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -37,7 +40,7 @@ func TestWebhookNotifier_parsingFromSettings(t *testing.T) { Settings: settingsJSON, } - not, err := NewWebHookNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil) + not, err := NewWebHookNotifier(model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) webhookNotifier := not.(*WebhookNotifier) diff --git a/pkg/services/alerting/service_test.go b/pkg/services/alerting/service_test.go index 0d8e19245a3..c845999025f 100644 --- a/pkg/services/alerting/service_test.go +++ b/pkg/services/alerting/service_test.go @@ -6,8 +6,10 @@ import ( "testing" "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/infra/usagestats" "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionprovider "github.com/grafana/grafana/pkg/services/encryption/provider" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" @@ -20,7 +22,15 @@ func TestService(t *testing.T) { nType := "test" registerTestNotifier(nType) - s := ProvideService(sqlStore, ossencryption.ProvideService(), nil) + usMock := &usagestats.UsageStatsMock{T: t} + + encProvider := encryptionprovider.ProvideEncryptionProvider() + settings := &setting.OSSImpl{Cfg: setting.NewCfg()} + + encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, settings) + require.NoError(t, err) + + s := ProvideService(sqlStore, encService, nil) origSecret := setting.SecretKey setting.SecretKey = "alert_notification_service_test" diff --git a/pkg/services/encryption/encryption.go b/pkg/services/encryption/encryption.go index 7f5f335f9f7..59210cd3b44 100644 --- a/pkg/services/encryption/encryption.go +++ b/pkg/services/encryption/encryption.go @@ -1,6 +1,18 @@ package encryption -import "context" +import ( + "context" + "crypto/sha256" + + "golang.org/x/crypto/pbkdf2" +) + +const ( + SaltLength = 8 + + AesCfb = "aes-cfb" + AesGcm = "aes-gcm" +) // Internal must not be used for general purpose encryption. // This service is used as an internal component for envelope encryption @@ -8,11 +20,29 @@ import "context" // // Unless there is any specific reason, you must use secrets.Service instead. type Internal interface { - Encrypt(ctx context.Context, payload []byte, secret string) ([]byte, error) - Decrypt(ctx context.Context, payload []byte, secret string) ([]byte, error) + Cipher + Decipher EncryptJsonData(ctx context.Context, kv map[string]string, secret string) (map[string][]byte, error) DecryptJsonData(ctx context.Context, sjd map[string][]byte, secret string) (map[string]string, error) GetDecryptedValue(ctx context.Context, sjd map[string][]byte, key string, fallback string, secret string) string } + +type Cipher interface { + Encrypt(ctx context.Context, payload []byte, secret string) ([]byte, error) +} + +type Decipher interface { + Decrypt(ctx context.Context, payload []byte, secret string) ([]byte, error) +} + +type Provider interface { + ProvideCiphers() map[string]Cipher + ProvideDeciphers() map[string]Decipher +} + +// KeyToBytes key length needs to be 32 bytes +func KeyToBytes(secret, salt string) ([]byte, error) { + return pbkdf2.Key([]byte(secret), []byte(salt), 10000, 32, sha256.New), nil +} diff --git a/pkg/services/encryption/encryption_test.go b/pkg/services/encryption/encryption_test.go new file mode 100644 index 00000000000..18146b317e3 --- /dev/null +++ b/pkg/services/encryption/encryption_test.go @@ -0,0 +1,22 @@ +package encryption + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_KeyToBytes(t *testing.T) { + t.Run("with regular secret", func(t *testing.T) { + key, err := KeyToBytes("secret", "salt") + require.NoError(t, err) + assert.Len(t, key, 32) + }) + + t.Run("with very long secret", func(t *testing.T) { + key, err := KeyToBytes("a very long secret key that is larger then 32bytes", "salt") + require.NoError(t, err) + assert.Len(t, key, 32) + }) +} diff --git a/pkg/services/encryption/ossencryption/ossencryption.go b/pkg/services/encryption/ossencryption/ossencryption.go deleted file mode 100644 index bfce3e35af8..00000000000 --- a/pkg/services/encryption/ossencryption/ossencryption.go +++ /dev/null @@ -1,180 +0,0 @@ -package ossencryption - -import ( - "bytes" - "context" - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "crypto/sha256" - "encoding/base64" - "errors" - "fmt" - "io" - - "github.com/grafana/grafana/pkg/util" - "golang.org/x/crypto/pbkdf2" -) - -// Service must not be used for encryption, -// use secrets.Service implementing envelope encryption instead. -type Service struct{} - -func ProvideService() *Service { - return &Service{} -} - -const ( - saltLength = 8 - aesCfb = "aes-cfb" - encryptionAlgorithmDelimiter = '*' -) - -func (s *Service) Decrypt(_ context.Context, payload []byte, secret string) ([]byte, error) { - alg, payload, err := deriveEncryptionAlgorithm(payload) - if err != nil { - return nil, err - } - - if len(payload) < saltLength { - return nil, errors.New("unable to compute salt") - } - salt := payload[:saltLength] - key, err := encryptionKeyToBytes(secret, string(salt)) - if err != nil { - return nil, err - } - - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - switch alg { - case aesCfb: - return decryptCFB(block, payload) - default: - return nil, errors.New("unsupported encryption algorithm") - } -} - -func deriveEncryptionAlgorithm(payload []byte) (string, []byte, error) { - if len(payload) == 0 { - return "", nil, fmt.Errorf("unable to derive encryption algorithm") - } - - if payload[0] != encryptionAlgorithmDelimiter { - return aesCfb, payload, nil // backwards compatibility - } - - payload = payload[1:] - algDelim := bytes.Index(payload, []byte{encryptionAlgorithmDelimiter}) - if algDelim == -1 { - return aesCfb, payload, nil // backwards compatibility - } - - algB64 := payload[:algDelim] - payload = payload[algDelim+1:] - - alg := make([]byte, base64.RawStdEncoding.DecodedLen(len(algB64))) - - _, err := base64.RawStdEncoding.Decode(alg, algB64) - if err != nil { - return "", nil, err - } - - return string(alg), payload, nil -} - -func decryptCFB(block cipher.Block, payload []byte) ([]byte, error) { - // The IV needs to be unique, but not secure. Therefore, it's common to - // include it at the beginning of the ciphertext. - if len(payload) < aes.BlockSize { - return nil, errors.New("payload too short") - } - - iv := payload[saltLength : saltLength+aes.BlockSize] - payload = payload[saltLength+aes.BlockSize:] - payloadDst := make([]byte, len(payload)) - - stream := cipher.NewCFBDecrypter(block, iv) - - // XORKeyStream can work in-place if the two arguments are the same. - stream.XORKeyStream(payloadDst, payload) - return payloadDst, nil -} - -func (s *Service) Encrypt(_ context.Context, payload []byte, secret string) ([]byte, error) { - salt, err := util.GetRandomString(saltLength) - if err != nil { - return nil, err - } - - key, err := encryptionKeyToBytes(secret, salt) - if err != nil { - return nil, err - } - - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - // The IV needs to be unique, but not secure. Therefore it's common to - // include it at the beginning of the ciphertext. - ciphertext := make([]byte, saltLength+aes.BlockSize+len(payload)) - copy(ciphertext[:saltLength], salt) - iv := ciphertext[saltLength : saltLength+aes.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - stream := cipher.NewCFBEncrypter(block, iv) - stream.XORKeyStream(ciphertext[saltLength+aes.BlockSize:], payload) - - return ciphertext, nil -} - -func (s *Service) EncryptJsonData(ctx context.Context, kv map[string]string, secret string) (map[string][]byte, error) { - encrypted := make(map[string][]byte) - for key, value := range kv { - encryptedData, err := s.Encrypt(ctx, []byte(value), secret) - if err != nil { - return nil, err - } - - encrypted[key] = encryptedData - } - return encrypted, nil -} - -func (s *Service) DecryptJsonData(ctx context.Context, sjd map[string][]byte, secret string) (map[string]string, error) { - decrypted := make(map[string]string) - for key, data := range sjd { - decryptedData, err := s.Decrypt(ctx, data, secret) - if err != nil { - return nil, err - } - - decrypted[key] = string(decryptedData) - } - return decrypted, nil -} - -func (s *Service) GetDecryptedValue(ctx context.Context, sjd map[string][]byte, key, fallback, secret string) string { - if value, ok := sjd[key]; ok { - decryptedData, err := s.Decrypt(ctx, value, secret) - if err != nil { - return fallback - } - - return string(decryptedData) - } - - return fallback -} - -// Key needs to be 32bytes -func encryptionKeyToBytes(secret, salt string) ([]byte, error) { - return pbkdf2.Key([]byte(secret), []byte(salt), 10000, 32, sha256.New), nil -} diff --git a/pkg/services/encryption/ossencryption/ossencryption_test.go b/pkg/services/encryption/ossencryption/ossencryption_test.go deleted file mode 100644 index c3ebcda536f..00000000000 --- a/pkg/services/encryption/ossencryption/ossencryption_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package ossencryption - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestEncryption(t *testing.T) { - svc := Service{} - - t.Run("getting encryption key", func(t *testing.T) { - key, err := encryptionKeyToBytes("secret", "salt") - require.NoError(t, err) - assert.Len(t, key, 32) - - key, err = encryptionKeyToBytes("a very long secret key that is larger then 32bytes", "salt") - require.NoError(t, err) - assert.Len(t, key, 32) - }) - - t.Run("decrypting basic payload", func(t *testing.T) { - ctx := context.Background() - - encrypted, err := svc.Encrypt(ctx, []byte("grafana"), "1234") - require.NoError(t, err) - - decrypted, err := svc.Decrypt(ctx, encrypted, "1234") - require.NoError(t, err) - - assert.Equal(t, []byte("grafana"), decrypted) - }) - - t.Run("decrypting empty payload should return error", func(t *testing.T) { - _, err := svc.Decrypt(context.Background(), []byte(""), "1234") - require.Error(t, err) - - assert.Equal(t, "unable to derive encryption algorithm", err.Error()) - }) - - t.Run("decrypting ciphertext with aes-gcm as encryption algorithm should return error", func(t *testing.T) { - // Raw slice of bytes that corresponds to the following ciphertext: - // - 'grafana' as payload - // - '1234' as secret - // - 'aes-gcm' as encryption algorithm - // With no encryption algorithm metadata. - ciphertext := []byte{42, 89, 87, 86, 122, 76, 87, 100, 106, 98, 81, 42, 48, 99, 55, 50, 51, 48, 83, 66, 20, 99, 47, 238, 61, 44, 129, 125, 14, 37, 162, 230, 47, 31, 104, 70, 144, 223, 26, 51, 180, 17, 76, 52, 36, 93, 17, 203, 99, 158, 219, 102, 74, 173, 74} - _, err := svc.Decrypt(context.Background(), ciphertext, "1234") - require.Error(t, err) - - assert.Equal(t, "unsupported encryption algorithm", err.Error()) - }) - - t.Run("decrypting ciphertext with aes-cfb as encryption algorithm do not fail", func(t *testing.T) { - // Raw slice of bytes that corresponds to the following ciphertext: - // - 'grafana' as payload - // - '1234' as secret - // - 'aes-cfb' as encryption algorithm - // With no encryption algorithm metadata. - ciphertext := []byte{42, 89, 87, 86, 122, 76, 87, 78, 109, 89, 103, 42, 73, 71, 50, 57, 121, 110, 90, 109, 115, 23, 237, 13, 130, 188, 151, 118, 98, 103, 80, 209, 79, 143, 22, 122, 44, 40, 102, 41, 136, 16, 27} - decrypted, err := svc.Decrypt(context.Background(), ciphertext, "1234") - require.NoError(t, err) - - assert.Equal(t, []byte("grafana"), decrypted) - }) -} diff --git a/pkg/services/encryption/provider/cipher_aescfb.go b/pkg/services/encryption/provider/cipher_aescfb.go new file mode 100644 index 00000000000..1712fc66dde --- /dev/null +++ b/pkg/services/encryption/provider/cipher_aescfb.go @@ -0,0 +1,45 @@ +package provider + +import ( + "context" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "io" + + "github.com/grafana/grafana/pkg/services/encryption" + "github.com/grafana/grafana/pkg/util" +) + +type aesCfbCipher struct{} + +func (c aesCfbCipher) Encrypt(_ context.Context, payload []byte, secret string) ([]byte, error) { + salt, err := util.GetRandomString(encryption.SaltLength) + if err != nil { + return nil, err + } + + key, err := encryption.KeyToBytes(secret, salt) + if err != nil { + return nil, err + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + // The IV needs to be unique, but not secure. Therefore, it's common to + // include it at the beginning of the ciphertext. + ciphertext := make([]byte, encryption.SaltLength+aes.BlockSize+len(payload)) + copy(ciphertext[:encryption.SaltLength], salt) + iv := ciphertext[encryption.SaltLength : encryption.SaltLength+aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + + stream := cipher.NewCFBEncrypter(block, iv) + stream.XORKeyStream(ciphertext[encryption.SaltLength+aes.BlockSize:], payload) + + return ciphertext, nil +} diff --git a/pkg/services/encryption/provider/cipher_aescfb_test.go b/pkg/services/encryption/provider/cipher_aescfb_test.go new file mode 100644 index 00000000000..d717381590f --- /dev/null +++ b/pkg/services/encryption/provider/cipher_aescfb_test.go @@ -0,0 +1,20 @@ +package provider + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/stretchr/testify/require" +) + +func Test_aesCfbCipher(t *testing.T) { + cipher := aesCfbCipher{} + ctx := context.Background() + + encrypted, err := cipher.Encrypt(ctx, []byte("grafana"), "1234") + require.NoError(t, err) + assert.NotNil(t, encrypted) + assert.NotEmpty(t, encrypted) +} diff --git a/pkg/services/encryption/provider/decipher_aes.go b/pkg/services/encryption/provider/decipher_aes.go new file mode 100644 index 00000000000..33cebbfe975 --- /dev/null +++ b/pkg/services/encryption/provider/decipher_aes.go @@ -0,0 +1,67 @@ +package provider + +import ( + "context" + "crypto/aes" + "crypto/cipher" + "errors" + + "github.com/grafana/grafana/pkg/services/encryption" +) + +type aesDecipher struct { + algorithm string +} + +func (d aesDecipher) Decrypt(_ context.Context, payload []byte, secret string) ([]byte, error) { + if len(payload) < encryption.SaltLength { + return nil, errors.New("unable to compute salt") + } + + salt := payload[:encryption.SaltLength] + key, err := encryption.KeyToBytes(secret, string(salt)) + if err != nil { + return nil, err + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + switch d.algorithm { + case encryption.AesGcm: + return decryptGCM(block, payload) + default: + return decryptCFB(block, payload) + } +} + +func decryptGCM(block cipher.Block, payload []byte) ([]byte, error) { + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonce := payload[encryption.SaltLength : encryption.SaltLength+gcm.NonceSize()] + ciphertext := payload[encryption.SaltLength+gcm.NonceSize():] + return gcm.Open(nil, nonce, ciphertext, nil) +} + +func decryptCFB(block cipher.Block, payload []byte) ([]byte, error) { + // The IV needs to be unique, but not secure. Therefore, it's common to + // include it at the beginning of the ciphertext. + if len(payload) < aes.BlockSize { + return nil, errors.New("payload too short") + } + + iv := payload[encryption.SaltLength : encryption.SaltLength+aes.BlockSize] + payload = payload[encryption.SaltLength+aes.BlockSize:] + payloadDst := make([]byte, len(payload)) + + stream := cipher.NewCFBDecrypter(block, iv) + + // XORKeyStream can work in-place if the two arguments are the same. + stream.XORKeyStream(payloadDst, payload) + return payloadDst, nil +} diff --git a/pkg/services/encryption/provider/decipher_aes_test.go b/pkg/services/encryption/provider/decipher_aes_test.go new file mode 100644 index 00000000000..b31958e8886 --- /dev/null +++ b/pkg/services/encryption/provider/decipher_aes_test.go @@ -0,0 +1,32 @@ +package provider + +import ( + "context" + "testing" + + "github.com/grafana/grafana/pkg/services/encryption" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_aesDecipher(t *testing.T) { + ctx := context.Background() + + t.Run("aes-cfb", func(t *testing.T) { + cipher := aesDecipher{algorithm: encryption.AesCfb} + cfbEncryptedCiphertext := []byte{69, 84, 85, 120, 65, 82, 107, 88, 144, 188, 109, 229, 91, 88, 85, 113, 220, 35, 178, 190, 208, 182, 209, 91, 252, 119, 138, 133, 198, 8, 1} + + decrypted, err := cipher.Decrypt(ctx, cfbEncryptedCiphertext, "1234") + require.NoError(t, err) + assert.Equal(t, []byte("grafana"), decrypted) + }) + + t.Run("aes-gcm", func(t *testing.T) { + cipher := aesDecipher{algorithm: encryption.AesGcm} + gcmEncryptedCiphertext := []byte{48, 99, 55, 50, 51, 48, 83, 66, 20, 99, 47, 238, 61, 44, 129, 125, 14, 37, 162, 230, 47, 31, 104, 70, 144, 223, 26, 51, 180, 17, 76, 52, 36, 93, 17, 203, 99, 158, 219, 102, 74, 173, 74} + + decrypted, err := cipher.Decrypt(ctx, gcmEncryptedCiphertext, "1234") + require.NoError(t, err) + assert.Equal(t, []byte("grafana"), decrypted) + }) +} diff --git a/pkg/services/encryption/provider/provider.go b/pkg/services/encryption/provider/provider.go new file mode 100644 index 00000000000..355419c3f1e --- /dev/null +++ b/pkg/services/encryption/provider/provider.go @@ -0,0 +1,24 @@ +package provider + +import ( + "github.com/grafana/grafana/pkg/services/encryption" +) + +type Provider struct{} + +func ProvideEncryptionProvider() Provider { + return Provider{} +} + +func (p Provider) ProvideCiphers() map[string]encryption.Cipher { + return map[string]encryption.Cipher{ + encryption.AesCfb: aesCfbCipher{}, + } +} + +func (p Provider) ProvideDeciphers() map[string]encryption.Decipher { + return map[string]encryption.Decipher{ + encryption.AesCfb: aesDecipher{algorithm: encryption.AesCfb}, + encryption.AesGcm: aesDecipher{algorithm: encryption.AesGcm}, + } +} diff --git a/pkg/services/encryption/service/helpers.go b/pkg/services/encryption/service/helpers.go new file mode 100644 index 00000000000..d32c1600d94 --- /dev/null +++ b/pkg/services/encryption/service/helpers.go @@ -0,0 +1,23 @@ +package service + +import ( + "testing" + + "github.com/grafana/grafana/pkg/infra/usagestats" + encryptionprovider "github.com/grafana/grafana/pkg/services/encryption/provider" + "github.com/grafana/grafana/pkg/setting" + "github.com/stretchr/testify/require" +) + +func SetupTestService(tb testing.TB) *Service { + tb.Helper() + + usMock := &usagestats.UsageStatsMock{T: tb} + provider := encryptionprovider.ProvideEncryptionProvider() + settings := &setting.OSSImpl{Cfg: setting.NewCfg()} + + service, err := ProvideEncryptionService(provider, usMock, settings) + require.NoError(tb, err) + + return service +} diff --git a/pkg/services/encryption/service/service.go b/pkg/services/encryption/service/service.go new file mode 100644 index 00000000000..7a8d3709677 --- /dev/null +++ b/pkg/services/encryption/service/service.go @@ -0,0 +1,243 @@ +package service + +import ( + "bytes" + "context" + "encoding/base64" + "errors" + "fmt" + + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/infra/usagestats" + "github.com/grafana/grafana/pkg/services/encryption" + "github.com/grafana/grafana/pkg/setting" +) + +const ( + encryptionAlgorithmDelimiter = '*' + + securitySection = "security.encryption" + encryptionAlgorithmKey = "algorithm" + defaultEncryptionAlgorithm = encryption.AesCfb +) + +// Service must not be used for encryption. +// Use secrets.Service implementing envelope encryption instead. +type Service struct { + log log.Logger + + settingsProvider setting.Provider + usageMetrics usagestats.Service + + ciphers map[string]encryption.Cipher + deciphers map[string]encryption.Decipher +} + +func ProvideEncryptionService( + provider encryption.Provider, + usageMetrics usagestats.Service, + settingsProvider setting.Provider, +) (*Service, error) { + s := &Service{ + log: log.New("encryption"), + + ciphers: provider.ProvideCiphers(), + deciphers: provider.ProvideDeciphers(), + + usageMetrics: usageMetrics, + settingsProvider: settingsProvider, + } + + algorithm := s.settingsProvider. + KeyValue(securitySection, encryptionAlgorithmKey). + MustString(defaultEncryptionAlgorithm) + + if err := s.checkEncryptionAlgorithm(algorithm); err != nil { + return nil, err + } + + settingsProvider.RegisterReloadHandler(securitySection, s) + + s.registerUsageMetrics() + + return s, nil +} + +func (s *Service) checkEncryptionAlgorithm(algorithm string) error { + var err error + defer func() { + if err != nil { + s.log.Error("Wrong security encryption configuration", "algorithm", algorithm, "error", err) + } + }() + + if _, ok := s.ciphers[algorithm]; !ok { + err = errors.New("no cipher registered for encryption algorithm configured") + return err + } + + if _, ok := s.deciphers[algorithm]; !ok { + err = errors.New("no cipher registered for encryption algorithm configured") + return err + } + + return nil +} + +func (s *Service) registerUsageMetrics() { + s.usageMetrics.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) { + algorithm := s.settingsProvider. + KeyValue(securitySection, encryptionAlgorithmKey). + MustString(defaultEncryptionAlgorithm) + + return map[string]interface{}{ + fmt.Sprintf("stats.encryption.%s.count", algorithm): 1, + }, nil + }) +} + +func (s *Service) Decrypt(ctx context.Context, payload []byte, secret string) ([]byte, error) { + var err error + defer func() { + if err != nil { + s.log.Error("Decryption failed", "error", err) + } + }() + + var ( + algorithm string + toDecrypt []byte + ) + algorithm, toDecrypt, err = deriveEncryptionAlgorithm(payload) + if err != nil { + return nil, err + } + + decipher, ok := s.deciphers[algorithm] + if !ok { + err = fmt.Errorf("no decipher available for algorithm '%s'", algorithm) + return nil, err + } + + var decrypted []byte + decrypted, err = decipher.Decrypt(ctx, toDecrypt, secret) + + return decrypted, err +} + +func deriveEncryptionAlgorithm(payload []byte) (string, []byte, error) { + if len(payload) == 0 { + return "", nil, fmt.Errorf("unable to derive encryption algorithm") + } + + if payload[0] != encryptionAlgorithmDelimiter { + return encryption.AesCfb, payload, nil // backwards compatibility + } + + payload = payload[1:] + algorithmDelimiterIdx := bytes.Index(payload, []byte{encryptionAlgorithmDelimiter}) + if algorithmDelimiterIdx == -1 { + return encryption.AesCfb, payload, nil // backwards compatibility + } + + algorithmB64 := payload[:algorithmDelimiterIdx] + payload = payload[algorithmDelimiterIdx+1:] + + algorithm := make([]byte, base64.RawStdEncoding.DecodedLen(len(algorithmB64))) + + _, err := base64.RawStdEncoding.Decode(algorithm, algorithmB64) + if err != nil { + return "", nil, err + } + + return string(algorithm), payload, nil +} + +func (s *Service) Encrypt(ctx context.Context, payload []byte, secret string) ([]byte, error) { + var err error + defer func() { + if err != nil { + s.log.Error("Encryption failed", "error", err) + } + }() + + algorithm := s.settingsProvider. + KeyValue(securitySection, encryptionAlgorithmKey). + MustString(defaultEncryptionAlgorithm) + + cipher, ok := s.ciphers[algorithm] + if !ok { + err = fmt.Errorf("no cipher available for algorithm '%s'", algorithm) + return nil, err + } + + var encrypted []byte + encrypted, err = cipher.Encrypt(ctx, payload, secret) + + prefix := make([]byte, base64.RawStdEncoding.EncodedLen(len([]byte(algorithm)))+2) + base64.RawStdEncoding.Encode(prefix[1:], []byte(algorithm)) + prefix[0] = encryptionAlgorithmDelimiter + prefix[len(prefix)-1] = encryptionAlgorithmDelimiter + + ciphertext := make([]byte, len(prefix)+len(encrypted)) + copy(ciphertext, prefix) + copy(ciphertext[len(prefix):], encrypted) + + return ciphertext, nil +} + +func (s *Service) EncryptJsonData(ctx context.Context, kv map[string]string, secret string) (map[string][]byte, error) { + encrypted := make(map[string][]byte) + for key, value := range kv { + encryptedData, err := s.Encrypt(ctx, []byte(value), secret) + if err != nil { + return nil, err + } + + encrypted[key] = encryptedData + } + return encrypted, nil +} + +func (s *Service) DecryptJsonData(ctx context.Context, sjd map[string][]byte, secret string) (map[string]string, error) { + decrypted := make(map[string]string) + for key, data := range sjd { + decryptedData, err := s.Decrypt(ctx, data, secret) + if err != nil { + return nil, err + } + + decrypted[key] = string(decryptedData) + } + return decrypted, nil +} + +func (s *Service) GetDecryptedValue(ctx context.Context, sjd map[string][]byte, key, fallback, secret string) string { + if value, ok := sjd[key]; ok { + decryptedData, err := s.Decrypt(ctx, value, secret) + if err != nil { + return fallback + } + + return string(decryptedData) + } + + return fallback +} + +func (s *Service) Validate(section setting.Section) error { + s.log.Debug("Validating encryption config") + + algorithm := section.KeyValue(encryptionAlgorithmKey). + MustString(defaultEncryptionAlgorithm) + + if err := s.checkEncryptionAlgorithm(algorithm); err != nil { + return err + } + + return nil +} + +func (s *Service) Reload(_ setting.Section) error { + return nil +} diff --git a/pkg/services/encryption/service/service_test.go b/pkg/services/encryption/service/service_test.go new file mode 100644 index 00000000000..e4850724699 --- /dev/null +++ b/pkg/services/encryption/service/service_test.go @@ -0,0 +1,94 @@ +package service + +import ( + "context" + "testing" + + "github.com/grafana/grafana/pkg/infra/usagestats" + "github.com/grafana/grafana/pkg/services/encryption" + "github.com/grafana/grafana/pkg/services/encryption/provider" + "github.com/grafana/grafana/pkg/setting" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_Service(t *testing.T) { + ctx := context.Background() + + encProvider := provider.Provider{} + usageStats := &usagestats.UsageStatsMock{} + settings := &setting.OSSImpl{Cfg: setting.NewCfg()} + + svc, err := ProvideEncryptionService(encProvider, usageStats, settings) + require.NoError(t, err) + + t.Run("decrypt empty payload should return error", func(t *testing.T) { + _, err := svc.Decrypt(context.Background(), []byte(""), "1234") + require.Error(t, err) + + assert.Equal(t, "unable to derive encryption algorithm", err.Error()) + }) + + t.Run("encrypt and decrypt with aes-cfb should work", func(t *testing.T) { + settings.Cfg.Raw.Section(securitySection).Key(encryptionAlgorithmKey).SetValue(encryption.AesCfb) + + encrypted, err := svc.Encrypt(ctx, []byte("grafana"), "1234") + require.NoError(t, err) + + decrypted, err := svc.Decrypt(ctx, encrypted, "1234") + require.NoError(t, err) + + assert.Equal(t, []byte("grafana"), decrypted) + }) + + t.Run("decrypt with aes-gcm should work", func(t *testing.T) { + // Raw slice of bytes that corresponds to the following ciphertext: + // - 'grafana' as payload + // - '1234' as secret + // - 'aes-gcm' as encryption algorithm + ciphertext := []byte{42, 89, 87, 86, 122, 76, 87, 100, 106, 98, 81, 42, 48, 99, 55, 50, 51, 48, 83, 66, 20, 99, 47, 238, 61, 44, 129, 125, 14, 37, 162, 230, 47, 31, 104, 70, 144, 223, 26, 51, 180, 17, 76, 52, 36, 93, 17, 203, 99, 158, 219, 102, 74, 173, 74} + + decrypted, err := svc.Decrypt(context.Background(), ciphertext, "1234") + require.NoError(t, err) + assert.Equal(t, []byte("grafana"), decrypted) + }) + + t.Run("encrypt with aes-gcm should fail", func(t *testing.T) { + settings.Cfg.Raw.Section(securitySection).Key(encryptionAlgorithmKey).SetValue(encryption.AesGcm) + + _, err := svc.Encrypt(ctx, []byte("grafana"), "1234") + require.Error(t, err) + }) + + t.Run("decrypting legacy ciphertext should work", func(t *testing.T) { + // Raw slice of bytes that corresponds to the following ciphertext: + // - 'grafana' as payload + // - '1234' as secret + // - no encryption algorithm metadata + ciphertext := []byte{73, 71, 50, 57, 121, 110, 90, 109, 115, 23, 237, 13, 130, 188, 151, 118, 98, 103, 80, 209, 79, 143, 22, 122, 44, 40, 102, 41, 136, 16, 27} + + decrypted, err := svc.Decrypt(context.Background(), ciphertext, "1234") + require.NoError(t, err) + assert.Equal(t, []byte("grafana"), decrypted) + }) +} + +func Test_Service_MissingProvider(t *testing.T) { + encProvider := fakeProvider{} + usageStats := &usagestats.UsageStatsMock{} + settings := &setting.OSSImpl{Cfg: setting.NewCfg()} + + service, err := ProvideEncryptionService(encProvider, usageStats, settings) + assert.Nil(t, service) + assert.Error(t, err) +} + +type fakeProvider struct{} + +func (p fakeProvider) ProvideCiphers() map[string]encryption.Cipher { + return nil +} + +func (p fakeProvider) ProvideDeciphers() map[string]encryption.Decipher { + return nil +} diff --git a/pkg/services/provisioning/notifiers/config_reader_test.go b/pkg/services/provisioning/notifiers/config_reader_test.go index 8c78a108a37..9e6ee7675e0 100644 --- a/pkg/services/provisioning/notifiers/config_reader_test.go +++ b/pkg/services/provisioning/notifiers/config_reader_test.go @@ -10,7 +10,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting/notifiers" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/stretchr/testify/require" @@ -33,6 +33,8 @@ func TestNotificationAsConfig(t *testing.T) { var sqlStore *sqlstore.SQLStore logger := log.New("fake.log") + encryptionService := encryptionservice.SetupTestService(t) + t.Run("Testing notification as configuration", func(t *testing.T) { setup := func() { sqlStore = sqlstore.InitTestDB(t) @@ -61,7 +63,7 @@ func TestNotificationAsConfig(t *testing.T) { _ = os.Setenv("TEST_VAR", "default") cfgProvider := &configReader{ orgStore: sqlStore, - encryptionService: ossencryption.ProvideService(), + encryptionService: encryptionService, log: log.New("test logger"), } @@ -140,7 +142,7 @@ func TestNotificationAsConfig(t *testing.T) { setup() fakeAlertNotification := &fakeAlertNotification{} fakeAlertNotification.ExpectedAlertNotification = &models.AlertNotification{OrgId: 1} - dc := newNotificationProvisioner(sqlStore, fakeAlertNotification, ossencryption.ProvideService(), nil, logger) + dc := newNotificationProvisioner(sqlStore, fakeAlertNotification, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), twoNotificationsConfig) if err != nil { @@ -166,7 +168,7 @@ func TestNotificationAsConfig(t *testing.T) { require.Equal(t, len(notificationsQuery.Result), 1) t.Run("should update one notification", func(t *testing.T) { - dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, ossencryption.ProvideService(), nil, logger) + dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) err = dc.applyChanges(context.Background(), twoNotificationsConfig) if err != nil { t.Fatalf("applyChanges return an error %v", err) @@ -175,7 +177,7 @@ func TestNotificationAsConfig(t *testing.T) { }) t.Run("Two notifications with is_default", func(t *testing.T) { setup() - dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, ossencryption.ProvideService(), nil, logger) + dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), doubleNotificationsConfig) t.Run("should both be inserted", func(t *testing.T) { require.NoError(t, err) @@ -210,7 +212,7 @@ func TestNotificationAsConfig(t *testing.T) { require.Equal(t, len(notificationsQuery.Result), 2) t.Run("should have two new notifications", func(t *testing.T) { - dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, ossencryption.ProvideService(), nil, logger) + dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), twoNotificationsConfig) if err != nil { t.Fatalf("applyChanges return an error %v", err) @@ -239,7 +241,7 @@ func TestNotificationAsConfig(t *testing.T) { err = sqlStore.CreateAlertNotificationCommand(context.Background(), &existingNotificationCmd) require.NoError(t, err) - dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, ossencryption.ProvideService(), nil, logger) + dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) err = dc.applyChanges(context.Background(), correctPropertiesWithOrgName) if err != nil { t.Fatalf("applyChanges return an error %v", err) @@ -248,7 +250,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Config doesn't contain required field", func(t *testing.T) { setup() - dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, ossencryption.ProvideService(), nil, logger) + dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), noRequiredFields) require.NotNil(t, err) @@ -262,7 +264,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Empty yaml file", func(t *testing.T) { t.Run("should have not changed repo", func(t *testing.T) { setup() - dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, ossencryption.ProvideService(), nil, logger) + dc := newNotificationProvisioner(sqlStore, &fakeAlertNotification{}, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), emptyFile) if err != nil { t.Fatalf("applyChanges return an error %v", err) @@ -277,7 +279,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Broken yaml should return error", func(t *testing.T) { reader := &configReader{ orgStore: sqlStore, - encryptionService: ossencryption.ProvideService(), + encryptionService: encryptionService, log: log.New("test logger"), } @@ -288,7 +290,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Skip invalid directory", func(t *testing.T) { cfgProvider := &configReader{ orgStore: sqlStore, - encryptionService: ossencryption.ProvideService(), + encryptionService: encryptionService, log: log.New("test logger"), } @@ -302,7 +304,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Unknown notifier should return error", func(t *testing.T) { cfgProvider := &configReader{ orgStore: sqlStore, - encryptionService: ossencryption.ProvideService(), + encryptionService: encryptionService, log: log.New("test logger"), } _, err := cfgProvider.readConfig(context.Background(), unknownNotifier) @@ -313,7 +315,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Read incorrect properties", func(t *testing.T) { cfgProvider := &configReader{ orgStore: sqlStore, - encryptionService: ossencryption.ProvideService(), + encryptionService: encryptionService, log: log.New("test logger"), } _, err := cfgProvider.readConfig(context.Background(), incorrectSettings) diff --git a/pkg/services/secrets/manager/helpers.go b/pkg/services/secrets/manager/helpers.go index 33448e84362..967c909be33 100644 --- a/pkg/services/secrets/manager/helpers.go +++ b/pkg/services/secrets/manager/helpers.go @@ -4,7 +4,8 @@ import ( "testing" "github.com/grafana/grafana/pkg/infra/usagestats" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionprovider "github.com/grafana/grafana/pkg/services/encryption/provider" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/kmsproviders/osskmsproviders" "github.com/grafana/grafana/pkg/services/secrets" @@ -37,10 +38,14 @@ func setupTestService(tb testing.TB, store secrets.Store, features *featuremgmt. require.NoError(tb, err) cfg := &setting.Cfg{Raw: raw} - settings := &setting.OSSImpl{Cfg: cfg} - encryption := ossencryption.ProvideService() + encProvider := encryptionprovider.Provider{} + usageStats := &usagestats.UsageStatsMock{} + + encryption, err := encryptionservice.ProvideEncryptionService(encProvider, usageStats, settings) + require.NoError(tb, err) + secretsService, err := ProvideSecretsService( store, osskmsproviders.ProvideService(encryption, settings, features), diff --git a/pkg/services/secrets/manager/manager_test.go b/pkg/services/secrets/manager/manager_test.go index 159fda5c3e8..5f704ffd0a4 100644 --- a/pkg/services/secrets/manager/manager_test.go +++ b/pkg/services/secrets/manager/manager_test.go @@ -6,7 +6,8 @@ import ( "time" "github.com/grafana/grafana/pkg/infra/usagestats" - "github.com/grafana/grafana/pkg/services/encryption/ossencryption" + encryptionprovider "github.com/grafana/grafana/pkg/services/encryption/provider" + encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/kmsproviders/osskmsproviders" "github.com/grafana/grafana/pkg/services/secrets" @@ -175,8 +176,14 @@ func TestSecretsService_UseCurrentProvider(t *testing.T) { raw, err := ini.Load([]byte(rawCfg)) require.NoError(t, err) - encryptionService := ossencryption.ProvideService() settings := &setting.OSSImpl{Cfg: &setting.Cfg{Raw: raw}} + + encProvider := encryptionprovider.Provider{} + usageStats := &usagestats.UsageStatsMock{} + + encryptionService, err := encryptionservice.ProvideEncryptionService(encProvider, usageStats, settings) + require.NoError(t, err) + features := featuremgmt.WithFeatures() kms := newFakeKMS(osskmsproviders.ProvideService(encryptionService, settings, features)) secretStore := database.ProvideSecretsStore(sqlstore.InitTestDB(t))