23時に寝て何度か起きて7時に起きた。夜に作業するつもりが、メイドインアビス を見ながら寝落ちした。

ldap で認証したユーザーの権限管理

rbac なロール管理 の仕組みを api サーバーに実装した。初期実装したときは静的にリソース (url) に対して acl から権限が許可されているかどうかのみをチェックするだけでよかった。ldap で認証したユーザーは自分の情報は更新できるが、他人の情報は更新できないといったリクエスト単位に権限が許可されているかどうかをミドルウェアで判別したい。いわば、リクエスト時に動的にリソースの情報をチェックしないといけない。

いくつか試行錯誤して、あーでもないこーどもないとやった結果、次のように落ち着いた。

  • リソースは動的な権限チェックのために AuthorizeFunc を取得するための AuthorizeKey をもつ
  • AuthorizeFunc は Context から取得する
  • AuthorizeFunc が true を返す場合は権限を付与する
func (r *Role) CanAccess(ctx context.Context, resourceName, target string) bool {
	for _, ac := range r.ACL {
		if ac.Resource.Match(resourceName) {
			for _, perm := range ac.Permissions {
				if perm.IsGranted(target) {
					return true
				}
			}
			if authorize, ok := ctx.Value(ac.Resource.Key).(AuthorizeFunc); ok {
				if authorize(ctx, resourceName, target) {
					return true
				}
			}
		}
	}
	return false
}

ロールに渡す Context にはあらかじめ、AuthorizeKey と AuthorizeFunc を登録しておく。

ctx = context.WithValue(ctx, role.LDAPResource, role.IsLDAPResourceOwner)

リソースを生成するときに AuthorizeKey をセットしておく。

ldapUserResource = rbac.NewResource(
	"ldap-user-specific-operation",
	"(/api/ldap/entry|/api/ldap/entry/.*)",
	LDAPResource,
)

ちょっと設定は煩雑になるが、ひとまずこれで要件を満たせた。