リソース拡張ガイド¶
項目
リソース拡張とは¶
intra-mart Accel Platform では標準的に以下のようなコンポーネントが認可機構と連携しています。
- ルータ
- メニュー
- ポータル
- IM共通マスタ(会社)
それぞれのコンポーネントの持つ特長によって、リソースの階層構造や使用できるアクションが異なっています。
認可機構ではリソースの階層構造によって継承による権限の継承が起こるため、これを利用して管理者の設定の手間を軽減できるようリソースの階層構造を決定すべきです。リソースのアクションについても、リソースの特性と組み合わせて認可設定の際の意味の分かりやすさを鑑みて設計されていなければなりません。
アプリケーションを認可機構と連携させるに当たり、上記に挙げたコンポーネント同様に独自のリソース構造やアクションを独自に定義したい場合、リソースの拡張を作成して実現することができます。
ここではリソースの拡張を行うための手順について説明します。
大まかな流れ¶
リソースタイプの拡張を行うには下記に示す実装と合わせて、認可機構にリソースに関連する情報の登録が必要になります。
アプリケーションのリソースを認可機構でどう表現するかを決めます。
以下のような事を作業を開始する前に決めておくと作業がスムーズに進められます。個々の詳細については後述します。
- リソースが使用するアクション
- リソースのURI書式
- リソースのグルーピングと階層構造
ResourceType クラスを実装します。( 図中 1 )
認可機構へのプラグインとしてリソースタイプクラスを実装します。
リソースタイプは認可対象となる実体の情報から認可機構上のリソースへの関連付けやリソースの持つアクションやURI書式についての責務を持っています。
管理者が認可設定ができるように、アプリケーションのリソースを認可機構へ登録します。
認可設定を管理する対象はリソースとして予め認可機構に登録しておかなければなりません。稼働前に必要になるリソースグループやリソースの情報がある場合はインポートファイルとして用意しておき、セットアップなどで投入しておきます ( 図中 2-a ) 。 アプリケーション側で認可対象としたいものが増えたり減ったりした場合、それに合わせて認可機構上のリソースも追加削除が必要になります ( 図中 2-b ) 。
認可処理をアプリケーションに組み込みます。
ここまでで認可リソースの準備ができているはずなので、アプリケーションに認可機構と連携する実装を組み込みます ( 図中 3 ) 。
- 適切なタイミングでリソースに対して認可要求を行う
- アプリケーションで登録したリソースの認可設定を認可設定画面部品を呼び出して行う
必要であれば、リソースのキャッシュを実現する ResourceTypeCacheController クラスを実装します。 ( 図中 4 ) 。
リソースが頻繁に利用される場合は、キャッシュを組み込むことでパフォーマンスを改善できます。キャッシュを組み込む際には、リソースのキャッシュコントローラクラスを実装します。
キャッシュコントローラは、リソースタイプごとに定義することができます。キャッシュコントローラを実装しない場合、リソース情報取得のたびにデータベースへのアクセスが発生します。
リソースを認可機構でどう表現するかを決める¶
アクションの決定¶
まずリソースがどんなアクションをとりうるかを明確にしておきます。
サンプルアプリケーションでは単純なデータのCRUD操作を扱うので、以下のアクションを定義することにします。
- Create (作成)
- Read (参照)
- Update (更新)
- Delete (削除)
リソースURI書式の決定¶
リソースを認可機構上でどう識別するかを定義します。
リソースはURI表記でシステム上一意になる文字列で表現します。
例: service://tenant/default_home認可側では <リソースタイプID>: で始まる点と使用可能な文字について制約を設けています(リソースタイプIDについては後述)。
大体の場合において、次のような書式が必要となるでしょう。
<リソースタイプID>:<アプリケーションの識別子><機能内の識別子1><機能内の識別子2> ... <リソースのID>サンプルアプリケーションでは単一のIDで識別可能なデータを扱うので、 割り当てるURIのパターンとして以下のように設計しました。
sample-data://im-authz-ext-sample/data/<データのID>
リソースのグループ構造の決定¶
認可機構内ではリソースは木構造になっていますが、アプリケーションが必要とするリソースをどこに格納するか予め設計しておく必要があります。
単一の根から葉に渡る木構造をひとまとまりとしてリソースグループセットと呼称していますが、機能によってはリソースグループセットを予約しています。例えばメニューグループ用には im-menu-group というIDのリソースグループセットが予約されています。
単純に画面を追加して画面に対する表示制御を行いたいのであれば既に http-services というリソースグループがありますので そのリソース構造に組み入れればよいでしょう。メニューの場合、im-menu-group というIDのリソースグループセットを APIが自動的に管理していますので、他のアプリケーションがこのリソースグループにリソース登録を行うのは適切ではありません。
新しいアプリケーション用に独自のリソースを作りたいのであれば基本的には新たなリソースグループセットを追加する方が良いでしょう。
他の機能の木にリソースを組み入れるか、独自のリソースグループセットを追加するかは、事前に検討してください。
独自のリソースグループセットを作成する場合、他のリソースグループと競合しないよう注意してください。intra-mart Accel Platform で予約されているリソースグループセットについては「認可仕様書」に一覧がありますので、そちらを参照してください。
サンプルアプリケーションでは サンプルのセットアップ手順 でインポート資材から sample-authz-data-crud というIDのリソースグループセットを追加しています。
sample-authz-resource-group.xml (リソースグループ追加資材)
<?xml version="1.0" encoding="UTF-8"?> <root xmlns="http://www.intra-mart.jp/authz/imex/resource-group"> <authz-resource-group id="sample-authz-data-crud"> <display-name> <name locale="ja">サンプルアプリケーション</name> </display-name> </authz-resource-group> </root>
リソース構造の設計¶
権限設定は木構造に従って継承が起こります。このためツリー上の一番末端のノードに対して一つ一つ権限を設定しなくても、 ある程度上位のノードに設定するだけで末端のノードに対して設定を適用することができます。この特性を考慮して管理ユーザの利便性を図りつつリソースの構造を設計しておきます。リソースグループにはそれぞれIDが必要になりますので、リソースの構造と合わせてどのようなID体系を使用するかについても考えておきます。
サンプルでは単純に以下のような構造を考えます。
- sample-authz-data-crud (アプリケーションのルートのリソースグループ)
- sample-authz-data-crud-data-<データのID> (アプリケーションで操作するデータに対応するリソース)
sample-authz-data-crud はアプリケーション用のリソースグループセットのルートになります。アプリケーション側でデータが追加されるとそれと連動して sample-authz-data-crud の配下にリソースを追加していきます。リソースを作成すると対となるグループが生成されますので、そのグループのIDの採番方式も決めておきます。ここでは連動するデータのIDを含めて以下のような形にしておきます。
sample-authz-data-crud-data-<データのID>
ResourceType の実装¶
ResourceTypeとは、リソースの特性を表す定義です。
- リソースがどのようなアクションを持つかを定義します
- リソースのモデルクラスを決定します
- リソースがどのようなURI体系を持つかを定義します
新たにResourceTypeを追加するにはResourceTypeインタフェースを実装するクラスとその関連クラスが必要になります。
ResourceType インタフェース¶
リソースタイプは以下のインタフェースを実装する必要があります。
jp.co.intra_mart.foundation.authz.model.resources.ResourceType<T>これを実装するためには、あわせて以下のクラスの実装が必要になります
- ResourceTypeが返すActionクラス群
- ResourceTypeの型引数になっているクラスT (リソースのモデルクラス)
このインタフェース定義から、このクラスで実装しなければいけないポイントは以下の5つです。
- リソースタイプIDを決定する
- リソースタイプIDはシステム内で重複してはいけません。
- 255文字までの英数、ハイフンで構成されていなければなりません
- このリソースタイプに関連付けられるリソースモデルの型を決定する
- リソースモデルはリソースタイプに対して1対1で紐づけられます。この紐づけはシステム上で重複してはいけません。
- 上記に反しないのであれば、このモデルのために新たなクラスを作成する必要はありません。
- このリソースタイプを持つリソースがとることのできる操作(Action)を明確にする
- このリソースに関連するアクションがすべてわかる必要があります。
- アクションはリソースタイプに紐づいており、認可機構上はリソースタイプ+アクションで一意に識別されます。
- リソースモデルのURI表現をサポートする
- リソースモデルをURI表現に変換できる必要があります。
- Actionの文字列表現をサポートする
- 文字列からActionクラスへパースできる必要があります。
- アクションの文字列表現は100文字以内の英数、ハイフン、アンダースコアで構成されていなければなりません。
サンプルアプリケーションではCRUD(Create, Read, Update, Delete) の操作を持つリソースタイプを定義しています。以下がその実装例です。
/** * SampleDataResourceType クラス * @author INTRAMART * @version 8.0 */ public class SampleDataResourceType implements ResourceType<SampleDataModel> { public static final String TYPE_ID = "sample-data"; public static final String ROOT_ID = "sample-authz-data-crud"; public static final String IDPREFIX = "sample-authz-data-crud-data-"; private static final long serialVersionUID = -1025455140074239366L; @Override public String createResourceUri(final SampleDataModel model) throws UnexpectedResourceModelReceivedException { return TYPE_ID.concat("://im-authz-ext-sample/data/").concat(model.getDataId()); } @Override public List<Action> getAllActions() { final List<Action> actions = new ArrayList<Action>(); actions.add(new C(this)); actions.add(new R(this)); actions.add(new U(this)); actions.add(new D(this)); return actions; } @Override public String getResourceTypeId() { return TYPE_ID; } @Override public Action parseAction(final String action) { if ("C".equals(action)) { return new C(this); } if ("R".equals(action)) { return new R(this); } if ("U".equals(action)) { return new U(this); } if ("D".equals(action)) { return new D(this); } throw new RuntimeException("invalid action :" + action); } }以下がモデルクラスの実装例です。
この例のモデルクラスはデータのIDだけを格納するものになっています。実際に実装する際にはリソースを一意に特定するために必要な情報を収めたクラスにしてください。既述のとおり、すでに存在するクラスで共用が可能ならばそれでもかまいません。
/** * SampleDataModel クラス * @author INTRAMART * @version 8.0 */ public class SampleDataModel { private String dataId; public SampleDataModel(final String id) { dataId = id; } public String getDataId() { return dataId; } public void setDataId(final String dataId) { this.dataId = dataId; } }
リソースタイプを認可機構に登録するための設定¶
%CONTEXT_PATH%/WEB-INF/conf/authz-resource-type-config/ に、設定ファイルを追加します。
この詳細については「設定ファイルリファレンス」、または「認可仕様書」を参照してください。
<?xml version="1.0" encoding="UTF-8"?> <p:authz-resource-type-config xmlns:p="http://www.intra-mart.jp/authz/authz-resource-type-config/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.intra-mart.jp/authz/authz-resource-type-config/ ../../../../../im_authz_impl/src/main/schema/authz-resource-type-config.xsd"> <resource-type type-class="sample.resource.type.SampleDataResourceType" model-class="sample.resource.type.SampleDataModel" /> </p:authz-resource-type-config>
- 要素 <authz-resource-type-config>
- この設定ファイルのルートノードです。
- 要素 <resource-type>
- リソースタイプ一つ分の定義です。複数定義可能です。
- 属性 type-class
- このリソースタイプのクラスを完全修飾クラス名で設定します。
- 属性 model-class
- このリソースタイプで使用するモデルクラスを完全修飾クラス名で設定します。
- type-class で指定しているクラスの型引数に指定されているクラスと一致していなければなりません。
この設定と、設定に書かれたクラスを配置し、再起動すれば認可機構でこのリソースタイプIDから始まるリソースURIを取り扱うことが可能になります。
アプリケーションと認可処理を連携するには、アプリケーション側で連携のための実装を行う必要があります。具体的には以下の2つの点です。
- アプリケーションの必要なポイントで認可要求を発行する実装を組み込むこと
- 認可要求が発生する前に認可機構へリソースを登録しておくこと
以降の節ではAPIやインポートを使用したリソースの登録方法と、アプリケーションへの認可要求の組み込みについて説明します。
リソースの連携¶
管理者が認可設定を行うためには、あらかじめリソースとして登録されていなければ認可対象が存在することがわかりません。運用中にリソースをリアルタイムに増減させたい場合などは、必要なタイミングで認可機構のAPIを呼び出してリソース登録を行う必要があります。
APIから認可リソース登録を行う場合は ResourceManager クラスを使用します。
今回のサンプルアプリケーションでは、以下のようなタイミングで認可リソースを変更します。
- データを登録されたタイミングで、対応する認可リソースも登録する。
- データのタイトルが更新されたタイミングで、認可リソースの名称を更新する。
- データを削除されたタイミングで、対応する認可リソースも削除する。
登録する内容はドキュメントの前節までに挙げてきた例から、以下のような内容とします:
- リソースグループセットの先頭のリソースグループ ( id: sample-authz-data-crud )があるものとします。
- 上記のリソースグループ配下にアプリケーションのデータに対応するリソースを追加します。
- リソースのURI書式は sample-data://im-authz-ext-sample/data/<データのID> 。 (ただし、リソースタイプがリソースモデルからURIを生成するため、このコード例には現れません)
- リソースとセットで作成されるリソースグループのIDは sample-authz-data-crud-data-<データのID>
サンプルでは上記の処理をユーティリティクラスとして実装しています。以下では該当箇所のみ解説します。ソースコードは以下のクラスを参照してください。
sample.resource.link.Linkageまずリソースの登録処理です。
/** * データに対応するリソースを作成します。 * @param id データのID * @param title データのタイトル * @throws UnexpectedResourceModelReceivedException */ public static void create(final String id, final String title) throws UnexpectedResourceModelReceivedException { // リソースを登録する際には ResourceManagerが必要です。 // ResourceManagerはファクトリクラスからインスタンスを取得します。 final ResourceManager manager = ResourceManagerFactory.getInstance().getResourceManager(); // データのIDを使用してモデルクラスを作成します。 final SampleDataModel model = new SampleDataModel(id); // リソースを登録する先のリソースグループ(ルートのグループ)を取得します。 // SampleDataResourceType.ROOT_ID は im-authz-sample-crud final ResourceGroup parent = manager.getResourceGroup(SampleDataResourceType.ROOT_ID); // 名称を作成します。本来ならテナントでサポートされている分の名称を登録すべきです。 final AccountContext context = Contexts.get(AccountContext.class); final I18nValue<String> name = new I18nValue<String>(context.getLocale(), title); // ルートのグループを親に、リソースの登録を行います。 manager.registerAsResource(model, name, SampleDataResourceType.IDPREFIX.concat(id), parent); }データのIDとタイトルを引数に受け、IDからリソースのURIとグループのIDを生成し、タイトルをリソースの名称として使用しています。
次はデータが削除された場合にリソースを削除する処理です。
/** * リソースの削除を行います。 * @param id データのID */ public static void remove(final String id) { final ResourceManager manager = ResourceManagerFactory.getInstance().getResourceManager(); // リソースグループを削除すると、対応するリソースも削除されます。 // ここではリソースグループのIDを直接指定して、リソースを削除しています。 manager.removeResourceGroup(SampleDataResourceType.IDPREFIX.concat(id)); }コメントにもありますが、リソースを消す場合はリソースに1対1で紐づいているリソースグループを削除します。 これでリソースも削除されます。
次はデータのタイトルが変更された際、リソースの名称に適用する更新処理です。
/** * リソースの名称を更新します。 * @param id データのID * @param title 更新する名称 */ public static void update(final String id, final String title) { final ResourceManager manager = ResourceManagerFactory.getInstance().getResourceManager(); // 名称を作成します。本来ならテナントでサポートされている分の名称を登録すべきです。 final AccountContext context = Contexts.get(AccountContext.class); final I18nValue<String> name = new I18nValue<String>(context.getLocale(), title); // 名称はリソースではなく、リソースに対応するリソースグループが保持しています。 // このため、リソースグループに対して 名称の更新を行います。 manager.setResourceGroupNames(SampleDataResourceType.IDPREFIX.concat(id), name); }サンプルアプリケーションでは画面でデータの追加・更新・削除操作をされるたびにスクリプト開発モデルのファンクションコンテナから上記のユーティリティを呼び出すことでリソースの連携を行っています。
コラム
サンプルアプリケーションはサンプルとしてシンプルにするために画面系の実装から直接リソースの連携を行っていますが、 設計としてはアプリケーションのモデルを扱うAPIをまず設計し、データベースへアプリケーションのデータを追加/削除すると同時に 認可リソースへの連携を行う等、アプリケーションデータと認可リソースの間で齟齬を起こさない設計であることが理想的です。
認可処理を組み込む¶
APIによる認可要求¶
アプリケーション固有のデータに対する認可処理を行う場合、APIなどでアクセスしようとするデータをURIに変換し、実行しようとするアクションとともに認可要求を行わなければなりません。
通常のWeb環境では認可サブジェクトコンテキストが存在するので、サブジェクトに関しては認可クライアント側で自動的に解決されます。リソースのURIについてはリソースタイプが登録されていればリソースモデルから変換が行われますので、リソースモデルとアクションがわかれば認可クライアントを介して認可要求を実行できます。
サンプルではリソースの連携用のユーティリティで認可要求の実装をしています。以下では該当箇所のみ解説します。ソースコードは以下のクラスを参照してください。
sample.resource.link.Linkage/** * データのIDとアクションから認可要求を行います。 <br> * このリソースタイプのアクションは * <ul> * <li>{@link C} 登録</li> * <li>{@link R} 参照</li> * <li>{@link U} 更新</li> * <li>{@link D} 削除</li> * </ul> * の4種があります。 * @param id データのID * @param action アクション("C","R","U","D") * @return 権限があればtrue, 無ければfalse * @throws UnexpectedResourceModelReceivedException */ public static boolean hasPermission(final String id, final String action) throws UnexpectedResourceModelReceivedException { // idを使用してリソースモデルを作成 final SampleDataModel model = new SampleDataModel(id); // 認可クライアントをファクトリから取得 final AuthorizationClient client = AuthorizationClientFactory.getInstance().getAuthorizationClient(); // 認可要求を実行 final AuthorizeResult result = client.authorize(model, action); // 結果を返します。 return AuthorizeResult.Permit.equals(result); }上記のように認可クライアントをファクトリから取得して、認可要求を実行します。リソースモデルがリソースタイプとともに認可機構に登録されていれば、リソースモデルを使用して認可要求をすることができます。結果はAuthorizationResult型のenumが返されますので、Permitであるかをみて処理を続行するかどうかを決めます。
imartタグ、カスタムタグによる認可要求¶
タグを使用して権限によって画面の表示可能領域を制御することができます。
Java EE 開発モデル( JSP )の例
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://www.intra-mart.co.jp/taglib/im-tenant" prefix="imt" %> <h1>認可要求のサンプル</h1> <imt:imAuthz uri="service://authz/settings/basic" action="execute" > <div>認可されていればここが表示されます。</div> </imt:imAuthz> <imt:imAuthz uri="service://authz/settings/basic" action="execute" negative="<%= Boolean.TRUE %>"> <div>認可されていなければここが表示されます。</div> </imt:imAuthz>注意
属性 negative は intra-mart Accel Platform 2013 Autumn 以降のバージョンで利用可能です。
スクリプト開発モデル(プレゼンテーションページ)の例
<h1>認可要求のサンプル</h1> <imart type="imAuthz" uri="service://authz/settings/basic" action="execute" > <div>認可されていればここが表示されます。</div> </imart> <imart type="imAuthz" uri="service://authz/settings/basic" action="execute" negative> <div>認可されていなければここが表示されます。</div> </imart>注意
属性 negative は intra-mart Accel Platform 2013 Autumn 以降のバージョンで利用可能です。
これらのタグを使用する場合にはリソースのURIとアクションがわかっている必要があります。サンプルアプリケーションでは、各データのuriをファンクションコンテナで求めておき、各アクション毎の権限によって「削除」や「変更」のボタンの表示非表示を切り替えています。
<table class="imui-table"> <!-- アプリケーションのデータを一覧で表示 --> <imart type="repeat" list=data item="item"> <tr> <td> <!-- 削除アクションの権限がない場合は削除ボタンを表示しない --> <imart type="imAuthz" uri=item.uri action="D"> <imart type="imuiButton" value="削除" class="imui-button right sample-delete" data-id=item.data_id /> </imart> <!-- 更新アクションの権限がない場合は変更ボタンを表示しない --> <imart type="imAuthz" uri=item.uri action="U"> <imart type="imuiButton" value="変更" class="imui-button right sample-update" data-id=item.data_id /> </imart> <!-- 参照アクションの権限がある場合は参照リンクを表示 --> <imart type="imAuthz" uri=item.uri action="R"> <h1><a id='<imart type="string" value=item.data_id />' href="javascript:void(0)" class="sample-data"><imart type="string" value=item.title /></a></h1> </imart> <!-- 参照アクションの権限がない場合は参照リンクを表示しない --> <imart type="imAuthz" uri=item.uri action="R" negative> <h1><imart type="string" value=item.title /></h1> </imart> <div>(<imart type="string" value=item.uri />)</div> </td> </tr> </imart> </table>
認可設定画面部品の使用¶
アプリケーション用にリソースグループセットを新たに追加した場合、アプリケーション側の管理画面として認可設定画面を表示することができます。このためにポリシー部分編集定義の設定を追加します。
ポリシー部分編集定義はリソースグループセットに対して権限設定に使用するサブジェクトタイプを選択して、部分的な認可設定を可能にするために定義する設定ファイルです。
認可設定画面はこのポリシー部分編集定義を集めて表示されますので、この設定がないと認可設定画面にも表示されません。
この設定の詳細については「設定ファイルリファレンス」、または「認可仕様書」を参照してください。
<?xml version="1.0" encoding="UTF-8"?> <authz-partial-policy-edit-config xmlns="http://www.intra-mart.jp/authz/authz-partial-policy-edit-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.intra-mart.jp/authz/authz-partial-policy-edit-config ../../schema/authz-partial-policy-edit-config.xsd"> <part-config> <part-id>im_authz_ext_sample</part-id> <caption-cd>CAP.Z.SAMPLE.AUTHZ.PARTCONFIG.TITLE</caption-cd> <resource-groups> <resource-group-id>sample-authz-data-crud</resource-group-id> </resource-groups> <subject-types> <subject-type-id>sample-prof-keep-alive</subject-type-id> <subject-type-id>sample-resource-owner</subject-type-id> </subject-types> </part-config> </authz-partial-policy-edit-config>今回例示してきた内容では リソースグループセットを追加していますので、使用するリソースグループIDにそのルートとなるリソースグループのID( id: sample-authz-data-crud ) を指定し、この配下のリソースをアプリケーションの管理機能の一部として認可設定できるようにしています。
またこの編集定義で使用できるサブジェクトタイプを sample-prof-keep-alive と sample-resource-owner の2種に設定しています。これらのサブジェクトタイプは サブジェクト拡張ガイド でサンプルとして実装しているものです。sample-prof-keep-alive は「プロファイルの有効期間がXXカ月以上」 というサブジェクトを追加するためのサブジェクトタイプでsample-resource-owner アプリケーションデータの作成者を「リソースオーナー」として扱うサブジェクトタイプです。
この設定を追加すると認可設定画面の左上「リソースの種類」のセレクトボックスに、この設定の選択肢が追加されます。
さらにアプリケーションの管理画面などで上記で設定した部分の認可設定画面を部品として呼び出すことができます。imAuthzPolicyEditorタグを使用して以下のように指定すると、画面にボタンが表示され、ポップアップ画面として認可設定画面を呼び出せます。
<imart type="imAuthzPolicyEditor" displayType="button" partId="im_authz_ext_sample">認可設定を開く</imart>partId には 上記で作成した設定ファイルで指定した part-id を指定します。そのほかのパラメータや、使い方の詳細についてはAPIリストを参照してください。
デフォルトでは、認可設定画面を部品として利用できるユーザは、認可設定の基本画面を開くことができる権限を持つユーザに限られます。それ以外の権限状態で認可設定画面を部品として利用可能にする方法の詳細は「リソース表示可否判断クラスの設定 」を参照してください。
リソース表示可否判断クラスの設定¶
通常、imAuthzPolicyEditorタグで認可設定画面を部品として利用できるユーザは、認可設定の基本画面を開くことができる権限を持つユーザに限られます。これは、通常認可設定ができないユーザに認可設定画面を利用させないようにするために、認可機構で制限しています。
しかし、認可設定画面を部品として利用する場合に、特定のリソースに対して呼び出し側の機能の権限に基づいて設定可否を判断したい場合があります。例えば、メニュー設定画面を開くことができるユーザが、登録したメニューグループに対して認可権限を設定するケースです。
認可機構側では個々のリソースグループに対して表示可否を判断できないため、このような細かなリソースグループの表示制御を行いたい場合に、各機能に問い合わせを行って表示可否を判断してもらうコールバック機能があります。
imAuthzPolicyEditorタグではこのコールバック機能を使用して、imAuthzPolicyEditorタグを使用する側の機能へ問い合わせを行います。コールバックの設定はポリシー部分編集定義の設定で行います。
コラム
intra-mart Accel Platform 2013 Autumn 以降のバージョンを利用する場合、認可設定の基本画面を開くことができる権限を持つユーザは、コールバックの設定に関わらずすべてのリソースグループが表示されます。
<?xml version="1.0" encoding="UTF-8"?> <authz-partial-policy-edit-config xmlns="http://www.intra-mart.jp/authz/authz-partial-policy-edit-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.intra-mart.jp/authz/authz-partial-policy-edit-config ../../schema/authz-partial-policy-edit-config.xsd"> <part-config> <part-id>im_authz_ext_sample</part-id> <caption-cd>CAP.Z.SAMPLE.AUTHZ.PARTCONFIG.TITLE</caption-cd> <resource-groups> <resource-group-id>sample-authz-data-crud</resource-group-id> </resource-groups> <subject-types> <subject-type-id>sample-prof-keep-alive</subject-type-id> <subject-type-id>sample-resource-owner</subject-type-id> </subject-types> <callbacks> <!----- この行を追加 -----------> <resource-group-authorizer>sample.resource.type.SampleDataResourceGroupAuthorizer</resource-group-authorizer> <!----- この行を追加 -----------> </callbacks> <!----- この行を追加 -----------> </part-config> </authz-partial-policy-edit-config>resource-group-authorizer で指定したクラスには、認可設定画面を部品として開く際に表示対象のリソース情報が渡されます。この表示可否判断クラスはimAuthzPolicyEditorタグを使用する各機能側で用意します。
表示可否判断クラスを作成するためには、 AuthzPartialResourceGroupAuthorizer インタフェースを実装するか、 AuthzPartialResourceGroupAuthorizerHelper クラスを継承するクラスが必要になります。
AuthzPartialResourceGroupAuthorizer インタフェースを実装する場合
AuthzPartialResourceGroupAuthorizer インタフェースでは、リソースグループIDのセットを受け取ります。表示対象のリソースグループが複数ある場合でも、認可機構によって一度だけ呼ばれます。
表示対象のリソースグループにかかわらず一律に表示可否の判断ができる場合や、リソースグループIDから判断可能な場合は、こちらの方法を採用した方が高速に動作します。
AuthzPartialResourceGroupAuthorizerHelper クラスを継承する場合
AuthzPartialResourceGroupAuthorizerHelper クラスでは、リソースグループIDが認可のリソース情報に変換され、それを受け取ります。表示対象のリソースグループ配下に存在するリソースの数分だけ、認可機構によって呼ばれます。
表示対象のリソースで表示可否を判断する場合は、こちらの方法を採用した方が便利です。
サンプルアプリケーションでは、AuthzPartialResourceGroupAuthorizerHelper クラスを継承して、サンプルデータの読み取り権限がある場合のみ表示する実装を定義しています。以下がその実装例です。
/** * サンプルのリソースグループ表示可否判断クラス * @author INTRAMART * @version 8.0.3 */ public class SampleDataResourceGroupAuthorizer extends AuthzPartialResourceGroupAuthorizerHelper { @Override public AuthorizeResult authorize(final AuthorizationClient client, final Resource resource) throws UnexpectedResourceModelReceivedException { // サンプルのリソースタイプの場合は判断不可 final ResourceType<?> resourceType = resource.getType(); if (!SampleDataResourceType.TYPE_ID.equals(resourceType.getResourceTypeId())) { return AuthorizeResult.Deny; } // 読み取り権限があるかどうか確認 final Action action = resourceType.parseAction("R"); return client.authorize(resource, action); } }
リソース情報をキャッシュする¶
リソース情報をキャッシュするためには、 ResourceTypeCacheController インタフェースを実装するクラスが必要になります。この実装クラスはリソースタイプごとに定義することができ、複数のリソースタイプで共通の実装を利用することもできます。
リソースのキャッシュコントローラは、リソースURIとリソースグループIDの関係をキャッシュする責務を持っています。キャッシュするサイズやキャッシュをクリアするタイミングなどは、実装や設定を変更することでリソースタイプごとに変化させることができ、リソースタイプにおける特性などからキャッシュの戦略を細かく制御することができます。
ResourceTypeCacheController インタフェース¶
リソースのキャッシュコントローラは以下のインタフェースを実装する必要があります。
jp.co.intra_mart.foundation.authz.services.admin.impl.cache.ResourceTypeCacheControllerこのインタフェース定義から、このクラスで実装しなければいけないポイントは以下の4つです。
- 全てのキャッシュをクリアする
- 一部のキャッシュをクリアする (任意)
- リソースをキャッシュする
- キャッシュからリソースを取得する
サンプルアプリケーションでは、アプリサーバのメモリに直接リソースの情報を記憶する実装を定義しています。以下がその実装例です。
/** * SampleDataResourceTypeCacheController クラス * @author INTRAMART * @version 8.0.3 */ public class SampleDataResourceTypeCacheController implements ResourceTypeCacheController { /** キャッシュ */ private static final ConcurrentMap<String, String> cache = new ConcurrentHashMap<String, String>(); @Override public void clearCache() throws ResourceGroupCacheUpdateException { // 全てのキャッシュをクリア cache.clear(); } @Override public void clearCache(final ResourceGroupChangedEvent e) throws ResourceGroupCacheUpdateException { // リソースグループが削除された場合のみ if (ResourceGroupChangedEvent.EventType.DELETE.equals(e.getEventType())) { // 指定されたリソースグループIDに該当するキャッシュをクリア for (final Entry<String, String> entry : cache.entrySet()) { if (e.getResourceGroupIds().contains(entry.getValue())) { cache.remove(entry.getKey()); } } } } @Override public String getResourceGroupId(final String resourceURI) { // キャッシュから、リソースURIに対応するリソースグループIDを取得 return cache.get(resourceURI); } @Override public void setResourceGroupId(final String resourceURI, final String resourceGroupId) { // キャッシュに対して、リソースURIに対応するリソースグループIDを設定 cache.put(resourceURI, resourceGroupId); } }注意
このサンプルではアプリサーバのメモリに直接記憶していますが、アプリサーバを複数台構築した分散環境の場合、全てのサーバに対してキャッシュクリアの要求を行い、その要求を受け取る実装を追加する必要があります。
キャッシュクリアの要求を行わない場合、サーバによってキャッシュの内容に不整合が発生してしまい、接続されたサーバによって認可の判断結果が異なる事象が発生する可能性があります。
キャッシュコントローラを使用するための設定¶
%CONTEXT_PATH%/WEB-INF/conf/authz-resource-type-config/ の設定ファイルに、 cache-class 属性を追加します。
この詳細については「設定ファイルリファレンス」、または「認可仕様書」も参照してください。
<?xml version="1.0" encoding="UTF-8"?> <p:authz-resource-type-config xmlns:p="http://www.intra-mart.jp/authz/authz-resource-type-config/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.intra-mart.jp/authz/authz-resource-type-config/ ../../../../../im_authz_impl/src/main/schema/authz-resource-type-config.xsd"> <resource-type type-class="sample.resource.type.SampleDataResourceType" model-class="sample.resource.type.SampleDataModel" cache-class="sample.resource.type.SampleDataResourceTypeCacheController" /> <!----- この行を追加 -----------> </p:authz-resource-type-config>
- 属性 cache-class
- このリソースタイプで使用するキャッシュコントローラクラスを完全修飾クラス名で設定します。
この設定と、設定に書かれたクラスを配置し、再起動すれば認可機構でこのリソースタイプが使用される際にキャッシュ機構を使用することが可能になります。