diff --git a/cmd/api/src/database/migration/migrations/v8.7.0.sql b/cmd/api/src/database/migration/migrations/v8.7.0.sql index d1b033af4d5..6e69df8ce4f 100644 --- a/cmd/api/src/database/migration/migrations/v8.7.0.sql +++ b/cmd/api/src/database/migration/migrations/v8.7.0.sql @@ -146,3 +146,13 @@ CREATE TABLE IF NOT EXISTS schema_list_findings ( CREATE INDEX IF NOT EXISTS idx_schema_list_findings_extension_id ON schema_list_findings (schema_extension_id); CREATE INDEX IF NOT EXISTS idx_schema_list_findings_environment_id ON schema_list_findings(environment_id); + +-- Add API Tokens Expiration Parameter +INSERT INTO parameter (key, name, description, value, created_at, updated_at) +VALUES ('auth.api_token_expiration', + 'API Token Expiration', + 'This configuration parameter enables/disables created API tokens to expire after the set number of days.', + '{"enabled":false, "expiration_period":90}', + current_timestamp, + current_timestamp) +ON CONFLICT DO NOTHING; diff --git a/cmd/api/src/database/parameters_test.go b/cmd/api/src/database/parameters_test.go index b8a8c971900..b4a7b75c9ee 100644 --- a/cmd/api/src/database/parameters_test.go +++ b/cmd/api/src/database/parameters_test.go @@ -213,3 +213,25 @@ func TestParameters_GetAPITokensParameter(t *testing.T) { require.Equal(t, enableApiKeys, appcfg.GetAPITokensParameter(testCtx, db)) } + +func TestParameters_GetAPITokenExpirationParameter(t *testing.T) { + var ( + db = integration.SetupDB(t) + testCtx = context.Background() + apiKeyExpiration = true + expirationPeriod = 30 + ) + + newVal, err := types.NewJSONBObject(map[string]any{"enabled": apiKeyExpiration, "expiration_period": expirationPeriod}) + require.Nil(t, err) + + require.Nil(t, db.SetConfigurationParameter(testCtx, appcfg.Parameter{ + Key: appcfg.APITokenExpiration, + Value: newVal, + })) + + valObtained := appcfg.GetAPITokenExpirationParameter(testCtx, db) + + require.Equal(t, apiKeyExpiration, valObtained.Enabled) + require.Equal(t, expirationPeriod, valObtained.ExpirationPeriod) +} diff --git a/cmd/api/src/model/appcfg/parameter.go b/cmd/api/src/model/appcfg/parameter.go index 1201de99b8a..093e0042ddc 100644 --- a/cmd/api/src/model/appcfg/parameter.go +++ b/cmd/api/src/model/appcfg/parameter.go @@ -43,6 +43,7 @@ const ( PruneTTL ParameterKey = "prune.ttl" ReconciliationKey ParameterKey = "analysis.reconciliation" ScheduledAnalysis ParameterKey = "analysis.scheduled" + APITokenExpiration ParameterKey = "auth.api_token_expiration" // The below keys are not intended to be user updatable, so should not be added to IsValidKey TrustedProxiesConfig ParameterKey = "http.trusted_proxies" @@ -90,7 +91,7 @@ func (s *Parameter) Map(value any) error { func (s *Parameter) IsValidKey(parameterKey ParameterKey) bool { switch parameterKey { - case PasswordExpirationWindow, Neo4jConfigs, PruneTTL, CitrixRDPSupportKey, ReconciliationKey, ScheduledAnalysis: + case PasswordExpirationWindow, Neo4jConfigs, PruneTTL, CitrixRDPSupportKey, ReconciliationKey, ScheduledAnalysis, APITokenExpiration: return true default: return false @@ -151,6 +152,8 @@ func (s *Parameter) Validate() utils.Errors { v = &TimeoutLimitParameter{} case EnvironmentTargetedAccessControlKey: v = &EnvironmentTargetedAccessControlParameters{} + case APITokenExpiration: + v = &APITokenExpirationParameter{} default: return utils.Errors{errors.New("invalid key")} } @@ -577,3 +580,27 @@ func GetEnvironmentTargetedAccessControlParameters(ctx context.Context, service return result } + +type APITokenExpirationParameter struct { + Enabled bool `json:"enabled"` + ExpirationPeriod int `json:"expiration_period" validate:"min=1,max=365"` +} + +func GetAPITokenExpirationParameter(ctx context.Context, service ParameterService) APITokenExpirationParameter { + result := APITokenExpirationParameter{Enabled: false, ExpirationPeriod: 90} + + if cfg, err := service.GetConfigurationParameter(ctx, APITokenExpiration); err != nil { + slog.WarnContext(ctx, "Failed to fetch API tokens expiration configuration; returning default values.") + } else if err := cfg.Map(&result); err != nil { + slog.WarnContext(ctx, "Invalid API tokens expiration configuration supplied, returning default values.", + slog.String("invalid_configuration", err.Error()), + slog.String("parameter_key", string(APITokenExpiration))) + } else if result.ExpirationPeriod <= 0 || result.ExpirationPeriod > 365 { + slog.WarnContext(ctx, "Invalid API token expiration period supplied, returning default values.", + slog.Int("invalid_expiration_period", result.ExpirationPeriod), + slog.String("parameter_key", string(APITokenExpiration))) + result.ExpirationPeriod = 90 + } + + return result +}