アクセス制御ライブラリ Casbin 使い方まとめ

アクセス制御（認可）ライブラリ [Casbin](https://casbin.org/) の使い方まとめ

## モデル定義

CasbinはPERM (Policy, Effect, Request, Matcher) ベースのアクセス制御モデルを採用している。モデル定義はconfファイルに記述するが、この中にはPERMに相当するPolicy Definition、Policy Effect、Request Definition、Matcherの4セクションを少なくとも記述する必要がある。

### Access Control List (ACL)

ファイルシステム等で使われるACLの[モデル定義](https://github.com/casbin/casbin/blob/master/examples/basic_model.conf)を題材に、Casbinのモデル定義方法を解説する。（参考：[Syntax for Models](https://casbin.org/docs/en/syntax-for-models)）

#### Request Definition

```go
[request_definition]
r = sub, obj, act
```

`[request_definition]` ではアクセス判定要求（access request）の入力となるモデルを定義する。ACLモデル定義のように、たいていの場合は `sub`（アクセス実行者）、`obj`（アクセス対象）、`act`（アクセス方法）の3つを利用する。

#### Policy Definition

```go
[policy_definition]
p = sub, obj, act
```

`[policy_definition]` ではポリシーの記述形式を定義する。このモデル定義で「 `file1 (obj)` を `user1 (sub)` が `read (act)` できる」というポリシーを記述すると `p, user1, file1, read` となる。

※ Casbinでは現在、policy definitionを1つのみしか定義できない制約がある。

#### Matcher

```
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
```

`[machers]` ではアクセス判定要求に合致するポリシーを探す条件式を定義する。アクセス判定要求 `r` とポリシー `p` それぞれの `[request_definition]` で定義したモデルを `.` で参照し、条件式を記述する。

ACLモデル定義では、アクセス判定要求の `sub`  `obj` `act` の全てが一致するポリシーを合致するものと判定されることになる。

※ Casbinでは現状、matcherを1つのみしか定義できない制約がある。（条件式に算術・論理演算子が使えるので、たいていの場合は1つで十分とのこと。）

#### Policy Effect

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

`[policy_effect]` ではアクセス判定要求に複数のポリシーが合致した場合に、どのように判定を行うかを定義する。

ACLモデル定義では、Matcherの条件式で合致するポリシーのうち `eft` が `allow` に設定されたものが1つでもある ( `some` ) 場合に許可判定となる。

この `eft` はアクセス不許可ポリシー（ブラックリスト）を定義するときにPolicy Definitionに定義する要素である。ACLモデル定義のように `eft` がPolicy Definitionに定義されていない場合は、`p.eft` は `allow` が設定されている（デフォルト値が `allow` ）とみなされる。アクセス不許可ポリシーの利用例は、[Supported Models](https://casbin.org/docs/en/supported-models)のDeny-overrideを参照。

### Role Based Access Control (RBAC)

RBACに対応するには、ACLのモデル定義から以下の2点を変更すればよい。（参考：[RBAC](https://casbin.org/docs/en/rbac)）

#### Role Definition

```go
[role_definition]
g = _, _
```

`[role_definition]`（オプショナルセクション）ではロールの記述形式を定義する。（ `[policy_definition]` のロール版と考えると理解しやすい。）

このモデル定義で `user1` への `role1` 割り当てを記述すると `g, user1, role1` となる。

#### Matchers

```go
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
```

`[matchers]` では、Role Definitionを関数として参照して、アクセス判定要求のアクセス実行者 `r.sub`（ユーザー）とポリシーのアクセス実行者 `p.sub` （ロール）の組み合わせに対応するポリシーが存在するかを判定する。

## 実装例（Java）

[rbac_model.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_model.conf)のモデル定義を読み込み、ロール、ポリシー追加、アクセス要求の判定を行う実装例を紹介する。

```java
/* モデル定義の読み込み */
Enforcer se = new Enforcer(ClassLoader.getSystemResource("rbac_model.conf").getFile());
// マルチスレッドで利用する場合はSyncedEnforcerクラスを使う
// Enforcer se = new SyncedEnforcer(ClassLoader.getSystemResource("rbac_model.conf").getFile());

/* ロール割り当て */
se.addNamedGroupingPolicy("g", "user1", "role1");
// デフォルトのロール（グループ）名 "g" に対して割り当てを行うメソッドも提供されている
//se.addGroupingPolicy("user1", "role1");
//se.addRoleForUser("user1", "role1");

se.addNamedPolicy("p", "role1", "data1", "read");
// デフォルトのポリシー名 "p" に対してポリシー追加を行うメソッドも提供されている
se.addPolicy("role1", "data1", "read");

/* アクセス要求判定 */
if (se.enforce("user1", "data1", "read")) {
	System.out.println("user1 can read data1.");
}
if (se.enforce("role1", "data1", "read")) {
	System.out.println("role1 can read data1.");
}

/* ユーザーのロール取得 */
List<String> roleList = se.getRolesForUser("user1");
System.out.println("user1 has " + roleList + " roles.");
```

実行結果

```
user1 can read data1.
role1 can read data1.
user1 has [role1] roles.
```