From 9d58d8b584f0453c4ac72991c59a7ba3ce4651a6 Mon Sep 17 00:00:00 2001 From: Saranya Jena Date: Fri, 5 Jul 2024 15:14:07 +0530 Subject: [PATCH] Added support for jwt secret creation of each user upon user login (#4719) * Added support for jwt secret creation of each user upon logic Signed-off-by: Saranya-jena * Fixed imports Signed-off-by: Saranya-jena * Add fixes in dex service Signed-off-by: Saranya-jena * Fixed UTs Signed-off-by: Saranya-jena * resolved comments Signed-off-by: Saranya-jena * updated logic Signed-off-by: Saranya-jena * fixed UTs and removed unecessary test cases Signed-off-by: Saranya-jena * fixed imports Signed-off-by: Saranya-jena * fixed imports Signed-off-by: Saranya-jena * resolved comments Signed-off-by: Saranya-jena * fixed imports Signed-off-by: Saranya-jena * resolved comments Signed-off-by: Saranya-jena * added server endpoint in allowed origins Signed-off-by: Saranya-jena * fixed imports Signed-off-by: Saranya-jena * minor chnages Signed-off-by: Saranya-jena * minor chnages Signed-off-by: Saranya-jena * fixed imports Signed-off-by: Saranya-jena --------- Signed-off-by: Saranya-jena --- .../api/handlers/rest/dex_auth_handler.go | 10 ++- .../api/handlers/rest/user_handlers.go | 11 ++- .../api/handlers/rest/user_handlers_test.go | 6 +- .../authentication/api/handlers/salt.go | 44 ++++++++++ chaoscenter/authentication/api/main.go | 21 ++++- .../authentication/api/mocks/rest_mocks.go | 26 +++++- .../pkg/authConfig/repository.go | 67 +++++++++++++++ .../authentication/pkg/authConfig/schema.go | 6 ++ .../authentication/pkg/entities/user.go | 1 + .../pkg/services/application_service.go | 6 +- .../pkg/services/auth_config_service.go | 25 ++++++ .../pkg/services/session_service.go | 20 +++-- .../pkg/services/user_service.go | 8 ++ .../authentication/pkg/user/repository.go | 13 ++- .../authentication/pkg/utils/configs.go | 2 +- .../authentication/pkg/utils/sanitizers.go | 16 ++++ .../graphql/server/api/middleware/cors.go | 11 +++ .../graph/chaos_experiment.resolvers.go | 10 +-- .../graph/chaos_experiment_run.resolvers.go | 2 +- .../server/graph/environment.resolvers.go | 9 +- chaoscenter/graphql/server/graph/resolver.go | 10 ++- .../authorization/authorization_fuzz_test.go | 58 +------------ .../server/pkg/authorization/user_jwt.go | 14 +++- .../handler/fuzz_tests/handler_fuzz_test.go | 28 +------ .../pkg/chaos_experiment/handler/handler.go | 39 +++------ .../chaos_experiment/handler/handler_test.go | 34 +++----- .../chaos_experiment/model/mocks/service.go | 2 +- .../chaos_experiment_run/handler/handler.go | 15 ++-- .../model/mocks/service.go | 2 +- .../pkg/chaos_infrastructure/cluster_jwt.go | 18 +++- .../database/mongodb/authConfig/operations.go | 27 ++++++ .../pkg/database/mongodb/common_schema.go | 5 ++ .../mongodb/mocks/mongo_operations.go | 9 +- .../server/pkg/database/mongodb/operations.go | 22 +++++ .../handler/fuzz_tests/handler_fuzz_test.go | 8 +- .../server/pkg/environment/handler/handler.go | 35 ++------ .../pkg/environment/test/handler_test.go | 84 ++++++------------- chaoscenter/graphql/server/utils/variables.go | 1 - 38 files changed, 455 insertions(+), 270 deletions(-) create mode 100644 chaoscenter/authentication/api/handlers/salt.go create mode 100644 chaoscenter/authentication/pkg/authConfig/repository.go create mode 100644 chaoscenter/authentication/pkg/authConfig/schema.go create mode 100644 chaoscenter/authentication/pkg/services/auth_config_service.go create mode 100644 chaoscenter/graphql/server/pkg/database/mongodb/authConfig/operations.go diff --git a/chaoscenter/authentication/api/handlers/rest/dex_auth_handler.go b/chaoscenter/authentication/api/handlers/rest/dex_auth_handler.go index c950c52d020..4db79d9cf9a 100644 --- a/chaoscenter/authentication/api/handlers/rest/dex_auth_handler.go +++ b/chaoscenter/authentication/api/handlers/rest/dex_auth_handler.go @@ -138,7 +138,15 @@ func DexCallback(userService services.ApplicationService) gin.HandlerFunc { c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError)) return } - jwtToken, err := userService.GetSignedJWT(signedInUser) + + salt, err := userService.GetConfig("salt") + if err != nil { + log.Error(err) + c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError)) + return + } + + jwtToken, err := userService.GetSignedJWT(signedInUser, salt.Value) if err != nil { log.Error(err) c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError)) diff --git a/chaoscenter/authentication/api/handlers/rest/user_handlers.go b/chaoscenter/authentication/api/handlers/rest/user_handlers.go index 6b7336cfd19..a839c46f062 100644 --- a/chaoscenter/authentication/api/handlers/rest/user_handlers.go +++ b/chaoscenter/authentication/api/handlers/rest/user_handlers.go @@ -5,12 +5,11 @@ import ( "strings" "time" - "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/validations" - "github.com/litmuschaos/litmus/chaoscenter/authentication/api/presenter" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/services" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/utils" + "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/validations" "github.com/gin-gonic/gin" "github.com/google/uuid" @@ -305,7 +304,13 @@ func LoginUser(service services.ApplicationService) gin.HandlerFunc { return } - token, err := service.GetSignedJWT(user) + salt, err := service.GetConfig("salt") + if err != nil { + c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError)) + return + } + + token, err := service.GetSignedJWT(user, salt.Value) if err != nil { log.Error(err) c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError)) diff --git a/chaoscenter/authentication/api/handlers/rest/user_handlers_test.go b/chaoscenter/authentication/api/handlers/rest/user_handlers_test.go index bd9063d5db9..0f1d5696d1a 100644 --- a/chaoscenter/authentication/api/handlers/rest/user_handlers_test.go +++ b/chaoscenter/authentication/api/handlers/rest/user_handlers_test.go @@ -13,6 +13,8 @@ import ( "strings" "testing" + "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/authConfig" + "go.mongodb.org/mongo-driver/bson/primitive" "github.com/gin-gonic/gin" @@ -408,9 +410,11 @@ func TestLoginUser(t *testing.T) { Password: "hashedPassword", Email: "test@example.com", } + service.On("GetConfig", "salt").Return(&authConfig.AuthConfig{}, nil) service.On("FindUserByUsername", "testUser").Return(userFromDB, nil) service.On("CheckPasswordHash", "hashedPassword", "testPassword").Return(nil) - service.On("GetSignedJWT", userFromDB).Return("someJWTToken", nil) + service.On("UpdateUserByQuery", mock.Anything, mock.Anything).Return(nil) + service.On("GetSignedJWT", userFromDB, mock.Anything).Return("someJWTToken", nil) project := &entities.Project{ ID: "someProjectID", } diff --git a/chaoscenter/authentication/api/handlers/salt.go b/chaoscenter/authentication/api/handlers/salt.go new file mode 100644 index 00000000000..1373d7632f0 --- /dev/null +++ b/chaoscenter/authentication/api/handlers/salt.go @@ -0,0 +1,44 @@ +package response + +import ( + "encoding/base64" + + "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/authConfig" + "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/services" + "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/utils" + log "github.com/sirupsen/logrus" + "go.mongodb.org/mongo-driver/mongo" +) + +func AddSalt(service services.ApplicationService) error { + // generate salt and add/update to user collection + // pass the salt in the below func which will act as jwt secret + getSalt, err := service.GetConfig("salt") + if err != nil && err != mongo.ErrNoDocuments { + log.Error(err) + return err + } + if getSalt != nil { + return nil + } + + salt, err := utils.RandomString(6) + if err != nil { + log.Error(err) + return err + } + encodedSalt := base64.StdEncoding.EncodeToString([]byte(salt)) + + config := authConfig.AuthConfig{ + Key: "salt", + Value: encodedSalt, + } + + err = service.CreateConfig(config) + if err != nil { + log.Error(err) + return err + } + + return nil +} diff --git a/chaoscenter/authentication/api/main.go b/chaoscenter/authentication/api/main.go index 42fa9512290..b0bffcd41d6 100644 --- a/chaoscenter/authentication/api/main.go +++ b/chaoscenter/authentication/api/main.go @@ -7,6 +7,9 @@ import ( "runtime" "time" + response "github.com/litmuschaos/litmus/chaoscenter/authentication/api/handlers" + "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/authConfig" + grpcHandler "github.com/litmuschaos/litmus/chaoscenter/authentication/api/handlers/grpc" "github.com/litmuschaos/litmus/chaoscenter/authentication/api/middleware" grpcPresenter "github.com/litmuschaos/litmus/chaoscenter/authentication/api/presenter/protos" @@ -82,6 +85,12 @@ func main() { log.Errorf("failed to create collection %s", err) } + // Creating AuthConfig Collection + err = utils.CreateCollection(utils.AuthConfigCollection, db) + if err != nil { + log.Errorf("failed to create collection %s", err) + } + // Creating RevokedToken Collection if err = utils.CreateCollection(utils.RevokedTokenCollection, db); err != nil { log.Errorf("failed to create collection %s", err) @@ -108,9 +117,17 @@ func main() { apiTokenCollection := db.Collection(utils.ApiTokenCollection) apiTokenRepo := session.NewApiTokenRepo(apiTokenCollection) + authConfigCollection := db.Collection(utils.AuthConfigCollection) + authConfigRepo := authConfig.NewAuthConfigRepo(authConfigCollection) + miscRepo := misc.NewRepo(db, client) - applicationService := services.NewService(userRepo, projectRepo, miscRepo, revokedTokenRepo, apiTokenRepo, db) + applicationService := services.NewService(userRepo, projectRepo, miscRepo, revokedTokenRepo, apiTokenRepo, authConfigRepo, db) + + err = response.AddSalt(applicationService) + if err != nil { + log.Fatal("couldn't create salt $s", err) + } validatedAdminSetup(applicationService) @@ -163,10 +180,10 @@ func runRestServer(applicationService services.ApplicationService) { if utils.DexEnabled { routes.DexRouter(app, applicationService) } + routes.CapabilitiesRouter(app) routes.MiscRouter(app, applicationService) routes.UserRouter(app, applicationService) routes.ProjectRouter(app, applicationService) - routes.CapabilitiesRouter(app) log.Infof("Listening and serving HTTP on %s", utils.Port) err := app.Run(utils.Port) diff --git a/chaoscenter/authentication/api/mocks/rest_mocks.go b/chaoscenter/authentication/api/mocks/rest_mocks.go index 80218864b50..10d947c976c 100644 --- a/chaoscenter/authentication/api/mocks/rest_mocks.go +++ b/chaoscenter/authentication/api/mocks/rest_mocks.go @@ -3,6 +3,8 @@ package mocks import ( "context" + "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/authConfig" + "github.com/golang-jwt/jwt" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities" "github.com/stretchr/testify/mock" @@ -70,6 +72,11 @@ func (m *MockedApplicationService) UpdateUser(user *entities.UserDetails) error return args.Error(0) } +func (m *MockedApplicationService) UpdateUserByQuery(filter bson.D, updateQuery bson.D) error { + args := m.Called(filter, updateQuery) + return args.Error(0) +} + func (m *MockedApplicationService) UpdateUserState(ctx context.Context, username string, isDeactivate bool, deactivateTime int64) error { args := m.Called(ctx, username, isDeactivate, deactivateTime) return args.Error(0) @@ -160,8 +167,8 @@ func (m *MockedApplicationService) ValidateToken(encodedToken string) (*jwt.Toke return args.Get(0).(*jwt.Token), args.Error(1) } -func (m *MockedApplicationService) GetSignedJWT(user *entities.User) (string, error) { - args := m.Called(user) +func (m *MockedApplicationService) GetSignedJWT(user *entities.User, jwtSecret string) (string, error) { + args := m.Called(user, jwtSecret) return args.String(0), args.Error(1) } @@ -199,3 +206,18 @@ func (m *MockedApplicationService) RbacValidator(userID, resourceID string, rule args := m.Called(userID, resourceID, rules, invitationStatus) return args.Error(0) } + +func (m *MockedApplicationService) CreateConfig(config authConfig.AuthConfig) error { + args := m.Called(config) + return args.Error(0) +} + +func (m *MockedApplicationService) GetConfig(key string) (*authConfig.AuthConfig, error) { + args := m.Called(key) + return args.Get(0).(*authConfig.AuthConfig), args.Error(1) +} + +func (m *MockedApplicationService) UpdateConfig(ctx context.Context, key string, value interface{}) error { + args := m.Called(ctx, key, value) + return args.Error(0) +} diff --git a/chaoscenter/authentication/pkg/authConfig/repository.go b/chaoscenter/authentication/pkg/authConfig/repository.go new file mode 100644 index 00000000000..0156f4b6a5f --- /dev/null +++ b/chaoscenter/authentication/pkg/authConfig/repository.go @@ -0,0 +1,67 @@ +package authConfig + +import ( + "context" + "encoding/base64" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type Repository interface { + CreateConfig(config AuthConfig) error + GetConfig(key string) (*AuthConfig, error) + UpdateConfig(ctx context.Context, key string, value interface{}) error +} + +type repository struct { + Collection *mongo.Collection +} + +func (r repository) CreateConfig(config AuthConfig) error { + _, err := r.Collection.InsertOne(context.Background(), config) + if err != nil { + return err + } + + return nil +} + +func (r repository) GetConfig(key string) (*AuthConfig, error) { + results := r.Collection.FindOne(context.Background(), bson.D{ + {"key", key}, + }) + + var config AuthConfig + err := results.Decode(&config) + if err != nil { + return nil, err + } + decodedValue, err := base64.URLEncoding.DecodeString(config.Value) + if err != nil { + return nil, err + } + config.Value = string(decodedValue) + return &config, nil +} + +func (r repository) UpdateConfig(ctx context.Context, key string, value interface{}) error { + query := bson.D{ + {"key", key}, + } + update := bson.D{{"$set", bson.D{{ + "value", value}}, + }} + _, err := r.Collection.UpdateOne(ctx, query, update) + if err != nil { + return err + } + return nil +} + +// NewAuthConfigRepo creates a new instance of this repository +func NewAuthConfigRepo(collection *mongo.Collection) Repository { + return &repository{ + Collection: collection, + } +} diff --git a/chaoscenter/authentication/pkg/authConfig/schema.go b/chaoscenter/authentication/pkg/authConfig/schema.go new file mode 100644 index 00000000000..84b79fca12a --- /dev/null +++ b/chaoscenter/authentication/pkg/authConfig/schema.go @@ -0,0 +1,6 @@ +package authConfig + +type AuthConfig struct { + Key string `bson:"key"` + Value string `bson:"value"` +} diff --git a/chaoscenter/authentication/pkg/entities/user.go b/chaoscenter/authentication/pkg/entities/user.go index de01b45ae7f..a3bcd5285a9 100644 --- a/chaoscenter/authentication/pkg/entities/user.go +++ b/chaoscenter/authentication/pkg/entities/user.go @@ -21,6 +21,7 @@ type User struct { ID string `bson:"_id,omitempty" json:"userID"` Username string `bson:"username,omitempty" json:"username"` Password string `bson:"password,omitempty" json:"password,omitempty"` + Salt string `bson:"salt" json:"salt"` Email string `bson:"email,omitempty" json:"email,omitempty"` Name string `bson:"name,omitempty" json:"name,omitempty"` Role Role `bson:"role,omitempty" json:"role"` diff --git a/chaoscenter/authentication/pkg/services/application_service.go b/chaoscenter/authentication/pkg/services/application_service.go index b49c09a82b4..daef00316b5 100644 --- a/chaoscenter/authentication/pkg/services/application_service.go +++ b/chaoscenter/authentication/pkg/services/application_service.go @@ -1,6 +1,7 @@ package services import ( + authConfig2 "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/authConfig" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/misc" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/project" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/session" @@ -14,6 +15,7 @@ type ApplicationService interface { transactionService miscService sessionService + authConfigService } type applicationService struct { @@ -22,17 +24,19 @@ type applicationService struct { miscRepository misc.Repository revokedTokenRepository session.RevokedTokenRepository apiTokenRepository session.ApiTokenRepository + authConfigRepo authConfig2.Repository db *mongo.Database } // NewService creates a new instance of this service -func NewService(userRepo user.Repository, projectRepo project.Repository, miscRepo misc.Repository, revokedTokenRepo session.RevokedTokenRepository, apiTokenRepo session.ApiTokenRepository, db *mongo.Database) ApplicationService { +func NewService(userRepo user.Repository, projectRepo project.Repository, miscRepo misc.Repository, revokedTokenRepo session.RevokedTokenRepository, apiTokenRepo session.ApiTokenRepository, authConfigRepo authConfig2.Repository, db *mongo.Database) ApplicationService { return &applicationService{ userRepository: userRepo, projectRepository: projectRepo, revokedTokenRepository: revokedTokenRepo, apiTokenRepository: apiTokenRepo, db: db, + authConfigRepo: authConfigRepo, miscRepository: miscRepo, } } diff --git a/chaoscenter/authentication/pkg/services/auth_config_service.go b/chaoscenter/authentication/pkg/services/auth_config_service.go new file mode 100644 index 00000000000..6bb6eb16386 --- /dev/null +++ b/chaoscenter/authentication/pkg/services/auth_config_service.go @@ -0,0 +1,25 @@ +package services + +import ( + "context" + + "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/authConfig" +) + +type authConfigService interface { + CreateConfig(config authConfig.AuthConfig) error + GetConfig(key string) (*authConfig.AuthConfig, error) + UpdateConfig(ctx context.Context, key string, value interface{}) error +} + +func (a applicationService) CreateConfig(config authConfig.AuthConfig) error { + return a.authConfigRepo.CreateConfig(config) +} + +func (a applicationService) GetConfig(key string) (*authConfig.AuthConfig, error) { + return a.authConfigRepo.GetConfig(key) +} + +func (a applicationService) UpdateConfig(ctx context.Context, key string, value interface{}) error { + return a.authConfigRepo.UpdateConfig(ctx, key, value) +} diff --git a/chaoscenter/authentication/pkg/services/session_service.go b/chaoscenter/authentication/pkg/services/session_service.go index 27f9d3814ff..d2643fa48e6 100644 --- a/chaoscenter/authentication/pkg/services/session_service.go +++ b/chaoscenter/authentication/pkg/services/session_service.go @@ -14,7 +14,7 @@ import ( type sessionService interface { RevokeToken(tokenString string) error ValidateToken(encodedToken string) (*jwt.Token, error) - GetSignedJWT(user *entities.User) (string, error) + GetSignedJWT(user *entities.User, jwtSecret string) (string, error) CreateApiToken(user *entities.User, request entities.ApiTokenInput) (string, error) GetApiTokensByUserID(userID string) ([]entities.ApiToken, error) DeleteApiToken(token string) error @@ -58,12 +58,17 @@ func (a applicationService) parseToken(encodedToken string) (*jwt.Token, error) if _, isValid := token.Method.(*jwt.SigningMethodHMAC); !isValid { return nil, fmt.Errorf("invalid token %s", token.Header["alg"]) } - return []byte(utils.JwtSecret), nil + salt, err := a.GetConfig("salt") + if err != nil { + log.Error(err) + return nil, fmt.Errorf("couldn't fetch jwt secret %v", err) + } + return []byte(salt.Value), nil }) } // GetSignedJWT generates the JWT Token for the user object -func (a applicationService) GetSignedJWT(user *entities.User) (string, error) { +func (a applicationService) GetSignedJWT(user *entities.User, jwtSecret string) (string, error) { token := jwt.New(jwt.SigningMethodHS512) claims := token.Claims.(jwt.MapClaims) claims["uid"] = user.ID @@ -71,7 +76,7 @@ func (a applicationService) GetSignedJWT(user *entities.User) (string, error) { claims["username"] = user.Username claims["exp"] = time.Now().Add(time.Minute * time.Duration(utils.JWTExpiryDuration)).Unix() - tokenString, err := token.SignedString([]byte(utils.JwtSecret)) + tokenString, err := token.SignedString([]byte(jwtSecret)) if err != nil { log.Error(err) return "", err @@ -90,7 +95,12 @@ func (a applicationService) CreateApiToken(user *entities.User, request entities claims["username"] = user.Username claims["exp"] = expiresAt - tokenString, err := token.SignedString([]byte(utils.JwtSecret)) + salt, err := a.GetConfig("salt") + if err != nil { + log.Error(err) + return "", fmt.Errorf("couldn't fetch jwt secret %v", err) + } + tokenString, err := token.SignedString([]byte(salt.Value)) if err != nil { log.Error(err) return "", err diff --git a/chaoscenter/authentication/pkg/services/user_service.go b/chaoscenter/authentication/pkg/services/user_service.go index 72fd2da41b3..9a26465ef7c 100644 --- a/chaoscenter/authentication/pkg/services/user_service.go +++ b/chaoscenter/authentication/pkg/services/user_service.go @@ -3,6 +3,8 @@ package services import ( "context" + "go.mongodb.org/mongo-driver/bson" + "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities" ) @@ -17,6 +19,7 @@ type userService interface { UpdatePassword(userPassword *entities.UserPassword, isAdminBeingReset bool) error CreateUser(user *entities.User) (*entities.User, error) UpdateUser(user *entities.UserDetails) error + UpdateUserByQuery(filter bson.D, updateQuery bson.D) error IsAdministrator(user *entities.User) error UpdateUserState(ctx context.Context, username string, isDeactivate bool, deactivateTime int64) error InviteUsers(invitedUsers []string) (*[]entities.User, error) @@ -67,6 +70,11 @@ func (a applicationService) UpdateUser(user *entities.UserDetails) error { return a.userRepository.UpdateUser(user) } +// UpdateUserByQuery updates user details in the database +func (a applicationService) UpdateUserByQuery(filter bson.D, updateQuery bson.D) error { + return a.userRepository.UpdateUserByQuery(filter, updateQuery) +} + // IsAdministrator verifies if the passed user is an administrator func (a applicationService) IsAdministrator(user *entities.User) error { return a.userRepository.IsAdministrator(user) diff --git a/chaoscenter/authentication/pkg/user/repository.go b/chaoscenter/authentication/pkg/user/repository.go index ca0352d3d98..2782826609c 100644 --- a/chaoscenter/authentication/pkg/user/repository.go +++ b/chaoscenter/authentication/pkg/user/repository.go @@ -26,6 +26,7 @@ type Repository interface { UpdatePassword(userPassword *entities.UserPassword, isAdminBeingReset bool) error CreateUser(user *entities.User) (*entities.User, error) UpdateUser(user *entities.UserDetails) error + UpdateUserByQuery(filter bson.D, updateQuery bson.D) error IsAdministrator(user *entities.User) error UpdateUserState(ctx context.Context, username string, isDeactivate bool, deactivateTime int64) error InviteUsers(invitedUsers []string) (*[]entities.User, error) @@ -222,10 +223,20 @@ func (r repository) CreateUser(user *entities.User) (*entities.User, error) { return user.SanitizedUser(), nil } +// UpdateUserByQuery updates user details in the database +func (r repository) UpdateUserByQuery(filter bson.D, updateQuery bson.D) error { + _, err := r.Collection.UpdateOne(context.Background(), filter, updateQuery) + if err != nil { + return err + } + + return nil +} + // UpdateUser updates user details in the database func (r repository) UpdateUser(user *entities.UserDetails) error { data, _ := toDoc(user) - _, err := r.Collection.UpdateOne(context.Background(), bson.M{"_id": user.ID}, bson.M{"$set": data}) + _, err := r.Collection.UpdateMany(context.Background(), bson.M{"_id": user.ID}, bson.M{"$set": data}) if err != nil { return err } diff --git a/chaoscenter/authentication/pkg/utils/configs.go b/chaoscenter/authentication/pkg/utils/configs.go index 5e54c224869..252e5a3b67c 100644 --- a/chaoscenter/authentication/pkg/utils/configs.go +++ b/chaoscenter/authentication/pkg/utils/configs.go @@ -6,7 +6,6 @@ import ( ) var ( - JwtSecret = os.Getenv("JWT_SECRET") AdminName = os.Getenv("ADMIN_USERNAME") AdminPassword = os.Getenv("ADMIN_PASSWORD") DBUrl = os.Getenv("DB_SERVER") @@ -26,6 +25,7 @@ var ( GrpcPort = ":3030" UserCollection = "users" ProjectCollection = "project" + AuthConfigCollection = "auth-config" RevokedTokenCollection = "revoked-token" ApiTokenCollection = "api-token" UsernameField = "username" diff --git a/chaoscenter/authentication/pkg/utils/sanitizers.go b/chaoscenter/authentication/pkg/utils/sanitizers.go index c21bfdd9ce3..df9c4d936a0 100644 --- a/chaoscenter/authentication/pkg/utils/sanitizers.go +++ b/chaoscenter/authentication/pkg/utils/sanitizers.go @@ -1,6 +1,8 @@ package utils import ( + crypto "crypto/rand" + "encoding/base64" "fmt" "regexp" "strings" @@ -47,6 +49,20 @@ func ValidateStrictPassword(input string) error { return nil } +// RandomString generates random strings, can be used to create ids +func RandomString(n int) (string, error) { + if n > 0 { + b := make([]byte, n) + _, err := crypto.Read(b) + if err != nil { + return "", err + } + + return base64.URLEncoding.EncodeToString(b), nil + } + return "", fmt.Errorf("length should be greater than 0") +} + // Username must start with a letter - ^[a-zA-Z] // Allow letters, digits, underscores, and hyphens - [a-zA-Z0-9_-] // Ensure the length of the username is between 3 and 16 characters (1 character is already matched above) - {2,15}$ diff --git a/chaoscenter/graphql/server/api/middleware/cors.go b/chaoscenter/graphql/server/api/middleware/cors.go index 22323d764fe..9efff066dc0 100644 --- a/chaoscenter/graphql/server/api/middleware/cors.go +++ b/chaoscenter/graphql/server/api/middleware/cors.go @@ -5,6 +5,10 @@ import ( "regexp" "strings" + "github.com/sirupsen/logrus" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_infrastructure" + "github.com/gin-gonic/gin" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" ) @@ -25,6 +29,13 @@ func ValidateCors() gin.HandlerFunc { } validOrigin := false + endpoint, err := chaos_infrastructure.GetEndpoint("external") + if err != nil { + logrus.Error(err) + } else if endpoint != "" { + allowedOrigins = append(allowedOrigins, endpoint) + + } for _, allowedOrigin := range allowedOrigins { match, err := regexp.MatchString(allowedOrigin, origin) if err == nil && match { diff --git a/chaoscenter/graphql/server/graph/chaos_experiment.resolvers.go b/chaoscenter/graphql/server/graph/chaos_experiment.resolvers.go index 4f205d574dd..f3f20addbff 100644 --- a/chaoscenter/graphql/server/graph/chaos_experiment.resolvers.go +++ b/chaoscenter/graphql/server/graph/chaos_experiment.resolvers.go @@ -30,7 +30,7 @@ func (r *mutationResolver) CreateChaosExperiment(ctx context.Context, request mo return nil, err } - uiResponse, err := r.chaosExperimentHandler.CreateChaosExperiment(ctx, &request, projectID) + uiResponse, err := r.chaosExperimentHandler.CreateChaosExperiment(ctx, &request, projectID, ctx.Value("username").(string)) if err != nil { return nil, errors.New("could not create experiment, error: " + err.Error()) } @@ -83,7 +83,7 @@ func (r *mutationResolver) SaveChaosExperiment(ctx context.Context, request mode var uiResponse string - uiResponse, err = r.chaosExperimentHandler.SaveChaosExperiment(ctx, request, projectID, data_store.Store) + uiResponse, err = r.chaosExperimentHandler.SaveChaosExperiment(ctx, request, projectID, ctx.Value(authorization.AuthKey).(string)) if err != nil { logrus.WithFields(logFields).Error(err) return "", err @@ -107,7 +107,7 @@ func (r *mutationResolver) UpdateChaosExperiment(ctx context.Context, request mo return nil, err } - uiResponse, err := r.chaosExperimentHandler.UpdateChaosExperiment(ctx, request, projectID, data_store.Store) + uiResponse, err := r.chaosExperimentHandler.UpdateChaosExperiment(ctx, request, projectID, data_store.Store, ctx.Value(authorization.AuthKey).(string)) if err != nil { logrus.WithFields(logFields).Error(err) return nil, err @@ -132,7 +132,7 @@ func (r *mutationResolver) DeleteChaosExperiment(ctx context.Context, experiment return false, err } - uiResponse, err := r.chaosExperimentHandler.DeleteChaosExperiment(ctx, projectID, experimentID, experimentRunID, data_store.Store) + uiResponse, err := r.chaosExperimentHandler.DeleteChaosExperiment(ctx, projectID, experimentID, experimentRunID, data_store.Store, ctx.Value(authorization.AuthKey).(string)) if err != nil { logrus.WithFields(logFields).Error(err) return false, err @@ -156,7 +156,7 @@ func (r *mutationResolver) UpdateCronExperimentState(ctx context.Context, experi return false, err } - uiResponse, err := r.chaosExperimentHandler.UpdateCronExperimentState(ctx, experimentID, disable, projectID, data_store.Store) + uiResponse, err := r.chaosExperimentHandler.UpdateCronExperimentState(ctx, experimentID, disable, projectID, data_store.Store, ctx.Value(authorization.AuthKey).(string)) if err != nil { logrus.WithFields(logFields).Error(err) return false, err diff --git a/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go b/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go index dec85e6261d..d46940ff94d 100644 --- a/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go +++ b/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go @@ -73,7 +73,7 @@ func (r *mutationResolver) StopExperimentRuns(ctx context.Context, projectID str return false, err } - uiResponse, err := r.chaosExperimentHandler.StopExperimentRuns(ctx, projectID, experimentID, experimentRunID, data_store.Store) + uiResponse, err := r.chaosExperimentHandler.StopExperimentRuns(ctx, projectID, experimentID, experimentRunID, data_store.Store, "") if err != nil { logrus.WithFields(logFields).Error(err) return false, err diff --git a/chaoscenter/graphql/server/graph/environment.resolvers.go b/chaoscenter/graphql/server/graph/environment.resolvers.go index 1e3c2e2534d..1153df39cac 100644 --- a/chaoscenter/graphql/server/graph/environment.resolvers.go +++ b/chaoscenter/graphql/server/graph/environment.resolvers.go @@ -24,7 +24,8 @@ func (r *mutationResolver) CreateEnvironment(ctx context.Context, projectID stri if err != nil { return nil, err } - return r.environmentService.CreateEnvironment(ctx, projectID, request) + + return r.environmentService.CreateEnvironment(ctx, projectID, request, ctx.Value(authorization.AuthKey).(string)) } // UpdateEnvironment is the resolver for the updateEnvironment field. @@ -40,7 +41,8 @@ func (r *mutationResolver) UpdateEnvironment(ctx context.Context, projectID stri if err != nil { return "", err } - return r.environmentService.UpdateEnvironment(ctx, projectID, request) + + return r.environmentService.UpdateEnvironment(ctx, projectID, request, ctx.Value(authorization.AuthKey).(string)) } // DeleteEnvironment is the resolver for the deleteEnvironment field. @@ -56,7 +58,8 @@ func (r *mutationResolver) DeleteEnvironment(ctx context.Context, projectID stri if err != nil { return "", err } - return r.environmentService.DeleteEnvironment(ctx, projectID, environmentID) + + return r.environmentService.DeleteEnvironment(ctx, projectID, environmentID, ctx.Value(authorization.AuthKey).(string)) } // GetEnvironment is the resolver for the getEnvironment field. diff --git a/chaoscenter/graphql/server/graph/resolver.go b/chaoscenter/graphql/server/graph/resolver.go index 79a835b7100..d1002be76c6 100644 --- a/chaoscenter/graphql/server/graph/resolver.go +++ b/chaoscenter/graphql/server/graph/resolver.go @@ -3,6 +3,8 @@ package graph import ( "context" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/authConfig" + chaos_experiment2 "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment/ops" "github.com/99designs/gqlgen/graphql" @@ -84,11 +86,17 @@ func NewConfig(mongodbOperator mongodb.MongoOperator) generated.Config { config.Directives.Authorized = func(ctx context.Context, obj interface{}, next graphql.Resolver) (interface{}, error) { token := ctx.Value(authorization.AuthKey).(string) - user, err := authorization.UserValidateJWT(token) + salt, err := authConfig.NewAuthConfigOperator(mongodb.Operator).GetAuthConfig(context.Background()) + if err != nil { + return "", err + } + user, err := authorization.UserValidateJWT(token, salt.Value) if err != nil { return nil, err } newCtx := context.WithValue(ctx, authorization.UserClaim, user) + newCtx = context.WithValue(ctx, "username", user["username"]) + return next(newCtx) } diff --git a/chaoscenter/graphql/server/pkg/authorization/authorization_fuzz_test.go b/chaoscenter/graphql/server/pkg/authorization/authorization_fuzz_test.go index 8c62733fca4..2df965d780e 100644 --- a/chaoscenter/graphql/server/pkg/authorization/authorization_fuzz_test.go +++ b/chaoscenter/graphql/server/pkg/authorization/authorization_fuzz_test.go @@ -1,14 +1,12 @@ package authorization import ( - "encoding/base64" "fmt" "testing" "time" fuzz "github.com/AdaLogics/go-fuzz-headers" "github.com/golang-jwt/jwt" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" ) // generateExpiredFakeJWTToken generates a fake JWT token with expiration time set to the past @@ -37,59 +35,11 @@ func generateFakeJWTToken(username string) string { "username": username, "exp": time.Now().Add(time.Hour * 24).Unix(), // Set expiration time to 24 hours from now }) - - signedToken, _ := token.SignedString([]byte(utils.Config.JwtSecret)) // No signature is needed for testing + fakeSecret := "" + signedToken, _ := token.SignedString([]byte(fakeSecret)) // No signature is needed for testing return signedToken } -func FuzzGetUsername(f *testing.F) { - f.Fuzz(func(t *testing.T, input string) { - // Create a fake JWT token with predefined claims - - // Invalid token format check - _, err := GetUsername(input) - if err == nil { - t.Error("Expected error for invalid token format") - } - - // Generating fake jwt token for testing - token := generateFakeJWTToken(base64.StdEncoding.EncodeToString([]byte(input))) - - // Run the test with the fake JWT token - username, err := GetUsername(token) - if err != nil { - t.Errorf("Error encountered: %v", err) - } - - // Decode the username back from base64 - decodedUsername, err := base64.StdEncoding.DecodeString(username) - if err != nil { - t.Errorf("Error decoding username: %v", err) - } - - // Check if the decoded username matches the input string - if string(decodedUsername) != input { - t.Errorf("Expected username: %s, got: %s", input, username) - } - - // Additional checks - // Expiration check - expiredToken := generateExpiredFakeJWTToken(input) - _, err = GetUsername(expiredToken) - if err == nil { - t.Error("Expected error for expired token") - } - - // Token signature check (invalid secret key) - invalidSignatureToken := generateFakeJWTTokenWithInvalidSignature(input) - _, err = GetUsername(invalidSignatureToken) - if err == nil { - t.Error("Expected error for token with invalid signature") - } - - }) -} - // generateJWTToken generates a JWT token with the given claims func generateJWTTokenFromClaims(claims jwt.MapClaims) (string, error) { // Set expiration time to 24 hours from now @@ -99,7 +49,7 @@ func generateJWTTokenFromClaims(claims jwt.MapClaims) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // Sign the token with a secret key - tokenString, err := token.SignedString([]byte(utils.Config.JwtSecret)) + tokenString, err := token.SignedString([]byte("")) if err != nil { return "", fmt.Errorf("failed to sign JWT token: %v", err) } @@ -122,7 +72,7 @@ func FuzzUserValidateJWT(f *testing.F) { } // Run the test with the generated JWT token - claims, err := UserValidateJWT(tokenString) + claims, err := UserValidateJWT(tokenString, "") if err != nil { t.Errorf("Error encountered: %v", err) } diff --git a/chaoscenter/graphql/server/pkg/authorization/user_jwt.go b/chaoscenter/graphql/server/pkg/authorization/user_jwt.go index 90d81bf1e27..500dbf3ab15 100644 --- a/chaoscenter/graphql/server/pkg/authorization/user_jwt.go +++ b/chaoscenter/graphql/server/pkg/authorization/user_jwt.go @@ -1,22 +1,24 @@ package authorization import ( + "context" "errors" "fmt" "log" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/authConfig" "github.com/golang-jwt/jwt" ) // UserValidateJWT validates the cluster jwt -func UserValidateJWT(token string) (jwt.MapClaims, error) { +func UserValidateJWT(token string, salt string) (jwt.MapClaims, error) { tkn, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { if _, isValid := token.Method.(*jwt.SigningMethodHMAC); !isValid { return nil, fmt.Errorf("invalid token %s", token.Header["alg"]) } - return []byte(utils.Config.JwtSecret), nil + return []byte(salt), nil }) if err != nil { @@ -38,8 +40,12 @@ func UserValidateJWT(token string) (jwt.MapClaims, error) { // GetUsername returns the username from the jwt token func GetUsername(token string) (string, error) { + salt, err := authConfig.NewAuthConfigOperator(mongodb.Operator).GetAuthConfig(context.Background()) + if err != nil { + return "", err + } tkn, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { - return []byte(utils.Config.JwtSecret), nil + return []byte(salt.Value), nil }) if err != nil { diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/fuzz_tests/handler_fuzz_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/fuzz_tests/handler_fuzz_test.go index 7142db50481..707a85be553 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/fuzz_tests/handler_fuzz_test.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/fuzz_tests/handler_fuzz_test.go @@ -12,16 +12,13 @@ import ( dbGitOpsMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/gitops/model/mocks" fuzz "github.com/AdaLogics/go-fuzz-headers" - "github.com/golang-jwt/jwt" "github.com/google/uuid" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/authorization" store "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/data-store" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" dbChaosExperiment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment" dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" dbChoasInfra "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_infrastructure" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" "github.com/sirupsen/logrus" "github.com/stretchr/testify/mock" "go.mongodb.org/mongo-driver/bson" @@ -75,9 +72,7 @@ func FuzzSaveChaosExperiment(f *testing.F) { if err != nil { return } - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) ctx := context.Background() - ctx = context.WithValue(ctx, authorization.AuthKey, username) findResult := []interface{}{bson.D{ {Key: "experiment_id", Value: targetStruct.request.ID}, }} @@ -93,8 +88,7 @@ func FuzzSaveChaosExperiment(f *testing.F) { mockServices.ChaosExperimentService.On("ProcessExperimentUpdate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, false, mock.Anything, mock.Anything).Return(nil).Once() mockServices.GitOpsService.On("UpsertExperimentToGit", ctx, mock.Anything, mock.Anything).Return(nil).Once() - store := store.NewStore() - res, err := mockServices.ChaosExperimentHandler.SaveChaosExperiment(ctx, targetStruct.request, targetStruct.projectID, store) + res, err := mockServices.ChaosExperimentHandler.SaveChaosExperiment(ctx, targetStruct.request, targetStruct.projectID, "") if err != nil { t.Errorf("ChaosExperimentHandler.SaveChaosExperiment() error = %v", err) return @@ -119,9 +113,7 @@ func FuzzDeleteChaosExperiment(f *testing.F) { return } logrus.Info("here", targetStruct) - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) ctx := context.Background() - ctx = context.WithValue(ctx, authorization.AuthKey, username) findResult := []interface{}{bson.D{ {Key: "experiment_id", Value: targetStruct.experimentId}, {Key: "experiment_runs", Value: []*dbChaosExperimentRun.ChaosExperimentRun{ @@ -137,7 +129,7 @@ func FuzzDeleteChaosExperiment(f *testing.F) { mockServices.ChaosExperimentRunService.On("ProcessExperimentRunDelete", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() store := store.NewStore() - res, err := mockServices.ChaosExperimentHandler.DeleteChaosExperiment(ctx, targetStruct.projectID, targetStruct.experimentId, &targetStruct.experimentRunID, store) + res, err := mockServices.ChaosExperimentHandler.DeleteChaosExperiment(ctx, targetStruct.projectID, targetStruct.experimentId, &targetStruct.experimentRunID, store, "") if err != nil { t.Errorf("ChaosExperimentHandler.DeleteChaosExperiment() error = %v", err) return @@ -161,9 +153,7 @@ func FuzzUpdateChaosExperiment(f *testing.F) { return } experimentType := dbChaosExperiment.NonCronExperiment - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) ctx := context.Background() - ctx = context.WithValue(ctx, authorization.AuthKey, username) mockServices := NewMockServices() mockServices.MongodbOperator.On("CountDocuments", ctx, mongodb.ChaosExperimentCollection, mock.Anything, mock.Anything).Return(int64(0), nil).Once() mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&model.ChaosExperimentRequest{ @@ -174,7 +164,7 @@ func FuzzUpdateChaosExperiment(f *testing.F) { mockServices.ChaosExperimentService.On("ProcessExperimentUpdate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() mockServices.GitOpsService.On("UpsertExperimentToGit", ctx, mock.Anything, mock.Anything).Return(nil).Once() store := store.NewStore() - res, err := mockServices.ChaosExperimentHandler.UpdateChaosExperiment(ctx, targetStruct.experiment, targetStruct.projectID, store) + res, err := mockServices.ChaosExperimentHandler.UpdateChaosExperiment(ctx, targetStruct.experiment, targetStruct.projectID, store, "") if err != nil { t.Errorf("ChaosExperimentHandler.UpdateChaosExperiment() error = %v", err) return @@ -197,9 +187,7 @@ func FuzzGetExperiment(f *testing.F) { if err != nil { return } - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) ctx := context.Background() - ctx = context.WithValue(ctx, authorization.AuthKey, username) mockServices := NewMockServices() findResult := []interface{}{bson.D{ {Key: "project_id", Value: targetStruct.projectID}, @@ -244,9 +232,6 @@ func FuzzListExperiment(f *testing.F) { if err != nil { return } - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) - ctx := context.Background() - ctx = context.WithValue(ctx, authorization.AuthKey, username) mockServices := NewMockServices() findResult := []interface{}{ bson.D{ @@ -282,13 +267,8 @@ func FuzzDisableCronExperiment(f *testing.F) { if len(targetStruct.request.Revision) < 1 { return } - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) - ctx := context.Background() - ctx = context.WithValue(ctx, authorization.AuthKey, username) mockServices := NewMockServices() mockServices.ChaosExperimentService.On("ProcessExperimentUpdate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() - - err = mockServices.ChaosExperimentHandler.DisableCronExperiment(username, targetStruct.request, targetStruct.projectID, store.NewStore()) if err != nil { t.Errorf("ChaosExperimentHandler.DisableCronExperiment() error = %v", err) return @@ -309,9 +289,7 @@ func FuzzGetExperimentStats(f *testing.F) { return } - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) ctx := context.Background() - ctx = context.WithValue(ctx, authorization.AuthKey, username) mockServices := NewMockServices() findResult := []interface{}{ bson.D{ diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go index bbe7eb4850c..bd0502334a8 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go @@ -18,7 +18,6 @@ import ( dbSchemaProbe "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/probe" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/authorization" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_infrastructure" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/gitops" @@ -73,7 +72,7 @@ func NewChaosExperimentHandler( } } -func (c *ChaosExperimentHandler) SaveChaosExperiment(ctx context.Context, request model.SaveChaosExperimentRequest, projectID string, r *store.StateData) (string, error) { +func (c *ChaosExperimentHandler) SaveChaosExperiment(ctx context.Context, request model.SaveChaosExperimentRequest, projectID string, username string) (string, error) { var revID = uuid.New().String() @@ -106,11 +105,6 @@ func (c *ChaosExperimentHandler) SaveChaosExperiment(ctx context.Context, reques if err != nil { return "", err } - tkn := ctx.Value(authorization.AuthKey).(string) - username, err := authorization.GetUsername(tkn) - if err != nil { - return "", err - } // Updating the existing experiment if wfDetails.ExperimentID == request.ID { @@ -159,7 +153,7 @@ func (c *ChaosExperimentHandler) SaveChaosExperiment(ctx context.Context, reques return "experiment saved successfully", nil } -func (c *ChaosExperimentHandler) CreateChaosExperiment(ctx context.Context, request *model.ChaosExperimentRequest, projectID string) (*model.ChaosExperimentResponse, error) { +func (c *ChaosExperimentHandler) CreateChaosExperiment(ctx context.Context, request *model.ChaosExperimentRequest, projectID string, username string) (*model.ChaosExperimentResponse, error) { var revID = uuid.New().String() @@ -180,9 +174,7 @@ func (c *ChaosExperimentHandler) CreateChaosExperiment(ctx context.Context, requ return nil, err } - tkn := ctx.Value(authorization.AuthKey).(string) - uid, err := authorization.GetUsername(tkn) - err = c.chaosExperimentService.ProcessExperimentCreation(context.TODO(), newRequest, uid, projectID, wfType, revID, nil) + err = c.chaosExperimentService.ProcessExperimentCreation(context.TODO(), newRequest, username, projectID, wfType, revID, nil) if err != nil { return nil, err } @@ -196,7 +188,7 @@ func (c *ChaosExperimentHandler) CreateChaosExperiment(ctx context.Context, requ }, nil } -func (c *ChaosExperimentHandler) DeleteChaosExperiment(ctx context.Context, projectID string, workflowID string, workflowRunID *string, r *store.StateData) (bool, error) { +func (c *ChaosExperimentHandler) DeleteChaosExperiment(ctx context.Context, projectID string, workflowID string, workflowRunID *string, r *store.StateData, username string) (bool, error) { query := bson.D{ {"experiment_id", workflowID}, {"project_id", projectID}, @@ -212,14 +204,12 @@ func (c *ChaosExperimentHandler) DeleteChaosExperiment(ctx context.Context, proj if workflow.IsRemoved { return false, errors.New("chaos experiment already deleted: " + workflowID) } - tkn := ctx.Value(authorization.AuthKey).(string) - uid, err := authorization.GetUsername(tkn) // If workflowRunID is nil, delete the experiment and all its corresponding runs if workflowRunID == nil { if workflow.CronSyntax != "" { - err = c.DisableCronExperiment(uid, workflow, projectID, r) + err = c.DisableCronExperiment(username, workflow, projectID, r) if err != nil { return false, err } @@ -235,7 +225,7 @@ func (c *ChaosExperimentHandler) DeleteChaosExperiment(ctx context.Context, proj return false, err } // Delete experiment - err = c.chaosExperimentService.ProcessExperimentDelete(query, workflow, uid, r) + err = c.chaosExperimentService.ProcessExperimentDelete(query, workflow, username, r) if err != nil { return false, err } @@ -263,7 +253,7 @@ func (c *ChaosExperimentHandler) DeleteChaosExperiment(ctx context.Context, proj return false, err } - err = c.chaosExperimentRunService.ProcessExperimentRunDelete(ctx, query, workflowRunID, workflowRun, workflow, uid, r) + err = c.chaosExperimentRunService.ProcessExperimentRunDelete(ctx, query, workflowRunID, workflowRun, workflow, username, r) if err != nil { return false, err } @@ -272,7 +262,7 @@ func (c *ChaosExperimentHandler) DeleteChaosExperiment(ctx context.Context, proj return true, nil } -func (c *ChaosExperimentHandler) UpdateChaosExperiment(ctx context.Context, request model.ChaosExperimentRequest, projectID string, r *store.StateData) (*model.ChaosExperimentResponse, error) { +func (c *ChaosExperimentHandler) UpdateChaosExperiment(ctx context.Context, request model.ChaosExperimentRequest, projectID string, r *store.StateData, username string) (*model.ChaosExperimentResponse, error) { var ( revID = uuid.New().String() ) @@ -287,8 +277,6 @@ func (c *ChaosExperimentHandler) UpdateChaosExperiment(ctx context.Context, requ if err != nil { return nil, err } - tkn := ctx.Value(authorization.AuthKey).(string) - uid, err := authorization.GetUsername(tkn) err = c.gitOpsService.UpsertExperimentToGit(ctx, projectID, newRequest) if err != nil { @@ -296,7 +284,7 @@ func (c *ChaosExperimentHandler) UpdateChaosExperiment(ctx context.Context, requ return nil, err } - err = c.chaosExperimentService.ProcessExperimentUpdate(newRequest, uid, wfType, revID, false, projectID, r) + err = c.chaosExperimentService.ProcessExperimentUpdate(newRequest, username, wfType, revID, false, projectID, r) if err != nil { return nil, err } @@ -1372,7 +1360,7 @@ func (c *ChaosExperimentHandler) validateDuplicateExperimentName(ctx context.Con return nil } -func (c *ChaosExperimentHandler) UpdateCronExperimentState(ctx context.Context, workflowID string, disable bool, projectID string, r *store.StateData) (bool, error) { +func (c *ChaosExperimentHandler) UpdateCronExperimentState(ctx context.Context, workflowID string, disable bool, projectID string, r *store.StateData, username string) (bool, error) { var ( cronWorkflowManifest v1alpha1.CronWorkflow ) @@ -1420,8 +1408,6 @@ func (c *ChaosExperimentHandler) UpdateCronExperimentState(ctx context.Context, } //Update the revision in database - tkn := ctx.Value(authorization.AuthKey).(string) - username, err := authorization.GetUsername(tkn) err = c.chaosExperimentService.ProcessExperimentUpdate(&model.ChaosExperimentRequest{ ExperimentID: &workflowID, @@ -1465,13 +1451,10 @@ func (c *ChaosExperimentHandler) UpdateCronExperimentState(ctx context.Context, return true, err } -func (c *ChaosExperimentHandler) StopExperimentRuns(ctx context.Context, projectID string, experimentID string, experimentRunID *string, r *store.StateData) (bool, error) { +func (c *ChaosExperimentHandler) StopExperimentRuns(ctx context.Context, projectID string, experimentID string, experimentRunID *string, r *store.StateData, username string) (bool, error) { var experimentRunsID []string - tkn := ctx.Value(authorization.AuthKey).(string) - username, err := authorization.GetUsername(tkn) - query := bson.D{ {"experiment_id", experimentID}, {"project_id", projectID}, diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler_test.go index 655ae8c8acf..bb4ea2ff3c2 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler_test.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler_test.go @@ -22,7 +22,6 @@ import ( dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" dbGitOpsMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/gitops/model/mocks" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) @@ -77,14 +76,13 @@ func TestChaosExperimentHandler_SaveChaosExperiment(t *testing.T) { projectID string } - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) + username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte("")) ctx := context.Background() projectId := uuid.New().String() experimentId := uuid.New().String() experimentType := dbChaosExperiment.NonCronExperiment infraId := uuid.New().String() - store := store.NewStore() tests := []struct { name string args args @@ -206,7 +204,7 @@ func TestChaosExperimentHandler_SaveChaosExperiment(t *testing.T) { t.Run(tc.name, func(t *testing.T) { mockServices := NewMockServices() tc.given(tc.args.request2, mockServices) - _, err := mockServices.ChaosExperimentHandler.SaveChaosExperiment(ctx, tc.args.request, tc.args.projectID, store) + _, err := mockServices.ChaosExperimentHandler.SaveChaosExperiment(ctx, tc.args.request, tc.args.projectID, "") if (err != nil) != tc.wantErr { t.Errorf("ChaosExperimentHandler.SaveChaosExperiment() error = %v, wantErr %v", err, tc.wantErr) return @@ -234,7 +232,7 @@ func TestChaosExperimentHandler_CreateChaosExperiment(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockServices := NewMockServices() - got, err := mockServices.ChaosExperimentHandler.CreateChaosExperiment(tt.args.ctx, tt.args.request, tt.args.projectID) + got, err := mockServices.ChaosExperimentHandler.CreateChaosExperiment(tt.args.ctx, tt.args.request, tt.args.projectID, "") if (err != nil) != tt.wantErr { t.Errorf("ChaosExperimentHandler.CreateChaosExperiment() error = %v, wantErr %v", err, tt.wantErr) return @@ -247,7 +245,7 @@ func TestChaosExperimentHandler_CreateChaosExperiment(t *testing.T) { } func TestChaosExperimentHandler_DeleteChaosExperiment(t *testing.T) { - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) + username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte("")) ctx := context.TODO() projectId := uuid.New().String() experimentId := uuid.New().String() @@ -334,7 +332,7 @@ func TestChaosExperimentHandler_DeleteChaosExperiment(t *testing.T) { t.Run(tc.name, func(t *testing.T) { mockServices := NewMockServices() tc.given(mockServices) - _, err := mockServices.ChaosExperimentHandler.DeleteChaosExperiment(ctx, projectId, experimentId, &experimentRunID, store) + _, err := mockServices.ChaosExperimentHandler.DeleteChaosExperiment(ctx, projectId, experimentId, &experimentRunID, store, "") if (err != nil) != tc.wantErr { t.Errorf("ChaosExperimentHandler.DeleteChaosExperiment() error = %v, wantErr %v", err, tc.wantErr) return @@ -349,7 +347,6 @@ func TestChaosExperimentHandler_UpdateChaosExperiment(t *testing.T) { request *model.ChaosExperimentRequest projectID string } - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) ctx := context.Background() projectId := uuid.New().String() infraId := uuid.New().String() @@ -375,11 +372,10 @@ func TestChaosExperimentHandler_UpdateChaosExperiment(t *testing.T) { }, }, given: func(request *model.ChaosExperimentRequest, mockServices *MockServices) { - ctx = context.WithValue(ctx, authorization.AuthKey, username) - mockServices.MongodbOperator.On("CountDocuments", ctx, mongodb.ChaosExperimentCollection, mock.Anything, mock.Anything).Return(int64(0), nil).Once() + mockServices.MongodbOperator.On("CountDocuments", mock.Anything, mongodb.ChaosExperimentCollection, mock.Anything, mock.Anything).Return(int64(0), nil).Once() mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(request, &experimentType, nil).Once() mockServices.ChaosExperimentService.On("ProcessExperimentUpdate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() - mockServices.GitOpsService.On("UpsertExperimentToGit", ctx, mock.Anything, request).Return(nil).Once() + mockServices.GitOpsService.On("UpsertExperimentToGit", mock.Anything, mock.Anything, request).Return(nil).Once() }, wantErr: false, @@ -395,7 +391,6 @@ func TestChaosExperimentHandler_UpdateChaosExperiment(t *testing.T) { }, }, given: func(request *model.ChaosExperimentRequest, mockServices *MockServices) { - ctx = context.WithValue(ctx, authorization.AuthKey, username) mockServices.MongodbOperator.On("CountDocuments", ctx, mongodb.ChaosExperimentCollection, mock.Anything, mock.Anything).Return(int64(0), nil).Once() mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(request, &experimentType, errors.New("Incorrect request format")).Once() }, @@ -412,8 +407,6 @@ func TestChaosExperimentHandler_UpdateChaosExperiment(t *testing.T) { }, }, given: func(request *model.ChaosExperimentRequest, mockServices *MockServices) { - ctx = context.WithValue(ctx, authorization.AuthKey, username) - mockServices.MongodbOperator.On("CountDocuments", ctx, mongodb.ChaosExperimentCollection, mock.Anything, mock.Anything).Return(int64(0), nil).Once() mockServices.ChaosExperimentService.On("ProcessExperiment", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(request, &experimentType, nil).Once() @@ -429,7 +422,7 @@ func TestChaosExperimentHandler_UpdateChaosExperiment(t *testing.T) { t.Run(tc.name, func(t *testing.T) { mockServices := NewMockServices() tc.given(tc.args.request, mockServices) - _, err := mockServices.ChaosExperimentHandler.UpdateChaosExperiment(ctx, *tc.args.request, tc.args.projectID, store) + _, err := mockServices.ChaosExperimentHandler.UpdateChaosExperiment(ctx, *tc.args.request, tc.args.projectID, store, "") if (err != nil) != tc.wantErr { t.Errorf("ChaosExperimentHandler.UpdateChaosExperiment() error = %v, wantErr %v", err, tc.wantErr) return @@ -628,7 +621,7 @@ func TestChaosExperimentHandler_ListExperiment(t *testing.T) { } func TestChaosExperimentHandler_DisableCronExperiment(t *testing.T) { - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) + projectID := uuid.New().String() experimentID := uuid.New().String() infraID := uuid.New().String() @@ -666,7 +659,7 @@ func TestChaosExperimentHandler_DisableCronExperiment(t *testing.T) { t.Run(tc.name, func(t *testing.T) { mockServices := NewMockServices() tc.given(mockServices) - if err := mockServices.ChaosExperimentHandler.DisableCronExperiment(username, experimentRequest, projectID, store); (err != nil) != tc.wantErr { + if err := mockServices.ChaosExperimentHandler.DisableCronExperiment("", experimentRequest, projectID, store); (err != nil) != tc.wantErr { t.Errorf("ChaosExperimentHandler.DisableCronExperiment() error = %v, wantErr %v", err, tc.wantErr) } assertExpectations(mockServices, t) @@ -675,6 +668,7 @@ func TestChaosExperimentHandler_DisableCronExperiment(t *testing.T) { } func TestChaosExperimentHandler_GetExperimentStats(t *testing.T) { + ctx := context.Background() projectID := uuid.New().String() tests := []struct { @@ -685,8 +679,6 @@ func TestChaosExperimentHandler_GetExperimentStats(t *testing.T) { { name: "success: get experiment stats", given: func(mockServices *MockServices) { - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) - ctx = context.WithValue(ctx, authorization.AuthKey, username) findResult := []interface{}{ bson.D{ {Key: "project_id", Value: projectID}, @@ -700,8 +692,6 @@ func TestChaosExperimentHandler_GetExperimentStats(t *testing.T) { { name: "failure: empty cursor returned", given: func(mockServices *MockServices) { - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) - ctx = context.WithValue(ctx, authorization.AuthKey, username) cursor, _ := mongo.NewCursorFromDocuments(nil, nil, nil) mockServices.MongodbOperator.On("Aggregate", mock.Anything, mongodb.ChaosExperimentCollection, mock.Anything, mock.Anything).Return(cursor, errors.New("empty cursor returned")).Once() }, @@ -710,8 +700,6 @@ func TestChaosExperimentHandler_GetExperimentStats(t *testing.T) { { name: "failure: getting experiment stats", given: func(mockServices *MockServices) { - username, _ := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{"username": "test"}).SignedString([]byte(utils.Config.JwtSecret)) - ctx = context.WithValue(ctx, authorization.AuthKey, username) findResult := []interface{}{ bson.D{ {Key: "project_id", Value: projectID}, diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/service.go b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/service.go index b5b051f39aa..d872be1286c 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks/service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.42.0. DO NOT EDIT. package mocks diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/handler.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/handler.go index cb8db9c9f7d..21ebe1ce905 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/handler.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/handler.go @@ -787,8 +787,6 @@ func (c *ChaosExperimentRunHandler) RunChaosWorkFlow(ctx context.Context, projec return nil, err } - tkn := ctx.Value(authorization.AuthKey).(string) - username, err := authorization.GetUsername(tkn) var ( wc = writeconcern.New(writeconcern.WMajority()) rc = readconcern.Snapshot() @@ -817,11 +815,11 @@ func (c *ChaosExperimentRunHandler) RunChaosWorkFlow(ctx context.Context, projec IsRemoved: false, CreatedAt: currentTime, CreatedBy: mongodb.UserDetailResponse{ - Username: username, + Username: ctx.Value(authorization.AuthKey).(string), }, UpdatedAt: currentTime, UpdatedBy: mongodb.UserDetailResponse{ - Username: username, + Username: ctx.Value(authorization.AuthKey).(string), }, }, }, @@ -863,11 +861,11 @@ func (c *ChaosExperimentRunHandler) RunChaosWorkFlow(ctx context.Context, projec IsRemoved: false, CreatedAt: currentTime, CreatedBy: mongodb.UserDetailResponse{ - Username: username, + Username: ctx.Value(authorization.AuthKey).(string), }, UpdatedAt: currentTime, UpdatedBy: mongodb.UserDetailResponse{ - Username: username, + Username: ctx.Value(authorization.AuthKey).(string), }, }, NotifyID: ¬ifyID, @@ -910,7 +908,7 @@ func (c *ChaosExperimentRunHandler) RunChaosWorkFlow(ctx context.Context, projec if err != nil { return nil, fmt.Errorf("failed to generate probes in workflow manifest, err: %v", err) } - + username := ctx.Value(authorization.AuthKey).(string) manifest, err := yaml.Marshal(workflowManifest) if err != nil { return nil, err @@ -993,8 +991,7 @@ func (c *ChaosExperimentRunHandler) RunCronExperiment(ctx context.Context, proje return err } - tkn := ctx.Value(authorization.AuthKey).(string) - username, err := authorization.GetUsername(tkn) + username := ctx.Value(authorization.AuthKey).(string) if r != nil { chaos_infrastructure.SendExperimentToSubscriber(projectID, &model.ChaosExperimentRequest{ diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks/service.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks/service.go index b0293d32c0c..a483d874c6e 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks/service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.42.0. DO NOT EDIT. package mocks diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/cluster_jwt.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/cluster_jwt.go index c88ced52c64..bb001e80c44 100644 --- a/chaoscenter/graphql/server/pkg/chaos_infrastructure/cluster_jwt.go +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/cluster_jwt.go @@ -1,11 +1,14 @@ package chaos_infrastructure import ( + "context" "errors" "fmt" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/authConfig" + "github.com/golang-jwt/jwt" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" ) // InfraCreateJWT generates jwt used in chaos_infra registration @@ -13,8 +16,11 @@ func InfraCreateJWT(id string) (string, error) { claims := jwt.MapClaims{} claims["chaos_infra_id"] = id token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - tokenString, err := token.SignedString([]byte(utils.Config.JwtSecret)) + config, err := authConfig.NewAuthConfigOperator(mongodb.Operator).GetAuthConfig(context.Background()) + if err != nil { + return "", err + } + tokenString, err := token.SignedString([]byte(config.Value)) if err != nil { return "", err } @@ -28,7 +34,11 @@ func InfraValidateJWT(token string) (string, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } - return []byte(utils.Config.JwtSecret), nil + config, err := authConfig.NewAuthConfigOperator(mongodb.Operator).GetAuthConfig(context.Background()) + if err != nil { + return "", err + } + return []byte(config.Value), nil }) if err != nil { diff --git a/chaoscenter/graphql/server/pkg/database/mongodb/authConfig/operations.go b/chaoscenter/graphql/server/pkg/database/mongodb/authConfig/operations.go new file mode 100644 index 00000000000..17eda96de79 --- /dev/null +++ b/chaoscenter/graphql/server/pkg/database/mongodb/authConfig/operations.go @@ -0,0 +1,27 @@ +package authConfig + +import ( + "context" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" +) + +// Operator is the model for cluster collection +type Operator struct { + operator mongodb.MongoOperator +} + +// NewAuthConfigOperator returns a new instance of Operator +func NewAuthConfigOperator(mongodbOperator mongodb.MongoOperator) *Operator { + return &Operator{ + operator: mongodbOperator, + } +} + +func (c *Operator) GetAuthConfig(ctx context.Context) (*mongodb.AuthConfig, error) { + salt, err := c.operator.GetAuthConfig(ctx, "salt") + if err != nil { + return nil, err + } + return salt, nil +} diff --git a/chaoscenter/graphql/server/pkg/database/mongodb/common_schema.go b/chaoscenter/graphql/server/pkg/database/mongodb/common_schema.go index 42859c00115..4cb7b2e7c2c 100644 --- a/chaoscenter/graphql/server/pkg/database/mongodb/common_schema.go +++ b/chaoscenter/graphql/server/pkg/database/mongodb/common_schema.go @@ -19,3 +19,8 @@ type UserDetailResponse struct { Username string `bson:"username" json:"username"` Email string `bson:"email" json:"email"` } + +type AuthConfig struct { + Key string `bson:"key"` + Value string `bson:"value"` +} diff --git a/chaoscenter/graphql/server/pkg/database/mongodb/mocks/mongo_operations.go b/chaoscenter/graphql/server/pkg/database/mongodb/mocks/mongo_operations.go index 97cbe724ee9..028ac7f2d6e 100644 --- a/chaoscenter/graphql/server/pkg/database/mongodb/mocks/mongo_operations.go +++ b/chaoscenter/graphql/server/pkg/database/mongodb/mocks/mongo_operations.go @@ -4,6 +4,7 @@ package mocks import ( "context" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" "github.com/stretchr/testify/mock" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" @@ -16,11 +17,17 @@ type MongoOperator struct { } // WatchEvents implements mongodb.MongoOperator. -func (m *MongoOperator) WatchEvents(ctx context.Context, client *mongo.Client, collectionType int, pipeline mongo.Pipeline, opts ...*options.ChangeStreamOptions) (*mongo.ChangeStream, error) { +func (m MongoOperator) WatchEvents(ctx context.Context, client *mongo.Client, collectionType int, pipeline mongo.Pipeline, opts ...*options.ChangeStreamOptions) (*mongo.ChangeStream, error) { args := m.Called(ctx, client, collectionType, pipeline, opts) return args.Get(0).(*mongo.ChangeStream), args.Error(1) } +// GetAuthConfig implements mongodb.MongoOperator. +func (m MongoOperator) GetAuthConfig(ctx context.Context, key string) (*mongodb.AuthConfig, error) { + args := m.Called(ctx, key) + return args.Get(0).(*mongodb.AuthConfig), args.Error(1) +} + // Create provides a mock function with given fields: ctx, collectionType, document func (m MongoOperator) Create(ctx context.Context, collectionType int, document interface{}) error { args := m.Called(ctx, collectionType, document) diff --git a/chaoscenter/graphql/server/pkg/database/mongodb/operations.go b/chaoscenter/graphql/server/pkg/database/mongodb/operations.go index d5a5606b4e9..cecd1395f13 100644 --- a/chaoscenter/graphql/server/pkg/database/mongodb/operations.go +++ b/chaoscenter/graphql/server/pkg/database/mongodb/operations.go @@ -2,6 +2,7 @@ package mongodb import ( "context" + "encoding/base64" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" @@ -25,6 +26,7 @@ type MongoOperator interface { ListCollection(ctx context.Context, mclient *mongo.Client) ([]string, error) ListDataBase(ctx context.Context, mclient *mongo.Client) ([]string, error) WatchEvents(ctx context.Context, client *mongo.Client, collectionType int, pipeline mongo.Pipeline, opts ...*options.ChangeStreamOptions) (*mongo.ChangeStream, error) + GetAuthConfig(ctx context.Context, key string) (*AuthConfig, error) } type MongoOperations struct { @@ -214,3 +216,23 @@ func (m *MongoOperations) WatchEvents(ctx context.Context, client *mongo.Client, } return events, nil } + +func (m *MongoOperations) GetAuthConfig(ctx context.Context, key string) (*AuthConfig, error) { + + authDb := MgoClient.Database("auth") + find := authDb.Collection("auth-config").FindOne(ctx, bson.D{ + {"key", key}, + }) + var conf AuthConfig + err := find.Decode(&conf) + if err != nil { + return nil, err + } + + decodedValue, err := base64.URLEncoding.DecodeString(conf.Value) + if err != nil { + return nil, err + } + conf.Value = string(decodedValue) + return &conf, nil +} diff --git a/chaoscenter/graphql/server/pkg/environment/handler/fuzz_tests/handler_fuzz_test.go b/chaoscenter/graphql/server/pkg/environment/handler/fuzz_tests/handler_fuzz_test.go index ac448180aaa..183edb37f97 100644 --- a/chaoscenter/graphql/server/pkg/environment/handler/fuzz_tests/handler_fuzz_test.go +++ b/chaoscenter/graphql/server/pkg/environment/handler/fuzz_tests/handler_fuzz_test.go @@ -15,7 +15,6 @@ import ( "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/authorization" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" "github.com/sirupsen/logrus" "github.com/stretchr/testify/mock" "go.mongodb.org/mongo-driver/bson" @@ -45,7 +44,6 @@ func GetSignedJWT(name string) (string, error) { } func FuzzCreateEnvironment(f *testing.F) { - utils.Config.JwtSecret = JwtSecret f.Fuzz(func(t *testing.T, data []byte) { fuzzConsumer := fuzz.NewConsumer(data) targetStruct := &struct { @@ -65,7 +63,7 @@ func FuzzCreateEnvironment(f *testing.F) { ctx := context.WithValue(context.Background(), authorization.AuthKey, token) service := handler.NewEnvironmentService(environmentOperator) - env, err := service.CreateEnvironment(ctx, targetStruct.projectID, &targetStruct.input) + env, err := service.CreateEnvironment(ctx, targetStruct.projectID, &targetStruct.input, "") if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -76,7 +74,6 @@ func FuzzCreateEnvironment(f *testing.F) { } func FuzzTestDeleteEnvironment(f *testing.F) { - utils.Config.JwtSecret = JwtSecret testCases := []struct { projectID string environmentID string @@ -107,7 +104,7 @@ func FuzzTestDeleteEnvironment(f *testing.F) { ctx := context.WithValue(context.Background(), authorization.AuthKey, token) service := handler.NewEnvironmentService(environmentOperator) - env, err := service.DeleteEnvironment(ctx, projectID, environmentID) + env, err := service.DeleteEnvironment(ctx, projectID, environmentID, "") if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -119,7 +116,6 @@ func FuzzTestDeleteEnvironment(f *testing.F) { } func FuzzTestGetEnvironment(f *testing.F) { - utils.Config.JwtSecret = JwtSecret testCases := []struct { projectID string environmentID string diff --git a/chaoscenter/graphql/server/pkg/environment/handler/handler.go b/chaoscenter/graphql/server/pkg/environment/handler/handler.go index 3ae2ee9368f..e1953c09f6c 100644 --- a/chaoscenter/graphql/server/pkg/environment/handler/handler.go +++ b/chaoscenter/graphql/server/pkg/environment/handler/handler.go @@ -7,7 +7,6 @@ import ( "time" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/authorization" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/environments" dbOperationsEnvironment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/environments" @@ -16,9 +15,9 @@ import ( ) type EnvironmentHandler interface { - CreateEnvironment(ctx context.Context, projectID string, input *model.CreateEnvironmentRequest) (*model.Environment, error) - UpdateEnvironment(ctx context.Context, projectID string, request *model.UpdateEnvironmentRequest) (string, error) - DeleteEnvironment(ctx context.Context, projectID string, environmentID string) (string, error) + CreateEnvironment(ctx context.Context, projectID string, input *model.CreateEnvironmentRequest, username string) (*model.Environment, error) + UpdateEnvironment(ctx context.Context, projectID string, request *model.UpdateEnvironmentRequest, username string) (string, error) + DeleteEnvironment(ctx context.Context, projectID string, environmentID string, username string) (string, error) GetEnvironment(projectID string, environmentID string) (*model.Environment, error) ListEnvironments(projectID string, request *model.ListEnvironmentRequest) (*model.ListEnvironmentResponse, error) } @@ -33,19 +32,13 @@ func NewEnvironmentService(EnvironmentOperator *dbOperationsEnvironment.Operator } } -func (e *EnvironmentService) CreateEnvironment(ctx context.Context, projectID string, input *model.CreateEnvironmentRequest) (*model.Environment, error) { +func (e *EnvironmentService) CreateEnvironment(ctx context.Context, projectID string, input *model.CreateEnvironmentRequest, username string) (*model.Environment, error) { currentTime := time.Now() if input.Tags == nil || len(input.Tags) == 0 { input.Tags = []string{} } - tkn := ctx.Value(authorization.AuthKey).(string) - username, err := authorization.GetUsername(tkn) - if err != nil { - return nil, err - } - desc := "" if input.Description != nil { desc = *input.Description @@ -75,7 +68,7 @@ func (e *EnvironmentService) CreateEnvironment(ctx context.Context, projectID st }, } - err = e.EnvironmentOperator.InsertEnvironment(context.Background(), newEnv) + err := e.EnvironmentOperator.InsertEnvironment(context.Background(), newEnv) if err != nil { return &model.Environment{}, err } @@ -91,7 +84,7 @@ func (e *EnvironmentService) CreateEnvironment(ctx context.Context, projectID st } -func (e *EnvironmentService) UpdateEnvironment(ctx context.Context, projectID string, request *model.UpdateEnvironmentRequest) (string, error) { +func (e *EnvironmentService) UpdateEnvironment(ctx context.Context, projectID string, request *model.UpdateEnvironmentRequest, username string) (string, error) { query := bson.D{ {"environment_id", request.EnvironmentID}, @@ -104,12 +97,6 @@ func (e *EnvironmentService) UpdateEnvironment(ctx context.Context, projectID st return "couldn't update environment", err } - tkn := ctx.Value(authorization.AuthKey).(string) - username, err := authorization.GetUsername(tkn) - if err != nil { - return "", err - } - updateQuery := bson.D{} updateQuery = append(updateQuery, bson.E{ Key: "$set", Value: bson.D{ @@ -156,20 +143,16 @@ func (e *EnvironmentService) UpdateEnvironment(ctx context.Context, projectID st return "environment updated successfully", nil } -func (e *EnvironmentService) DeleteEnvironment(ctx context.Context, projectID string, environmentID string) (string, error) { +func (e *EnvironmentService) DeleteEnvironment(ctx context.Context, projectID string, environmentID string, username string) (string, error) { currTime := time.Now().UnixMilli() - tkn := ctx.Value(authorization.AuthKey).(string) - username, err := authorization.GetUsername(tkn) - if err != nil { - return "", err - } + query := bson.D{ {"environment_id", environmentID}, {"project_id", projectID}, {"is_removed", false}, } - _, err = e.EnvironmentOperator.GetEnvironment(query) + _, err := e.EnvironmentOperator.GetEnvironment(query) if err != nil { return "couldn't fetch environment details", err } diff --git a/chaoscenter/graphql/server/pkg/environment/test/handler_test.go b/chaoscenter/graphql/server/pkg/environment/test/handler_test.go index 170239f7df5..9b1ac42dc8d 100644 --- a/chaoscenter/graphql/server/pkg/environment/test/handler_test.go +++ b/chaoscenter/graphql/server/pkg/environment/test/handler_test.go @@ -2,10 +2,11 @@ package test import ( "context" - "errors" "testing" "time" + "go.mongodb.org/mongo-driver/mongo" + "github.com/golang-jwt/jwt" "github.com/google/uuid" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" @@ -14,7 +15,6 @@ import ( dbOperationsEnvironment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/environments" dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/environment/handler" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" "github.com/stretchr/testify/mock" "go.mongodb.org/mongo-driver/bson" ) @@ -42,7 +42,6 @@ func GetSignedJWT(name string) (string, error) { } func TestCreateEnvironment(t *testing.T) { - utils.Config.JwtSecret = JwtSecret testCases := []struct { name string projectID string @@ -63,7 +62,7 @@ func TestCreateEnvironment(t *testing.T) { return nil }, expectedEnv: nil, - expectedErr: errors.New("invalid Token"), + expectedErr: nil, given: func() string { token, err := GetSignedJWT("testUser") if err != nil { @@ -72,34 +71,18 @@ func TestCreateEnvironment(t *testing.T) { return "invalid Token" }, }, - { - name: "Failed environment creation due to invalid token", - projectID: "testProject", - input: &model.CreateEnvironmentRequest{ - EnvironmentID: "testEnvID", - Name: "testName", - }, - mockInsertFunc: func(ctx context.Context, env environments.Environment) error { - return nil - }, - expectedEnv: nil, - expectedErr: errors.New("invalid Token"), - given: func() string { - return "invalid Token" - }, - }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - mongodbMockOperator.On("Insert", mock.Anything, mock.AnythingOfType("environments.Environment")). - Return(tc.mockInsertFunc) + mongodbMockOperator.On("Create", mock.Anything, mock.Anything, mock.AnythingOfType("environments.Environment")). + Return(nil) token := tc.given() ctx := context.WithValue(context.Background(), authorization.AuthKey, token) mockOperator := environmentOperator service := handler.NewEnvironmentService(mockOperator) - env, err := service.CreateEnvironment(ctx, tc.projectID, tc.input) + env, err := service.CreateEnvironment(ctx, tc.projectID, tc.input, "") if (err != nil && tc.expectedErr == nil) || (err == nil && tc.expectedErr != nil) || (err != nil && tc.expectedErr != nil && err.Error() != tc.expectedErr.Error()) { @@ -115,30 +98,27 @@ func TestCreateEnvironment(t *testing.T) { } func TestDeleteEnvironment(t *testing.T) { - utils.Config.JwtSecret = JwtSecret + findResult := []interface{}{bson.D{ + {Key: "environment_id", Value: "testEnvID"}, + }} + singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) testCases := []struct { name string projectID string environmentID string - mockGetEnvironmentFunc func(query bson.D) (environments.Environment, error) - mockUpdateFunc func(ctx context.Context, query bson.D, update bson.D) error + mockGetEnvironmentFunc *mongo.SingleResult + mockUpdateFunc *mongo.UpdateResult expectedResult string expectedErr error given func() string }{ { - name: "success", - projectID: "testProject", - environmentID: "testEnvID", - mockGetEnvironmentFunc: func(query bson.D) (environments.Environment, error) { - return environments.Environment{ - EnvironmentID: "testEnvID", - }, nil - }, - mockUpdateFunc: func(ctx context.Context, query bson.D, update bson.D) error { - return nil - }, - expectedErr: errors.New("invalid Token"), + name: "success", + projectID: "testProject", + environmentID: "testEnvID", + mockGetEnvironmentFunc: singleResult, + mockUpdateFunc: &mongo.UpdateResult{}, + expectedErr: nil, given: func() string { token, err := GetSignedJWT("testUser") if err != nil { @@ -146,37 +126,21 @@ func TestDeleteEnvironment(t *testing.T) { } return "invalid Token" }, - }, - { - name: "Failed environment", - projectID: "testProject", - environmentID: "testEnvID", - mockGetEnvironmentFunc: func(query bson.D) (environments.Environment, error) { - return environments.Environment{ - EnvironmentID: "testEnvID", - }, nil - }, - mockUpdateFunc: func(ctx context.Context, query, update bson.D) error { - return nil - }, - expectedErr: errors.New("invalid Token"), - given: func() string { - return "invalid Token" - }, - }, - } + }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - mongodbMockOperator.On("Insert", mock.Anything, mock.AnythingOfType("environments.Environment")). - Return(tc.mockUpdateFunc) + + mongodbMockOperator.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(tc.mockGetEnvironmentFunc, nil) + mongodbMockOperator.On("UpdateMany", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(tc.mockUpdateFunc, nil) token := tc.given() ctx := context.WithValue(context.Background(), authorization.AuthKey, token) mockOperator := environmentOperator service := handler.NewEnvironmentService(mockOperator) - _, err := service.DeleteEnvironment(ctx, tc.projectID, tc.environmentID) + _, err := service.DeleteEnvironment(ctx, tc.projectID, tc.environmentID, "") if (err != nil && tc.expectedErr == nil) || (err == nil && tc.expectedErr != nil) || (err != nil && tc.expectedErr != nil && err.Error() != tc.expectedErr.Error()) { diff --git a/chaoscenter/graphql/server/utils/variables.go b/chaoscenter/graphql/server/utils/variables.go index 1eba08a4d90..5c1b72dd1a5 100644 --- a/chaoscenter/graphql/server/utils/variables.go +++ b/chaoscenter/graphql/server/utils/variables.go @@ -8,7 +8,6 @@ type Configuration struct { Version string `required:"true"` InfraDeployments string `required:"true" split_words:"true"` DbServer string `required:"true" split_words:"true"` - JwtSecret string `required:"true" split_words:"true"` LitmusPortalNamespace string `required:"true" split_words:"true"` DbUser string `required:"true" split_words:"true"` DbPassword string `required:"true" split_words:"true"`