Skip to content

Commit 5479d12

Browse files
Added fuzzers in utils and authorization(graphql) (#4467)
* Added fuzzers in utils and authorization Signed-off-by: Saranya-jena <[email protected]> * fixed imports Signed-off-by: Saranya-jena <[email protected]> * fixed imports Signed-off-by: Saranya-jena <[email protected]> * go mod changes Signed-off-by: Saranya-jena <[email protected]> * updated directories Signed-off-by: Saranya-jena <[email protected]> * updated file strucuture Signed-off-by: Saranya-jena <[email protected]> --------- Signed-off-by: Saranya-jena <[email protected]> Co-authored-by: Namkyu Park <[email protected]>
1 parent 786bb52 commit 5479d12

File tree

8 files changed

+239
-32
lines changed

8 files changed

+239
-32
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package authorization
2+
3+
import (
4+
"encoding/base64"
5+
"fmt"
6+
"testing"
7+
"time"
8+
9+
fuzz "github.com/AdaLogics/go-fuzz-headers"
10+
"github.com/golang-jwt/jwt"
11+
"github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils"
12+
)
13+
14+
// generateExpiredFakeJWTToken generates a fake JWT token with expiration time set to the past
15+
func generateExpiredFakeJWTToken(username string) string {
16+
token := jwt.New(jwt.SigningMethodHS256)
17+
claims := token.Claims.(jwt.MapClaims)
18+
claims["username"] = username
19+
claims["exp"] = time.Now().Add(-time.Hour).Unix() // Set expiration time to 1 hour ago
20+
signedToken, _ := token.SignedString([]byte("your-secret-key")) // Sign the token with a secret key
21+
return signedToken
22+
}
23+
24+
// generateFakeJWTTokenWithInvalidSignature generates a fake JWT token with an invalid signature
25+
func generateFakeJWTTokenWithInvalidSignature(username string) string {
26+
token := jwt.New(jwt.SigningMethodHS256)
27+
claims := token.Claims.(jwt.MapClaims)
28+
claims["username"] = username
29+
claims["exp"] = time.Now().Add(time.Hour * 24).Unix() // Set expiration time to 24 hours from now
30+
signedToken, _ := token.SignedString([]byte("invalid-secret-key")) // Sign the token with an invalid secret key
31+
return signedToken
32+
}
33+
34+
// generateFakeJWTToken generates a fake JWT token with predefined claims
35+
func generateFakeJWTToken(username string) string {
36+
token := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{
37+
"username": username,
38+
"exp": time.Now().Add(time.Hour * 24).Unix(), // Set expiration time to 24 hours from now
39+
})
40+
41+
signedToken, _ := token.SignedString([]byte(utils.Config.JwtSecret)) // No signature is needed for testing
42+
return signedToken
43+
}
44+
45+
func FuzzGetUsername(f *testing.F) {
46+
f.Fuzz(func(t *testing.T, input string) {
47+
// Create a fake JWT token with predefined claims
48+
49+
// Invalid token format check
50+
_, err := GetUsername(input)
51+
if err == nil {
52+
t.Error("Expected error for invalid token format")
53+
}
54+
55+
// Generating fake jwt token for testing
56+
token := generateFakeJWTToken(base64.StdEncoding.EncodeToString([]byte(input)))
57+
58+
// Run the test with the fake JWT token
59+
username, err := GetUsername(token)
60+
if err != nil {
61+
t.Errorf("Error encountered: %v", err)
62+
}
63+
64+
// Decode the username back from base64
65+
decodedUsername, err := base64.StdEncoding.DecodeString(username)
66+
if err != nil {
67+
t.Errorf("Error decoding username: %v", err)
68+
}
69+
70+
// Check if the decoded username matches the input string
71+
if string(decodedUsername) != input {
72+
t.Errorf("Expected username: %s, got: %s", input, username)
73+
}
74+
75+
// Additional checks
76+
// Expiration check
77+
expiredToken := generateExpiredFakeJWTToken(input)
78+
_, err = GetUsername(expiredToken)
79+
if err == nil {
80+
t.Error("Expected error for expired token")
81+
}
82+
83+
// Token signature check (invalid secret key)
84+
invalidSignatureToken := generateFakeJWTTokenWithInvalidSignature(input)
85+
_, err = GetUsername(invalidSignatureToken)
86+
if err == nil {
87+
t.Error("Expected error for token with invalid signature")
88+
}
89+
90+
})
91+
}
92+
93+
// generateJWTToken generates a JWT token with the given claims
94+
func generateJWTTokenFromClaims(claims jwt.MapClaims) (string, error) {
95+
// Set expiration time to 24 hours from now
96+
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
97+
98+
// Create a new token with the claims
99+
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
100+
101+
// Sign the token with a secret key
102+
tokenString, err := token.SignedString([]byte(utils.Config.JwtSecret))
103+
if err != nil {
104+
return "", fmt.Errorf("failed to sign JWT token: %v", err)
105+
}
106+
107+
return tokenString, nil
108+
}
109+
110+
func FuzzUserValidateJWT(f *testing.F) {
111+
f.Fuzz(func(t *testing.T, data []byte) {
112+
fuzzConsumer := fuzz.NewConsumer(data)
113+
inputClaims := &jwt.MapClaims{}
114+
err := fuzzConsumer.GenerateStruct(inputClaims)
115+
if err != nil {
116+
return
117+
}
118+
// Generate a JWT token with fuzzed claims
119+
tokenString, err := generateJWTTokenFromClaims(*inputClaims)
120+
if err != nil {
121+
t.Fatalf("Error generating JWT token: %v", err)
122+
}
123+
124+
// Run the test with the generated JWT token
125+
claims, err := UserValidateJWT(tokenString)
126+
if err != nil {
127+
t.Errorf("Error encountered: %v", err)
128+
}
129+
130+
// Optionally, check if claims are nil when there's an error
131+
if claims == nil && err == nil {
132+
t.Errorf("Claims are nil while no error is returned")
133+
}
134+
135+
})
136+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
go test fuzz v1
2+
string("0")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
go test fuzz v1
2+
string("\x88")

chaoscenter/graphql/server/pkg/authorization/user_jwt.go

+3-22
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,19 @@ func UserValidateJWT(token string) (jwt.MapClaims, error) {
2121

2222
if err != nil {
2323
log.Print("USER JWT ERROR: ", err)
24-
return nil, errors.New("Invalid Token")
24+
return nil, errors.New("invalid Token")
2525
}
2626

2727
if !tkn.Valid {
28-
return nil, errors.New("Invalid Token")
28+
return nil, errors.New("invalid Token")
2929
}
3030

3131
claims, ok := tkn.Claims.(jwt.MapClaims)
3232
if ok {
3333
return claims, nil
3434
}
3535

36-
return nil, errors.New("Invalid Token")
36+
return nil, errors.New("invalid Token")
3737
}
3838

3939
// GetUsername returns the username from the jwt token
@@ -54,22 +54,3 @@ func GetUsername(token string) (string, error) {
5454

5555
return "", errors.New("invalid Token")
5656
}
57-
58-
// GetUserID returns the GetUserID from the jwt token
59-
func GetUserID(token string) (string, error) {
60-
tkn, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
61-
return []byte(utils.Config.JwtSecret), nil
62-
})
63-
64-
if err != nil {
65-
log.Print("USER JWT ERROR: ", err)
66-
return "", errors.New("invalid Token")
67-
}
68-
69-
claims, ok := tkn.Claims.(jwt.MapClaims)
70-
if ok {
71-
return claims["uid"].(string), nil
72-
}
73-
74-
return "", errors.New("invalid Token")
75-
}

chaoscenter/graphql/server/pkg/environment/handler/handler_test.go chaoscenter/graphql/server/pkg/environment/test/handler_test.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package handler
1+
package test
22

33
import (
44
"context"
@@ -13,6 +13,7 @@ import (
1313
"github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/environments"
1414
dbOperationsEnvironment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/environments"
1515
dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks"
16+
"github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/environment/handler"
1617
"github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils"
1718
"github.com/stretchr/testify/mock"
1819
"go.mongodb.org/mongo-driver/bson"
@@ -96,7 +97,7 @@ func TestCreateEnvironment(t *testing.T) {
9697
token := tc.given()
9798
ctx := context.WithValue(context.Background(), authorization.AuthKey, token)
9899
mockOperator := environmentOperator
99-
service := NewEnvironmentService(mockOperator)
100+
service := handler.NewEnvironmentService(mockOperator)
100101

101102
env, err := service.CreateEnvironment(ctx, tc.projectID, tc.input)
102103
if (err != nil && tc.expectedErr == nil) ||
@@ -173,7 +174,7 @@ func TestDeleteEnvironment(t *testing.T) {
173174
ctx := context.WithValue(context.Background(), authorization.AuthKey, token)
174175

175176
mockOperator := environmentOperator
176-
service := NewEnvironmentService(mockOperator)
177+
service := handler.NewEnvironmentService(mockOperator)
177178

178179
_, err := service.DeleteEnvironment(ctx, tc.projectID, tc.environmentID)
179180
if (err != nil && tc.expectedErr == nil) ||
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package utils
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
fuzz "github.com/AdaLogics/go-fuzz-headers"
8+
)
9+
10+
func isValidString(s string) bool {
11+
// Define the set of valid characters
12+
validChars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"
13+
14+
// Iterate over each character in the string
15+
for _, char := range s {
16+
// Check if the character is not in the set of valid characters
17+
if !strings.ContainsRune(validChars, char) {
18+
return false
19+
}
20+
}
21+
return true
22+
}
23+
24+
func FuzzRandomString(f *testing.F) {
25+
f.Add(10)
26+
f.Fuzz(func(t *testing.T, n int) {
27+
randomString := RandomString(n)
28+
// Perform checks on the generated string
29+
// Check if the length matches the expected length
30+
if n >= 0 && len(randomString) != n {
31+
t.Errorf("Generated string length doesn't match expected length")
32+
}
33+
34+
// Check if the string contains only valid characters
35+
if !isValidString(randomString) {
36+
t.Errorf("Generated string contains invalid characters")
37+
}
38+
})
39+
40+
}
41+
42+
func FuzzContainsString(f *testing.F) {
43+
f.Fuzz(func(t *testing.T, data []byte) {
44+
fuzzConsumer := fuzz.NewConsumer(data)
45+
targetStruct := &struct {
46+
s []string
47+
str string
48+
}{}
49+
err := fuzzConsumer.GenerateStruct(targetStruct)
50+
if err != nil {
51+
return
52+
}
53+
// Perform checks on the ContainsString function
54+
// Check if ContainsString returns true when the target string is in the array
55+
if ContainsString(targetStruct.s, targetStruct.str) {
56+
found := false
57+
for _, v := range targetStruct.s {
58+
if v == targetStruct.str {
59+
found = true
60+
break
61+
}
62+
}
63+
if !found {
64+
t.Errorf("ContainsString returned true for target '%s' not present in the array", targetStruct.str)
65+
}
66+
} else {
67+
// Check if ContainsString returns false when the target string is not in the array
68+
found := false
69+
for _, v := range targetStruct.s {
70+
if v == targetStruct.str {
71+
found = true
72+
break
73+
}
74+
}
75+
if found {
76+
t.Errorf("ContainsString returned false for target '%s' present in the array", targetStruct.str)
77+
}
78+
}
79+
})
80+
}

chaoscenter/graphql/server/utils/misc.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,17 @@ func WriteHeaders(w *gin.ResponseWriter, statusCode int) {
2929

3030
// RandomString generates random strings, can be used to create ids or random secrets
3131
func RandomString(n int) string {
32-
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-")
33-
rand.Seed(time.Now().UnixNano())
34-
s := make([]rune, n)
35-
for i := range s {
36-
s[i] = letters[rand.Intn(len(letters))]
37-
}
32+
if n > 0 {
33+
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-")
34+
rand.Seed(time.Now().UnixNano())
35+
s := make([]rune, n)
36+
for i := range s {
37+
s[i] = letters[rand.Intn(len(letters))]
38+
}
3839

39-
return string(s)
40+
return string(s)
41+
}
42+
return ""
4043
}
4144

4245
func AddRootIndent(b []byte, n int) []byte {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
go test fuzz v1
2+
int(-57)

0 commit comments

Comments
 (0)