Nityananda Gohain 0a2b7ca1d8
chore(auth): refactor the auth modules and handler in preparation for multi tenant login (#7778)
* chore: update auth

* chore: password changes

* chore: make changes in oss code

* chore: login

* chore: get to a running state

* fix: migration inital commit

* fix: signoz cloud intgtn tests

* fix: minor fixes

* chore: sso code fixed with org domain

* fix: tests

* fix: ee auth api's

* fix: changes in name

* fix: return user in login api

* fix: address comments

* fix: validate password

* fix: handle get domain by email properly

* fix: move authomain to usermodule

* fix: use displayname instead of hname

* fix: rename back endpoints

* fix: update telemetry

* fix: correct errors

* fix: test and fix the invite endpoints

* fix: delete all things related to user in store

* fix: address issues

* fix: ee delete invite

* fix: rename func

* fix: update user and update role

* fix: update role

* fix: login and invite changes

* fix: return org name in users response

* fix: update user role

* fix: nil check

* fix: getinvite and update role

* fix: sso

* fix: getinvite use sso ctx

* fix: use correct sourceurl

* fix: getsourceurl from req payload

* fix: update created_at

* fix: fix reset password

* fix: sso signup and token password change

* fix: don't delete last admin

* fix: reset password and migration

* fix: migration

* fix: reset password for sso users

* fix: clean up invite

* fix: migration

* fix: update claims and store code

* fix: use correct error

* fix: proper nil checks

* fix: make migration multitenant

* fix: address comments

* fix: minor fixes

* fix: test

* fix: rename reset password

---------

Co-authored-by: Vikrant Gupta <vikrant@signoz.io>
2025-05-14 23:12:55 +05:30

321 lines
10 KiB
Go

package cloudintegrations
import (
"context"
"testing"
"github.com/SigNoz/signoz/pkg/modules/organization"
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
"github.com/SigNoz/signoz/pkg/modules/user"
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
"github.com/SigNoz/signoz/pkg/query-service/model"
"github.com/SigNoz/signoz/pkg/query-service/utils"
"github.com/SigNoz/signoz/pkg/types"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)
func TestRegenerateConnectionUrlWithUpdatedConfig(t *testing.T) {
require := require.New(t)
sqlStore := utils.NewQueryServiceDBForTests(t)
controller, err := NewController(sqlStore)
require.NoError(err)
organizationModule := implorganization.NewModule(implorganization.NewStore(sqlStore))
userModule := impluser.NewModule(impluser.NewStore(sqlStore))
user, apiErr := createTestUser(organizationModule, userModule)
require.Nil(apiErr)
// should be able to generate connection url for
// same account id again with updated config
testAccountConfig1 := types.AccountConfig{EnabledRegions: []string{"us-east-1", "us-west-1"}}
resp1, apiErr := controller.GenerateConnectionUrl(
context.TODO(), user.OrgID, "aws", GenerateConnectionUrlRequest{
AccountConfig: testAccountConfig1,
AgentConfig: SigNozAgentConfig{Region: "us-east-2"},
},
)
require.Nil(apiErr)
require.NotEmpty(resp1.ConnectionUrl)
require.NotEmpty(resp1.AccountId)
testAccountId := resp1.AccountId
account, apiErr := controller.accountsRepo.get(
context.TODO(), user.OrgID, "aws", testAccountId,
)
require.Nil(apiErr)
require.Equal(testAccountConfig1, *account.Config)
testAccountConfig2 := types.AccountConfig{EnabledRegions: []string{"us-east-2", "us-west-2"}}
resp2, apiErr := controller.GenerateConnectionUrl(
context.TODO(), user.OrgID, "aws", GenerateConnectionUrlRequest{
AccountId: &testAccountId,
AccountConfig: testAccountConfig2,
AgentConfig: SigNozAgentConfig{Region: "us-east-2"},
},
)
require.Nil(apiErr)
require.Equal(testAccountId, resp2.AccountId)
account, apiErr = controller.accountsRepo.get(
context.TODO(), user.OrgID, "aws", testAccountId,
)
require.Nil(apiErr)
require.Equal(testAccountConfig2, *account.Config)
}
func TestAgentCheckIns(t *testing.T) {
require := require.New(t)
sqlStore := utils.NewQueryServiceDBForTests(t)
controller, err := NewController(sqlStore)
require.NoError(err)
organizationModule := implorganization.NewModule(implorganization.NewStore(sqlStore))
userModule := impluser.NewModule(impluser.NewStore(sqlStore))
user, apiErr := createTestUser(organizationModule, userModule)
require.Nil(apiErr)
// An agent should be able to check in from a cloud account even
// if no connection url was requested (no account with agent's account id exists)
testAccountId1 := uuid.NewString()
testCloudAccountId1 := "546311234"
resp1, err := controller.CheckInAsAgent(
context.TODO(), user.OrgID, "aws", AgentCheckInRequest{
ID: testAccountId1,
AccountID: testCloudAccountId1,
},
)
require.Nil(err)
require.Equal(testAccountId1, resp1.AccountId)
require.Equal(testCloudAccountId1, resp1.CloudAccountId)
// The agent should not be able to check in with a different
// cloud account id for the same account.
testCloudAccountId2 := "99999999"
_, err = controller.CheckInAsAgent(
context.TODO(), user.OrgID, "aws", AgentCheckInRequest{
ID: testAccountId1,
AccountID: testCloudAccountId2,
},
)
require.NotNil(err)
// The agent should not be able to check-in with a particular cloud account id
// if another connected AccountRecord exists for same cloud account
// i.e. there can't be 2 connected account records for the same cloud account id
// at any point in time.
existingConnected, apiErr := controller.accountsRepo.getConnectedCloudAccount(
context.TODO(), user.OrgID, "aws", testCloudAccountId1,
)
require.Nil(apiErr)
require.NotNil(existingConnected)
require.Equal(testCloudAccountId1, *existingConnected.AccountID)
require.Nil(existingConnected.RemovedAt)
testAccountId2 := uuid.NewString()
_, err = controller.CheckInAsAgent(
context.TODO(), user.OrgID, "aws", AgentCheckInRequest{
ID: testAccountId2,
AccountID: testCloudAccountId1,
},
)
require.NotNil(err)
// After disconnecting existing account record, the agent should be able to
// connected for a particular cloud account id
_, _ = controller.DisconnectAccount(
context.TODO(), user.OrgID, "aws", testAccountId1,
)
existingConnected, apiErr = controller.accountsRepo.getConnectedCloudAccount(
context.TODO(), user.OrgID, "aws", testCloudAccountId1,
)
require.Nil(existingConnected)
require.NotNil(apiErr)
require.Equal(model.ErrorNotFound, apiErr.Type())
_, err = controller.CheckInAsAgent(
context.TODO(), user.OrgID, "aws", AgentCheckInRequest{
ID: testAccountId2,
AccountID: testCloudAccountId1,
},
)
require.Nil(err)
// should be able to keep checking in
_, err = controller.CheckInAsAgent(
context.TODO(), user.OrgID, "aws", AgentCheckInRequest{
ID: testAccountId2,
AccountID: testCloudAccountId1,
},
)
require.Nil(err)
}
func TestCantDisconnectNonExistentAccount(t *testing.T) {
require := require.New(t)
sqlStore := utils.NewQueryServiceDBForTests(t)
controller, err := NewController(sqlStore)
require.NoError(err)
organizationModule := implorganization.NewModule(implorganization.NewStore(sqlStore))
userModule := impluser.NewModule(impluser.NewStore(sqlStore))
user, apiErr := createTestUser(organizationModule, userModule)
require.Nil(apiErr)
// Attempting to disconnect a non-existent account should return error
account, apiErr := controller.DisconnectAccount(
context.TODO(), user.OrgID, "aws", uuid.NewString(),
)
require.NotNil(apiErr)
require.Equal(model.ErrorNotFound, apiErr.Type())
require.Nil(account)
}
func TestConfigureService(t *testing.T) {
require := require.New(t)
sqlStore := utils.NewQueryServiceDBForTests(t)
controller, err := NewController(sqlStore)
require.NoError(err)
organizationModule := implorganization.NewModule(implorganization.NewStore(sqlStore))
userModule := impluser.NewModule(impluser.NewStore(sqlStore))
user, apiErr := createTestUser(organizationModule, userModule)
require.Nil(apiErr)
// create a connected account
testCloudAccountId := "546311234"
testConnectedAccount := makeTestConnectedAccount(t, user.OrgID, controller, testCloudAccountId)
require.Nil(testConnectedAccount.RemovedAt)
require.NotEmpty(testConnectedAccount.AccountID)
require.Equal(testCloudAccountId, *testConnectedAccount.AccountID)
// should start out without any service config
svcListResp, apiErr := controller.ListServices(
context.TODO(), user.OrgID, "aws", &testCloudAccountId,
)
require.Nil(apiErr)
testSvcId := svcListResp.Services[0].Id
require.Nil(svcListResp.Services[0].Config)
svcDetails, err := controller.GetServiceDetails(
context.TODO(), user.OrgID, "aws", testSvcId, &testCloudAccountId,
)
require.Nil(err)
require.Equal(testSvcId, svcDetails.Id)
require.Nil(svcDetails.Config)
// should be able to configure a service for a connected account
testSvcConfig := types.CloudServiceConfig{
Metrics: &types.CloudServiceMetricsConfig{
Enabled: true,
},
}
updateSvcConfigResp, err := controller.UpdateServiceConfig(
context.TODO(), user.OrgID, "aws", testSvcId, &UpdateServiceConfigRequest{
CloudAccountId: testCloudAccountId,
Config: testSvcConfig,
},
)
require.Nil(err)
require.Equal(testSvcId, updateSvcConfigResp.Id)
require.Equal(testSvcConfig, updateSvcConfigResp.Config)
svcDetails, err = controller.GetServiceDetails(
context.TODO(), user.OrgID, "aws", testSvcId, &testCloudAccountId,
)
require.Nil(err)
require.Equal(testSvcId, svcDetails.Id)
require.Equal(testSvcConfig, *svcDetails.Config)
svcListResp, apiErr = controller.ListServices(
context.TODO(), user.OrgID, "aws", &testCloudAccountId,
)
require.Nil(apiErr)
for _, svc := range svcListResp.Services {
if svc.Id == testSvcId {
require.Equal(testSvcConfig, *svc.Config)
}
}
// should not be able to configure service after cloud account has been disconnected
_, apiErr = controller.DisconnectAccount(
context.TODO(), user.OrgID, "aws", testConnectedAccount.ID.StringValue(),
)
require.Nil(apiErr)
_, err = controller.UpdateServiceConfig(
context.TODO(), user.OrgID, "aws", testSvcId,
&UpdateServiceConfigRequest{
CloudAccountId: testCloudAccountId,
Config: testSvcConfig,
},
)
require.NotNil(err)
// should not be able to configure a service for a cloud account id that is not connected yet
_, err = controller.UpdateServiceConfig(
context.TODO(), user.OrgID, "aws", testSvcId,
&UpdateServiceConfigRequest{
CloudAccountId: "9999999999",
Config: testSvcConfig,
},
)
require.NotNil(err)
// should not be able to set config for an unsupported service
_, err = controller.UpdateServiceConfig(
context.TODO(), user.OrgID, "aws", "bad-service", &UpdateServiceConfigRequest{
CloudAccountId: testCloudAccountId,
Config: testSvcConfig,
},
)
require.NotNil(err)
}
func makeTestConnectedAccount(t *testing.T, orgId string, controller *Controller, cloudAccountId string) *types.CloudIntegration {
require := require.New(t)
// a check in from SigNoz agent creates or updates a connected account.
testAccountId := uuid.NewString()
resp, apiErr := controller.CheckInAsAgent(
context.TODO(), orgId, "aws", AgentCheckInRequest{
ID: testAccountId,
AccountID: cloudAccountId,
},
)
require.Nil(apiErr)
require.Equal(testAccountId, resp.AccountId)
require.Equal(cloudAccountId, resp.CloudAccountId)
acc, err := controller.accountsRepo.get(context.TODO(), orgId, "aws", resp.AccountId)
require.Nil(err)
return acc
}
func createTestUser(organizationModule organization.Module, userModule user.Module) (*types.User, *model.ApiError) {
// Create a test user for auth
ctx := context.Background()
organization := types.NewOrganization("test")
err := organizationModule.Create(ctx, organization)
if err != nil {
return nil, model.InternalError(err)
}
random, err := utils.RandomHex(3)
if err != nil {
return nil, model.InternalError(err)
}
user, err := types.NewUser("test", random+"test@test.com", types.RoleAdmin.String(), organization.ID.StringValue())
if err != nil {
return nil, model.InternalError(err)
}
err = userModule.CreateUser(ctx, user)
if err != nil {
return nil, model.InternalError(err)
}
return user, nil
}