メインコンテンツにスキップ

ABAC

Understanding ABAC

Attribute-Based Access Control (ABAC) determines access permissions by evaluating the properties of subjects, objects, and actions rather than relying solely on identity strings. While standards like XACML provide comprehensive but complex ABAC implementations, Casbin offers a streamlined approach where structs or class instances replace simple string identifiers.

Consider this basic ABAC configuration:

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

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

[matchers]
m = r.sub == r.obj.Owner

The matcher references r.obj.Owner, expecting r.obj to be a structured object rather than a plain string. When you call Enforce(), Casbin uses reflection to access the Owner field from the provided object.

A typical resource structure looks like this:

type testResource struct {
Name string
Owner string
}

For JSON-based parameter passing, enable JSON request handling:

e, _ := NewEnforcer("examples/abac_model.conf")
e.EnableAcceptJsonRequest(true)

data1Json := `{ "Name": "data1", "Owner": "bob"}`

ok, err := e.Enforce("alice", data1Json, "read")
if err != nil {
// Handle JSON parsing errors
fmt.Printf("Enforcement failed: %v\n", err)
return
}

When JSON request handling is enabled, Casbin automatically detects and parses strings that begin with { or [. If a string looks like JSON but contains invalid syntax, Enforce() returns a clear error message indicating which parameter failed to parse. Plain strings that don't start with JSON delimiters are passed through unchanged, avoiding unnecessary parsing attempts.

// Valid JSON - automatically parsed
validJSON := `{"Name": "alice", "Age": 25}`
ok, err := e.Enforce(validJSON, "data1", "read") // Works correctly

// Invalid JSON - returns descriptive error
invalidJSON := `{"Name": "alice",}` // Trailing comma is invalid in JSON
ok, err := e.Enforce(invalidJSON, "data1", "read")
// Returns: "failed to parse JSON parameter at index 0: ..."

// Plain string - no parsing attempted
plainString := "alice"
ok, err := e.Enforce(plainString, "data1", "read") // Treated as plain string
メモ

Enabling JSON parameter support introduces a performance overhead of approximately 1.1 to 1.5x.

Using ABAC

Implementing ABAC requires two steps:

  1. Reference attributes within your model matcher.
  2. Supply struct or class instances as arguments to Enforce().
warning

ABAC attribute access works only for request elements (r.sub, r.obj, r.act). Policy elements like p.sub cannot use ABAC since policies cannot store struct or class definitions.

tip

Matchers can reference multiple attributes simultaneously. Example: m = r.sub.Domain == r.obj.Domain.

tip

When policies require commas that would conflict with CSV parsing, wrap the expression in quotation marks. Example: "keyMatch("bob", r.sub.Role)" prevents unwanted splitting.

Handling Complex ABAC Requirements

While the basic ABAC model works for simple scenarios, real-world authorization often demands intricate rule sets. For such cases, move rule complexity from the model into policies using the eval() function.

Model configuration with eval():

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub_rule, obj, act

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

[matchers]
m = eval(p.sub_rule) && r.obj == p.obj && r.act == p.act

Here, p.sub_rule holds expressions that reference request attributes. These expressions are evaluated dynamically during enforcement.

Policy definitions using attribute-based rules:

p, r.sub.Age > 18, /data1, read
p, r.sub.Age < 60, /data2, write