diff --git a/chaoscenter/graphql/server/pkg/authorization/authorization_fuzz_test.go b/chaoscenter/graphql/server/pkg/authorization/authorization_fuzz_test.go new file mode 100644 index 00000000000..8c62733fca4 --- /dev/null +++ b/chaoscenter/graphql/server/pkg/authorization/authorization_fuzz_test.go @@ -0,0 +1,136 @@ +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 +func generateExpiredFakeJWTToken(username string) string { + token := jwt.New(jwt.SigningMethodHS256) + claims := token.Claims.(jwt.MapClaims) + claims["username"] = username + claims["exp"] = time.Now().Add(-time.Hour).Unix() // Set expiration time to 1 hour ago + signedToken, _ := token.SignedString([]byte("your-secret-key")) // Sign the token with a secret key + return signedToken +} + +// generateFakeJWTTokenWithInvalidSignature generates a fake JWT token with an invalid signature +func generateFakeJWTTokenWithInvalidSignature(username string) string { + token := jwt.New(jwt.SigningMethodHS256) + claims := token.Claims.(jwt.MapClaims) + claims["username"] = username + claims["exp"] = time.Now().Add(time.Hour * 24).Unix() // Set expiration time to 24 hours from now + signedToken, _ := token.SignedString([]byte("invalid-secret-key")) // Sign the token with an invalid secret key + return signedToken +} + +// generateFakeJWTToken generates a fake JWT token with predefined claims +func generateFakeJWTToken(username string) string { + token := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{ + "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 + 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 + claims["exp"] = time.Now().Add(time.Hour * 24).Unix() + + // Create a new token with the claims + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + // Sign the token with a secret key + tokenString, err := token.SignedString([]byte(utils.Config.JwtSecret)) + if err != nil { + return "", fmt.Errorf("failed to sign JWT token: %v", err) + } + + return tokenString, nil +} + +func FuzzUserValidateJWT(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + inputClaims := &jwt.MapClaims{} + err := fuzzConsumer.GenerateStruct(inputClaims) + if err != nil { + return + } + // Generate a JWT token with fuzzed claims + tokenString, err := generateJWTTokenFromClaims(*inputClaims) + if err != nil { + t.Fatalf("Error generating JWT token: %v", err) + } + + // Run the test with the generated JWT token + claims, err := UserValidateJWT(tokenString) + if err != nil { + t.Errorf("Error encountered: %v", err) + } + + // Optionally, check if claims are nil when there's an error + if claims == nil && err == nil { + t.Errorf("Claims are nil while no error is returned") + } + + }) +} diff --git a/chaoscenter/graphql/server/pkg/authorization/testdata/fuzz/FuzzGetUsername/771e938e4458e983 b/chaoscenter/graphql/server/pkg/authorization/testdata/fuzz/FuzzGetUsername/771e938e4458e983 new file mode 100644 index 00000000000..ee3f33997f9 --- /dev/null +++ b/chaoscenter/graphql/server/pkg/authorization/testdata/fuzz/FuzzGetUsername/771e938e4458e983 @@ -0,0 +1,2 @@ +go test fuzz v1 +string("0") diff --git a/chaoscenter/graphql/server/pkg/authorization/testdata/fuzz/FuzzGetUsername/f7d774048ada30d0 b/chaoscenter/graphql/server/pkg/authorization/testdata/fuzz/FuzzGetUsername/f7d774048ada30d0 new file mode 100644 index 00000000000..4f97796359d --- /dev/null +++ b/chaoscenter/graphql/server/pkg/authorization/testdata/fuzz/FuzzGetUsername/f7d774048ada30d0 @@ -0,0 +1,2 @@ +go test fuzz v1 +string("\x88") diff --git a/chaoscenter/graphql/server/pkg/authorization/user_jwt.go b/chaoscenter/graphql/server/pkg/authorization/user_jwt.go index e34f4a28ec6..90d81bf1e27 100644 --- a/chaoscenter/graphql/server/pkg/authorization/user_jwt.go +++ b/chaoscenter/graphql/server/pkg/authorization/user_jwt.go @@ -21,11 +21,11 @@ func UserValidateJWT(token string) (jwt.MapClaims, error) { if err != nil { log.Print("USER JWT ERROR: ", err) - return nil, errors.New("Invalid Token") + return nil, errors.New("invalid Token") } if !tkn.Valid { - return nil, errors.New("Invalid Token") + return nil, errors.New("invalid Token") } claims, ok := tkn.Claims.(jwt.MapClaims) @@ -33,7 +33,7 @@ func UserValidateJWT(token string) (jwt.MapClaims, error) { return claims, nil } - return nil, errors.New("Invalid Token") + return nil, errors.New("invalid Token") } // GetUsername returns the username from the jwt token @@ -54,22 +54,3 @@ func GetUsername(token string) (string, error) { return "", errors.New("invalid Token") } - -// GetUserID returns the GetUserID from the jwt token -func GetUserID(token string) (string, error) { - tkn, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { - return []byte(utils.Config.JwtSecret), nil - }) - - if err != nil { - log.Print("USER JWT ERROR: ", err) - return "", errors.New("invalid Token") - } - - claims, ok := tkn.Claims.(jwt.MapClaims) - if ok { - return claims["uid"].(string), nil - } - - return "", errors.New("invalid Token") -} diff --git a/chaoscenter/graphql/server/pkg/environment/handler/handler_test.go b/chaoscenter/graphql/server/pkg/environment/test/handler_test.go similarity index 96% rename from chaoscenter/graphql/server/pkg/environment/handler/handler_test.go rename to chaoscenter/graphql/server/pkg/environment/test/handler_test.go index 15f29ecf328..170239f7df5 100644 --- a/chaoscenter/graphql/server/pkg/environment/handler/handler_test.go +++ b/chaoscenter/graphql/server/pkg/environment/test/handler_test.go @@ -1,4 +1,4 @@ -package handler +package test import ( "context" @@ -13,6 +13,7 @@ import ( "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/environments" 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" @@ -96,7 +97,7 @@ func TestCreateEnvironment(t *testing.T) { token := tc.given() ctx := context.WithValue(context.Background(), authorization.AuthKey, token) mockOperator := environmentOperator - service := NewEnvironmentService(mockOperator) + service := handler.NewEnvironmentService(mockOperator) env, err := service.CreateEnvironment(ctx, tc.projectID, tc.input) if (err != nil && tc.expectedErr == nil) || @@ -173,7 +174,7 @@ func TestDeleteEnvironment(t *testing.T) { ctx := context.WithValue(context.Background(), authorization.AuthKey, token) mockOperator := environmentOperator - service := NewEnvironmentService(mockOperator) + service := handler.NewEnvironmentService(mockOperator) _, err := service.DeleteEnvironment(ctx, tc.projectID, tc.environmentID) if (err != nil && tc.expectedErr == nil) || diff --git a/chaoscenter/graphql/server/utils/fuzz_test.go b/chaoscenter/graphql/server/utils/fuzz_test.go new file mode 100644 index 00000000000..d9841a269e5 --- /dev/null +++ b/chaoscenter/graphql/server/utils/fuzz_test.go @@ -0,0 +1,80 @@ +package utils + +import ( + "strings" + "testing" + + fuzz "github.com/AdaLogics/go-fuzz-headers" +) + +func isValidString(s string) bool { + // Define the set of valid characters + validChars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-" + + // Iterate over each character in the string + for _, char := range s { + // Check if the character is not in the set of valid characters + if !strings.ContainsRune(validChars, char) { + return false + } + } + return true +} + +func FuzzRandomString(f *testing.F) { + f.Add(10) + f.Fuzz(func(t *testing.T, n int) { + randomString := RandomString(n) + // Perform checks on the generated string + // Check if the length matches the expected length + if n >= 0 && len(randomString) != n { + t.Errorf("Generated string length doesn't match expected length") + } + + // Check if the string contains only valid characters + if !isValidString(randomString) { + t.Errorf("Generated string contains invalid characters") + } + }) + +} + +func FuzzContainsString(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + s []string + str string + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + // Perform checks on the ContainsString function + // Check if ContainsString returns true when the target string is in the array + if ContainsString(targetStruct.s, targetStruct.str) { + found := false + for _, v := range targetStruct.s { + if v == targetStruct.str { + found = true + break + } + } + if !found { + t.Errorf("ContainsString returned true for target '%s' not present in the array", targetStruct.str) + } + } else { + // Check if ContainsString returns false when the target string is not in the array + found := false + for _, v := range targetStruct.s { + if v == targetStruct.str { + found = true + break + } + } + if found { + t.Errorf("ContainsString returned false for target '%s' present in the array", targetStruct.str) + } + } + }) +} diff --git a/chaoscenter/graphql/server/utils/misc.go b/chaoscenter/graphql/server/utils/misc.go index 5678786545d..49986e8b79f 100644 --- a/chaoscenter/graphql/server/utils/misc.go +++ b/chaoscenter/graphql/server/utils/misc.go @@ -29,14 +29,17 @@ func WriteHeaders(w *gin.ResponseWriter, statusCode int) { // RandomString generates random strings, can be used to create ids or random secrets func RandomString(n int) string { - var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-") - rand.Seed(time.Now().UnixNano()) - s := make([]rune, n) - for i := range s { - s[i] = letters[rand.Intn(len(letters))] - } + if n > 0 { + var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-") + rand.Seed(time.Now().UnixNano()) + s := make([]rune, n) + for i := range s { + s[i] = letters[rand.Intn(len(letters))] + } - return string(s) + return string(s) + } + return "" } func AddRootIndent(b []byte, n int) []byte { diff --git a/chaoscenter/graphql/server/utils/testdata/fuzz/FuzzRandomString/6397b820ae00f953 b/chaoscenter/graphql/server/utils/testdata/fuzz/FuzzRandomString/6397b820ae00f953 new file mode 100644 index 00000000000..5ad17818142 --- /dev/null +++ b/chaoscenter/graphql/server/utils/testdata/fuzz/FuzzRandomString/6397b820ae00f953 @@ -0,0 +1,2 @@ +go test fuzz v1 +int(-57)