Skip to content

Commit

Permalink
feat: support "ABAC" model (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
liewstar authored Jan 11, 2025
1 parent bb1e417 commit 50ecee2
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 18 deletions.
40 changes: 22 additions & 18 deletions cmd/enforce.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ func handleEnforceResult(cmd *cobra.Command, res bool, explain []string, err err
encoder.Encode(response)
}

// createStructWithValue creates a struct with a single field and value.
func createStructWithValue(fieldName string, value interface{}) interface{} {
caser := cases.Title(language.English)
structType := reflect.StructOf([]reflect.StructField{
{
Name: caser.String(fieldName),
Type: reflect.TypeOf(value),
},
})

structValue := reflect.New(structType).Elem()
structValue.Field(0).Set(reflect.ValueOf(value))
return structValue.Interface()
}

// Function to parse parameters and execute policy check.
func executeEnforce(cmd *cobra.Command, args []string, isEnforceEx bool) {
modelPath, _ := cmd.Flags().GetString("model")
Expand All @@ -58,8 +73,8 @@ func executeEnforce(cmd *cobra.Command, args []string, isEnforceEx bool) {
panic(err)
}

// Define regex pattern to match format like {field: value}.
paramRegex := regexp.MustCompile(`{\s*"?(\w+)"?\s*:\s*(\d+)\s*}`)
// Define regex pattern to match format like {field: value} or {field: "value"}.
paramRegex := regexp.MustCompile(`{\s*"?(\w+)"?\s*:\s*(?:"?([^"{}]+)"?)\s*}`)

params := make([]interface{}, len(args))
for i, v := range args {
Expand All @@ -68,24 +83,13 @@ func executeEnforce(cmd *cobra.Command, args []string, isEnforceEx bool) {
fieldName := matches[1]
valueStr := matches[2]

// Convert value to integer.
// Try to convert value to integer first.
if val, err := strconv.Atoi(valueStr); err == nil {
// Dynamically create struct type.
caser := cases.Title(language.English)
structType := reflect.StructOf([]reflect.StructField{
{
Name: caser.String(fieldName),
Type: reflect.TypeOf(0),
},
})

// Create struct instance and set value.
structValue := reflect.New(structType).Elem()
structValue.Field(0).SetInt(int64(val))

params[i] = structValue.Interface()
continue
params[i] = createStructWithValue(fieldName, val)
} else {
params[i] = createStructWithValue(fieldName, valueStr)
}
continue
}
params[i] = v
}
Expand Down
4 changes: 4 additions & 0 deletions cmd/enforce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,8 @@ func Test_enforceExCmd(t *testing.T) {
abacArgs := []string{"enforceEx", "-m", "../test/abac_rule_model.conf", "-p", "../test/abac_rule_policy.csv"}
assertExecuteCommand(t, rootCmd, "{\"allow\":true,\"explain\":[\"r.sub.Age > 18\",\"/data1\",\"read\"]}\n", append(abacArgs, "{\"Age\":30}", "/data1", "read")...)
assertExecuteCommand(t, rootCmd, "{\"allow\":false,\"explain\":[]}\n", append(abacArgs, "{\"Age\":15}", "/data1", "read")...)

abacArgs = []string{"enforceEx", "-m", "../test/abac_model.conf", "-p", "../test/abac_policy.csv"}
assertExecuteCommand(t, rootCmd, "{\"allow\":true,\"explain\":[]}\n", append(abacArgs, "alice", "{\"Owner\":\"alice\"}")...)
assertExecuteCommand(t, rootCmd, "{\"allow\":false,\"explain\":[]}\n", append(abacArgs, "alice", "{\"Owner\":\"bob\"}")...)
}
11 changes: 11 additions & 0 deletions test/abac_model.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[request_definition]
r = sub, obj

[policy_definition]
p = sub, obj

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == r.obj.Owner
Empty file added test/abac_policy.csv
Empty file.

0 comments on commit 50ecee2

Please sign in to comment.