diff --git a/enforcer.go b/enforcer.go index 804c63148..498680c07 100644 --- a/enforcer.go +++ b/enforcer.go @@ -674,13 +674,17 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac if e.acceptJsonRequest { // try to parse all request values from json to map[string]interface{} - // skip if there is an error for i, rval := range rvals { switch rval := rval.(type) { case string: - var mapValue map[string]interface{} - mapValue, err = util.JsonToMap(rval) - if err == nil { + // Only attempt JSON parsing for strings that look like JSON objects or arrays + if len(rval) > 0 && (rval[0] == '{' || rval[0] == '[') { + var mapValue map[string]interface{} + mapValue, err = util.JsonToMap(rval) + if err != nil { + // Return a clear error when JSON-like string fails to parse + return false, fmt.Errorf("failed to parse JSON parameter at index %d: %w", i, err) + } rvals[i] = mapValue } } diff --git a/enforcer_json_test.go b/enforcer_json_test.go new file mode 100644 index 000000000..6e5fc669a --- /dev/null +++ b/enforcer_json_test.go @@ -0,0 +1,66 @@ +package casbin + +import ( + "strings" + "testing" + + "github.com/casbin/casbin/v3/model" +) + +func TestInvalidJsonRequest(t *testing.T) { + modelText := ` +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act + +[role_definition] +g = _, _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = r.sub.Name == " " +` + + m, err := model.NewModelFromString(modelText) + if err != nil { + t.Fatalf("Failed to create model: %v", err) + } + e, err := NewEnforcer(m) + if err != nil { + t.Fatalf("Failed to create enforcer: %v", err) + } + e.EnableAcceptJsonRequest(true) + + // Test with invalid JSON (contains \x escape sequence which is not valid in JSON) + invalidJSON := `{"Name": "\x20"}` + _, err = e.Enforce(invalidJSON, "obj", "read") + if err == nil { + t.Fatalf("Expected error for invalid JSON, got nil") + } + if !strings.Contains(err.Error(), "failed to parse JSON parameter") { + t.Fatalf("Expected error message to contain 'failed to parse JSON parameter', got: %v", err) + } + + // Test with valid JSON - should work + validJSON := `{"Name": " "}` + res, err := e.Enforce(validJSON, "obj", "read") + if err != nil { + t.Fatalf("Valid JSON should not return error: %v", err) + } + if !res { + t.Fatalf("Expected true for valid JSON with matching Name") + } + + // Test with plain string (doesn't start with { or [) - should not try to parse as JSON + plainString := "alice" + _, err = e.Enforce(plainString, "obj", "read") + // This will fail because plainString is not a struct with Name field, + // but it shouldn't fail with JSON parsing error + if err != nil && strings.Contains(err.Error(), "failed to parse JSON parameter") { + t.Fatalf("Plain string should not trigger JSON parsing error: %v", err) + } +}