Wednesday, May 20, 2020

ResourcePermissionの考察 (1)

こんにちは。ウです。

みな様がLiferayカスタマイズをする時、権限周りのメソッド"シグネチャーに困ったことがありますか?例えば、PermissionCheckerとか、Liferay 7.1から新規したヘルパークラスModelResourcePermission.javaPortletResourcePermission.javaなどにおいてはメソッド中、このような定義がよく見えます。

//PermissionChecker
public boolean hasOwnerPermission(long companyId, String name, long primKey, long ownerId, String actionId);

public boolean hasPermission(Group group, String name, long primKey, String actionId);

// ModelResourcePermission
public void check(PermissionChecker permissionChecker, long primaryKey, String actionId);

public void check(PermissionChecker permissionChecker, T model, String actionId);

// PortletResourcePermission
public void check(PermissionChecker permissionChecker, Group group, String actionId);

どの場面でどのメソッドを利用しますか?利用の際どの値をメソッドに与えますか?そのメソッドシグネチャーはLiferayの権限管理の関係はどうですか?今回はこの権限周りにいて考察しようと思います。

ちなみに、みなさまはLiferayオフィシャルブログの権限関連記事を読んだことがありますか?この記事はLiferayのロールと権限の基本関係を説明しているのでぜひおすすめです。

Liferayの権限

みな様のご存知通り、Liferayの権限システムには、ポートレットリソースまたはモデルリソース毎の粒度で行われています。従って:

  • Liferayリソース(BlogJournalArticleまたはDLFileEntryなど)の初期パーミッションは全部ResourceLocalService.addResourcesに介してResourcePermissionテーブルにレコードを作成している(例:JournalArticleLocalServiceImpl.java)。
  • 逆に、PermissionCheckerがユーザの権限をチェックする際、同じくResourceLocalService.hasUserPermissionなどのメソッドを利用している(例:AdvancedPermissionChecker.java)。

すなわち、Liferayでは、ResourcePermissionPermissionCheckerを利用し本当のResourcePermissionテーブルの詳細情報を隠しています。Liferayの権限システムを深く理解したい場合、ResourcePermissionテーブルとリソース権限の関係を考察しないといけない理由はそこにあります。

ResourcePermissionテーブル

Liferayが行なっている権限管理はロールベースアクセス制御(RBAC)方式のため、最終的にデータベースに記入するレコードは以下の内容になります:
  • あるロールが
  • あるリソースに対して
  • どんな操作が許可される
ResourcePermissionテーブルはその三つの情報を含んでいます。上記Liferayオフィシャルブログ記事を参考して具体的に整理してみましょう。

  • name: リソース名
    • ポートレットリソース:ポートレットキー
    • モデルリソース:モデル名
  • primKey: リソースID(権限範囲)
    • 全Liferayインスタンス有効権限: companyId
    • グループ内有効: groupId
    • 具体的なリソースに対する権限:
      • モデルリソース: リソースprimKey
      • ポートレットリソース: layoutId + _LAYOUT_ + portletId
  • scope: 権限の範囲
    • 1: 全Liferayインスタンスに有効
    • 2: グループ内のみ有効
    • 3: グループテンプレート(サイト、組織)内のみ有効
    • 4: 具体的なリソースインスタンスに対する権限
  •  roleId: ロールID
  •  actionId: 権限が許可する操作

まとめると、以下のグラフのようにRBACに必要な情報をレコードで格納しています。


それでは、具体的にどのような内容が格納されるのかを確認しましょう。

考察

今回はLiferayの標準モジュールBlogポートレットを利用してResourcePermissionテーブル中一般ロールに対する権限の表現を確認しましょう。

一般ロール x モデルリソース

以下の準備を行いましょう:

  • 一般ロールblog_roleを作成する
  • blog_roleを開いて、権限定義に
    • ブログ/エントリー追加する権限を追加する
    • ブログのエントリ/表示権限を追加する

  • デフォルトサイトにブログポートレットを置き、その中にpermisison-blogというブログエンティティを作成する
  • permission-blogの権限定義に、
    •  blog_role表示更新を追加する


その後、ロールとResourcePermissionテーブルで確認しましょう。
select roleId, name, type_ from Role_ where name = "blog_role";
select resourcePermissionId, name, scope, primKey, primKeyId, roleId, actionIds from ResourcePermission where roleId = 50867;

結果は以下の通りです。
roleId ロール名 ロールtype
50867 blog_role 1
ID リソース名 scope primKey primKeyId roleId 操作
5207 com.liferay.blogs 1 20099 20099 50867 2
5218 com.liferay.blogs.model.BlogsEntry 1 20099 20099 50867 1
5219 com.liferay.blogs.model.BlogsEntry 4 50893 50893 50867 33

では、その結果はどのような権限を表すのかについて考察しましょう。
ID ロール どんなリソース どの操作※
5207 blog_role scope=1: liferayインスタンス20099中の全てcom.liferay.blogs ADD_ENTRY
5218 blog_role scope=1: liferayインスタンス20099中の全てcom.liferay.blogs.model.BlogsEntry VIEW
5219 blog_role scope=4: id=50893com.liferay.blogs.model.BlogsEntryインスタンス VIEW + UPDATE

一般ロール x ポートレットリソース

続いて、以下の準備を行いましょう。
  •  blog_roleを開いて、権限定義に
    • アプリケーション権限/ページに追加する権限を追加する

  • デフォルトサイトのブログポートレットに
    • ポートレット権限設定を開いてblog_role設定権限を追加する

それ後、ロールとResourcePermissionテーブルで確認しましょう。
select resourcePermissionId, name, scope, primKey, primKeyId, roleId, actionIds from ResourcePermission where roleId = 50867;

結果は以下の通りです(重複レコードを除外します)。
ID リソース名 scope primKey primKeyId roleId 操作
5222 com_liferay_blogs_web_portlet_BlogsPortlet 1 20099 20099 50867 2
5223 com_liferay_blogs_web_portlet_BlogsPortlet 4 38656_LAYOUT_com_liferay_blogs_web_portlet_BlogsPortlet 0 50867 4

では、その結果はどのような権限を表すのかについて考察しましょう。
ID ロール どんなリソース どの操作
5222 blog_role scope=1: liferayインスタンス20099中の全てBlogsPortlet ADD_TO_PAGE
5219 blog_role scope=4: id=38656のレイアウト上のBlogsPortlet CONFIGURATION

まとめ

ここまでチェックすると、権限を与えられるリソースは三種類があることがわかりました。
  • 具体的なインスタンスを持っていないリソース
    • そのモデルクラスは存在しないためインスタンス化できないため仮想モデルとして認識します。
      • 例:リソースcom.liferay.blogsはLiferayブログその概念を表すものと認識できます。
    • そのリソースに与えられる権限は、具体的なブログエンティティに関係ありません。
      • 権限例:新規作成、パーミッション設定、ブログの購読
    • 特定できるインスタンスに適用しないため、scopeは4になれません。
    • primKeyは権限が適用される範囲の対象を表します。
      • scope=1の場合、primKeyはliferayインスタンスIDです。
  • 任意ある種類のインスタンス化可能なリソース
    • 対象は任意Liferayモデルまたはポートレット
      • 例:リソースcom.liferay.blogs.model.BlogsEntry, scope=1は全Liferayインスタンス中の任意Liferayブログを表し、そのリソースに与える権限は全Liferayインスタンス中のブログで有効となります。
      • 例:リソースcom_liferay_blogs_web_portlet_BlogsPortlet, scope=1は全Liferayインスタンス中任意ブログポートレットを表し、そのリソースに与える権限は全Liferayインスタンス中のブログポートレットで有効となります。
    • 操作は具体的にインスタンスに対するアクションです。
      • 例:参照、更新、削除、コメント追加、ポートレット追加
    • 任意インスタンスに適応する権限のため、scopeは4になれません。
    • primKeyは権限が適用される範囲の対象を表します。
      • scope=1の場合、primKey=LiferayインスタンスID
  • 特定したリソース
    • 対象は任意Liferayモデルまたはポートレット
      • 例:リソースcom.liferay.blogs.model.BlogsEntry, scope=4primKeyに指定するブログエンティティと認識します。その権限はその特定のブログエンティティのみで有効です。
      • 例:リソースcom_liferay_blogs_web_portlet_BlogsPortlet, scope=4primKeyに指定するブログポートレットと認識します。その権限はその特定のブログポートレットので有効です。
    • 操作は具体的にインスタンスに対するアクションです。
    • primKeyは特定インスタンスのIDになります。
      • モデルリソースの場合、primKey=モデルID
      • ポートレットリソースの場合、primKey=layoutId + _LAYOUT_ + ポートレットキー
次回、サイトロールなどグループロールに与える権限を考察しようと思います。


※ actionIdの内容は以下のsqlで取得できます。
select name, actionId, bitwiseValue from ResourceAction where name="com.liferay.blogs" and bitwiseValue = 2;
select name, actionId, bitwiseValue from ResourceAction where name="com.liferay.blogs.model.BlogsEntry" and (bitwiseValue = 1 or bitwiseValue=32);
select name, actionId, bitwiseValue from ResourceAction where name="com_liferay_blogs_web_portlet_BlogsPortlet " and (bitwiseValue = 2 or bitwiseValue = 4);
リソース名操作bitwiseValue
com.liferay.blogsADD_ENTRY2
com.liferay.blogs.model.BlogsEntryVIEW1
com.liferay.blogs.model.BlogsEntryUPDATE32
com_liferay_blogs_web_portlet_BlogsPortletADD_TO_PAGE2
com_liferay_blogs_web_portlet_BlogsPortletCONFIGURATION4

No comments: