Skip to content

Commit

Permalink
Added fuzzers in utils and authorization(graphql) (#4467)
Browse files Browse the repository at this point in the history
* Added fuzzers in utils and authorization

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* fixed imports

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* fixed imports

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* go mod changes

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* updated directories

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* updated file strucuture

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

---------

Signed-off-by: Saranya-jena <saranya.jena@harness.io>
Co-authored-by: Namkyu Park <53862866+namkyu1999@users.noreply.github.com>
  • Loading branch information
Saranya-jena and namkyu1999 authored Mar 14, 2024
1 parent 786bb52 commit 5479d12
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -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")
}

})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
string("0")
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
string("\x88")
25 changes: 3 additions & 22 deletions chaoscenter/graphql/server/pkg/authorization/user_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ 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)
if ok {
return claims, nil
}

return nil, errors.New("Invalid Token")
return nil, errors.New("invalid Token")
}

// GetUsername returns the username from the jwt token
Expand All @@ -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")
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package handler
package test

import (
"context"
Expand All @@ -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"
Expand Down Expand Up @@ -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) ||
Expand Down Expand Up @@ -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) ||
Expand Down
80 changes: 80 additions & 0 deletions chaoscenter/graphql/server/utils/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
})
}
17 changes: 10 additions & 7 deletions chaoscenter/graphql/server/utils/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
int(-57)

0 comments on commit 5479d12

Please sign in to comment.