|
15 | 15 | package stringadapter |
16 | 16 |
|
17 | 17 | import ( |
| 18 | + "strings" |
18 | 19 | "testing" |
19 | 20 |
|
20 | 21 | "github.com/casbin/casbin/v3" |
21 | 22 | "github.com/casbin/casbin/v3/model" |
| 23 | + "github.com/casbin/casbin/v3/persist" |
22 | 24 | ) |
23 | 25 |
|
24 | 26 | func Test_KeyMatchRbac(t *testing.T) { |
@@ -61,6 +63,73 @@ g, alice, data_group_admin |
61 | 63 | } |
62 | 64 | } |
63 | 65 |
|
| 66 | +// Test_SavePolicyRoundTripWithCommas verifies that a policy rule whose fields contain |
| 67 | +// commas (e.g. ABAC condition expressions) survives a SavePolicy → LoadPolicy round trip |
| 68 | +// without corruption. See https://github.com/apache/casbin/issues/1733. |
| 69 | +func Test_SavePolicyRoundTripWithCommas(t *testing.T) { |
| 70 | + conf := ` |
| 71 | +[request_definition] |
| 72 | +r = sub, obj, act, cond |
| 73 | +
|
| 74 | +[policy_definition] |
| 75 | +p = sub, obj, act, cond |
| 76 | +
|
| 77 | +[policy_effect] |
| 78 | +e = some(where (p.eft == allow)) |
| 79 | +
|
| 80 | +[matchers] |
| 81 | +m = r.sub == p.sub && r.obj == p.obj && r.act == p.act |
| 82 | +` |
| 83 | + // cond field intentionally contains commas (as in ABAC expressions). |
| 84 | + condWithComma := `r.attrs in ('val1','val2')` |
| 85 | + line := "p, alice, data1, read, " + `"` + condWithComma + `"` |
| 86 | + |
| 87 | + a := NewAdapter(line) |
| 88 | + m := model.NewModel() |
| 89 | + if err := m.LoadModelFromText(conf); err != nil { |
| 90 | + t.Fatalf("load model: %v", err) |
| 91 | + } |
| 92 | + e, err := casbin.NewEnforcer(m, a) |
| 93 | + if err != nil { |
| 94 | + t.Fatalf("new enforcer: %v", err) |
| 95 | + } |
| 96 | + |
| 97 | + // SavePolicy serialises in-memory rules back to the adapter string. |
| 98 | + err = e.SavePolicy() |
| 99 | + if err != nil { |
| 100 | + t.Fatalf("SavePolicy: %v", err) |
| 101 | + } |
| 102 | + |
| 103 | + // The saved line must be a properly quoted CSV so that re-loading produces |
| 104 | + // exactly one rule with the comma-containing cond field intact. |
| 105 | + saved := a.Line |
| 106 | + reloaded := model.NewModel() |
| 107 | + err = reloaded.LoadModelFromText(conf) |
| 108 | + if err != nil { |
| 109 | + t.Fatalf("reload model: %v", err) |
| 110 | + } |
| 111 | + for _, l := range strings.Split(saved, "\n") { |
| 112 | + if l == "" { |
| 113 | + continue |
| 114 | + } |
| 115 | + err = persist.LoadPolicyLine(l, reloaded) |
| 116 | + if err != nil { |
| 117 | + t.Fatalf("LoadPolicyLine on saved line %q: %v", l, err) |
| 118 | + } |
| 119 | + } |
| 120 | + |
| 121 | + rules, err := reloaded.GetPolicy("p", "p") |
| 122 | + if err != nil { |
| 123 | + t.Fatalf("GetPolicy: %v", err) |
| 124 | + } |
| 125 | + if len(rules) != 1 { |
| 126 | + t.Fatalf("expected 1 rule after round-trip, got %d (saved: %q)", len(rules), saved) |
| 127 | + } |
| 128 | + if rules[0][3] != condWithComma { |
| 129 | + t.Errorf("cond field corrupted after round-trip: got %q, want %q", rules[0][3], condWithComma) |
| 130 | + } |
| 131 | +} |
| 132 | + |
64 | 133 | func Test_StringRbac(t *testing.T) { |
65 | 134 | conf := ` |
66 | 135 | [request_definition] |
|
0 commit comments