kagamihogeの日記

kagamihogeの日記です。

Apache Shiro Terminologyをテキトーに訳した

Apache Shiroのチュートリアルの一部で用語集に関する部分の https://shiro.apache.org/terminology.html をテキトーに訳した。

Apache Shiro Terminology

この用語集を読み終えるには2分程度ですが、Shiroではこれらの用語の理解は重要です。以下の用語と概念はドキュメント全般で使われているため、セキュリティ一般とShiroを素早く理解するのにこの用語集を活用してください。

セキュリティはそこで使われる用語が原因で大変混乱しやすいです。コアの概念を明確化にして理解しやすく整理したので、ShiroのAPIにその概念がどのように反映されているかを見てみてください。

  • 認証(Authentication)
    認証とは、サブジェクトのアイデンティティを検証するプロセスで、基本的には、ある人物が自分を誰であると言ってきているのかを確認するものです。認証の試行が成功すると、アプリケーションはそのサブジェクトをアプリケーションが期待するものである、として信頼します。
  • 認可(Authorization)
    認可、別名ではアクセス制御(Access Control)は、あるユーザ/サブジェクトに許可されるまたは許可されない何かを決定するプロセスです。このプロセスは通常、サブジェクトのロールやパーミッションを参照したり処理することで実行され、その後、リクエストされたリソースや関数に対するアクセスの許可もしくは拒否が行われます。
  • 暗号(Cipher)
    暗号は、暗号化または復号化を処理するアルゴリズムを指します。通常、アルゴリズムはキーと呼ばれる情報に依存します。暗号化はキーによって変化するため、複合化をキー無しで行うのは非常に難しくなります。
    暗号には色々なバリエーションがあります。ブロック暗号(Block Ciphers)は通常は固定サイズのシンボルのブロックを処理し、一方、ストリーム暗号(Stream Ciphers)はシンボルの逐次的なストリームを処理します。対称暗号(Symmetric Ciphers)は暗号化と複合化に同一のキーを使うのに対し、非対称暗号(Asymmetric Ciphers)は異なるキーを使います。また、非対称暗号のキーはもう片方からは生成出来ないので、公開鍵/秘密鍵のペアを生成して公開鍵を公開します。
  • クレデンシャル(Credential)
    クレデンシャルとは、ユーザ/サブジェクトのアイデンティティを検証するための情報です。プリンシパルと共にユーザ/サブジェクトはクレデンシャルをサブミットし、認証でそれを検証します。クレデンシャルはユーザと関連付けられています。クレデンシャルは、通常は個々のユーザ/サブジェクトだけが知る秘密事項で、パスワード・PGPキー・生体情報・などが挙げられます。
    プリンシパルとの関連では、唯一人だけがそのプリンシパルと'ペア'になる正しいクレデンシャルを把握しています。カレントのユーザ/サブジェクトがシステムに格納されているものと正しくマッチするクレデンシャルを与えられる場合、システムはカレントのユーザ/サブジェクトが自身を誰と言ってきてるのかを信頼します。信頼の度合いはよりセキュアなクレデンシャルを使うことで高まります(例えば、生体認証 > パスワード)。
  • 暗号化(Cryptography)*1
    暗号化は想定外のアクセスから情報を防御するもので、データを隠したり読めない形式に変換するなどします。Shiroには二つのコア要素があり、一つは公開鍵または秘密鍵でemailなどのデータを暗号化するciphersと、もう一つはパスワードなどのデータを不可逆的に暗号化するハッシュ(メッセージダイジェストなど)があります。
  • ハッシュ(Hash)
    ハッシュ関数は、片方向で、入力ソースの不可逆変換を行い、メッセージをエンコードしたハッシュ値はメッセージダイジェストと呼びます。ハッシュは、パスワード・デジタルフィンガープリント・基底バイト配列のデータ、に対して使うことが多いです。
  • パーミッション(Permission)
    パーミッションとは、少なくともShiroが解釈するものとしては、アプリケーションにおける最も細かい機能の記述の表明です。パーミッションセキュリティポリシーにおける最も低レベルの構成要素で、アプリケーションが"何を"実行可能かのみ定義します。"誰が"そのアクションを実行可能かは記述しません。パーミッションは振る舞いの表明でしかありません。以下はパーミッションの例です。
    • ファイルをオープンする。
    • ‘/user/list'のwebページを閲覧する。
    • ドキュメントを印刷する。
    • ‘jsmith'ユーザを削除する。
  • プリンシパル(Principal)
    プリンシパルとは、アプリケーションユーザ(サブジェクト)の何らかの識別属性(identifying attribute)です。'識別属性'となりうるモノは、ユーザの姓名・社会保障番号・ユーザID、など、ただそれだけのモノです。
    Shiroはサブジェクトのプライマリープリンシパルと呼ばれるものを参照します。プライマリープリンシパルはアプリケーション全体でサブジェクトを一意に識別する何らかのプリンシパルです。理想的なプライマリープリンシパルRDBMSのユーザーテーブルのプライマリキーとなるユーザ名やIDなどが該当します。あるアプリケーションにおいてユーザ(サブジェクト)のプライマリープリンシパルは一つだけしか存在しません。
  • レルム(Realm)
    レルムとは、ユーザ・ロール・パーミッションなどのアプリケーション固有のセキュリティデータにアクセスするコンポーネントです。セキュリティ用のDAO(Data Access Object)と言えます。レルムはアプリケーション固有のデータをShiroの形式に変換し、それから理解しやすい単一のサブジェクトAPIをShiroが提供します。このAPIの裏で動くものは、データソースの数やアプリケーション固有のデータの提供方法が何であっても構いません。
    レルムは通常は、RDBLDAPディレクトリ・ファイルシステムやその他類似のリソースと1対1の関係を持ちます。そのため、レルムインタフェースの実装は認証データ(ロール・パーミッションなど)の取得にデータソース固有のAPI、例えばJDBC・ファイルIO・HibernateJPAなどのデータアクセスAPI、を用います。
  • ロール(Role)
    The definition of a Role can vary based on who you talk to.*2 たいていのアプリケーションにおいて、暗黙的なセキュリティポリシー定義が関の山です。Shiroはロールをシンプルな名前のパーミッションのコレクションとして使うのを推奨します。言い換えると、アプリケーションは一つ以上のパーミッション宣言を集約したものに一意の名前を付けます。
    これにより、多数のアプリケーションで使われている暗黙的定義よりも明確な定義が作れます。Shiroが想定するデータモデルにすれば、セキュリティポリシーの運用をより強力なものにできるでしょう。
  • セッション(Session)
    セッションは一つのユーザ/サブジェクトと関連付けられるステートフルなデータコンテキストです。このユーザ/サブジェクトは、ある一定期間ソフトウェアシステムと相互作用を行います。サブジェクトがアプリケーションを使用している間、セッションからデータを追加・取得・削除可能で、それからアプリケーションは必要に応じてそのデータを使用可能です。ユーザ/サブジェクトがアプリケーションをログアウトあるいはタイムアウトするとセッションは終了します。
    HttpSessionを知っている人向けに補足すると、ShiroのSessionは同様な目的に使えますが、ShiroのセッションはServletコンテナやEJBコンテナが無い環境でも使用可能な点が異なります。
  • サブジェクト(Subject)
    サブジェクトは、基本的にはアプリケーションユーザをセキュリティ視点から見た'ビュー'を意味する、ちょっと格式ばった言い方のセキュリティ用語です。サブジェクトは常に人間である訳ではなく、アプリケーションを外部から呼び出す何らかのプロセスを意味します。また、ある一定期間ごとに何らかの処理を実行するデーモンシステムアカウント(cronジョブなど)の場合もあります。サブジェクトは基本的には、アプリケーションを用いて何らかの処理をするエンティティを指します。

Lend a hand with documentation

Apache Shiroで何かを作る際にこのドキュメントが役に立つことを願いますが、コミュニティが成長すればドキュメントも常に拡張していきます。もしShiroプロジェクトに興味がある場合、必要だと感じたドキュメントの追加・修正・収集をお願いしたいと思います。ほんの少しの助けであってもコミュニティは前進し、結果としてShiroも前進します。

ドキュメントをコントリビュートする最も簡単な方法はこのページ下のEditリンクをクリックしてプルリクエストをサブミットするか、User ForumあるいはUser Mailing List送信します。

*1:この用語集のみ読む限りでは、Cryptographyの一つにCipherがある、って感じらしい。俺自身セキュリティにはさして詳しくないんで、どっちも『暗号』にしてしまってます。

*2:よくわからん

Apache Shiro Architectureをテキトーに訳した

Apache Shiroのチュートリアルの一部でアーキテクチャ概要に関する部分の https://shiro.apache.org/architecture.html をテキトーに訳した。

Apache Shiro Architecture

Apache Shiroの設計目標は直感的で使いやすいようにアプリケーションセキュリティを単純化することです。Shiroのコア部分の設計は、人がアプリケーションセキュリティをどう捉えるかをモデル化しており、そのモデルはアプリケーションと相互作用する誰か(もしくは何か)という状況を背景に置いています。

通常、ソフトウェアアプリケーションはユーザーストーリーに沿って設計されます。つまり、開発者は、ユーザとソフトウェアが相互作用する(もしくは、すべき)方法に従って、ユーザインタフェースもしくはサービスAPIを設計していると思います。たとえば、"アプリケーションと相互作用するユーザはログイン後、そのユーザ自身のアカウント情報を参照可能なクリックできるボタンを表示する。未ログインの場合、サインアップボタンを表示する。"といった具合です。

上記の例文は、アプリケーションは主としてユーザ要求とニーズを満たすように作られる、ということを示しています。"ユーザ"が別システムの場合や、人間ではない場合でも、ソフトウェアがある時点で相互作用する誰か(もしくは、何か)を基点にした振る舞い を反映するようなコードを開発者は作成します。

Shiroはこうした思想を設計に組み込んでいます。開発者にとって直感的な概念に合わせることにより、Apache Shiroは直感的であらゆるアプリケーションに実用的な使いやすさを提供しています。

High-Level Overview

最上位の設計レベルにおいて、Shiroのアーキテクチャは三つの主要な概念、Subject, SecurityManager, Realmsで構成されています。以下の図はそれらのコンポーネントの相互作用の概要を示しています。各コンポーネントについては後で解説します。

図:https://shiro.apache.org/assets/images/ShiroBasicArchitecture.png

  • サブジェクト(Subject): チュートリアルにある通り、Subjectは基本的に現在実行中ユーザのセキュリティ視点での'ビュー(view)‘となります。'ユーザ(User)'という単語は人間を連想させますが、Subjectは人間以外に、サードパーティのデバイス、デーモンアカウント、cron jobなどが考えられ、要するにソフトウェアとその時相互作用する何か、になります。
    SubjectインスタンスはすべてSecurityManagerにバインドされています*1Subjectと相互作用するとき、その相互作用はSecurityManagerを用いるサブジェクト固有の相互作用に変換されます。
  • セキュリティマネージャー(SecurityManager): SecurityManagerはShiroのアーキテクチャの中核で、ある種のアンブレラ(‘umbrella’)オブジェクトとして振る舞います。このオブジェクトは、内部的なセキュリティコンポーネントとの調整役となり、コンポーネントと共にオブジェクトグラフを形成しています。ただし、SecurityManagerと内部オブジェクトグラフを一度アプリケーションに設定したあとは、基本的にその設定を触ることは無く、アプリケーション開発者はSubjectAPI以外を使うことはほとんどありません。
    SecurityManagerに関する詳細は後ほど触れますが、Subjectと何らかの相互作用を行う場合、Subjectのあらゆるセキュリティ操作に対する、すべての重い処理の背後には実際にはSecurityManagerがいることを覚えておいて下さい。この処理の流れは上の図の通りです。
  • Realms(レルム): レルムの振る舞いはShiroとアプリケーションのセキュリティデータ間で"ブリッジ"あるいは"コネクタ"といったものになります。認証(ログイン)と認可(アクセス制御)の実行にユーザアカウントなどのセキュリティ関連データを用いて実際に相互作用する段階になると、Shiroはアプリケーションに設定されている一つ以上のレルムから様々なデータを参照します。
    その意味において、レルムは基本的にはセキュリティ固有のDAOと言えます。このDAOは、データソースへの接続詳細をカプセル化し、必要に応じて関連データをShiroで利用可能にします。Shiroの設定時には、認証もしくは認可の両方で使うためのレルムを少なくとも一つ指定する必要があります。SecurityManagerは複数のレルムを設定可能で、少なくとも一つのレルムが必要です。
    Shiroはいくつかのレルムを提供しており、LDAP, RDB(JDBC), INIライクのテキスト設定ソース, プロパティファイルなどのセキュリティデータソースに接続するためのレルムを用意しています。これらデフォルトのレルムが要求を満たさない場合、カスタムデータソースを記述する自前のレルム実装をプラグイン出来ます。
    他の内部コンポーネント同様に、ShiroのSecurityManagerは、Subjectに用いられるアイデンティティデータとセキュリティデータを取得するのに使われるレルムを管理します。

Detailed Architecture

以下はShiroのコアアーキテクチャを示す図です。

図:https://shiro.apache.org/assets/images/ShiroArchitecture.png

以下は個々の要素の概要です。

  • Subject(org.apache.shiro.subject.Subject))
    セキュリティ視点でのエンティティ(ユーザ・サードパーティサービス・cron・jobなど)の'ビュー'で、ソフトウェアと相互作用を行う。
  • SecurityManager(org.apache.shiro.mgt.SecurityManager)
    上述のように、SecurityManagerはShiroのアーキテクチャの中核要素です。SecurityManagerは基本的には配下の管理コンポーネント群をうまいこと動作させるための詳細を隠蔽しています。また、アプリケーションユーザごとのShiroのビューを管理しており、ユーザごとに必要となるセキュリティ操作も管理しています。
  • Authenticator(org.apache.shiro.authc.Authenticator)
    Authenticatorはユーザの認証(ログイン)要求に対する処理と反応を返すためのコンポーネントです。ユーザがログインをするとき、そのロジックはAuthenticatorが実行します。Authenticatorはユーザ/アカウント関連情報を格納している一つ以上のRealmsの処理を担っています。Realmsから取得するデータは、そのユーザが自分自身を誰だと言ってきているのかを保証するユーザ一意性(user’s identity)を検証するのに使われます。
    • Authentication Strategy (org.apache.shiro.authc.pam.AuthenticationStrategy)
      複数のRealmを設定する場合、AuthenticationStrategyは認証処理の成功と失敗を決定するためにRealms間の調整を行います(たとえば、もし一つのレルムが成功して他は失敗の場合、認証処理は成功とするのか? すべてのレルムが成功しなければならないのか? 最初のみ成功でも通すのか?)。
  • SessionManager (org.apache.shiro.session.mgt.SessionManager)
    SessionManagerは、Sessionに関する堅牢なユーザ体験をあらゆる環境下で提供するため、ユーザSessionライフサイクルの作成と管理を担当します。セキュリティフレームワーク界隈においてこれはユニークな機能で、Web/ServletEJBコンテナが利用可能でなくとも、Shiroはどんな環境でもユーザのSessionを管理する能力を有しています。デフォルトでは、Shiroは何らかの機構(Servletコンテナなど)が使えればそのセッション機構を使用しますが、それが無い場合、たとえばスタンドアローンアプリケーションや非web環境などでは、何らかの機構と同様の体験を提供するのにShiroに組み込まれているエンタープライズセッション管理を使用します。SessionDAOは何らかのデータソースがセッションを永続化するのを許可するために使います。
    • SessionDAO (org.apache.shiro.session.mgt.eis.SessionDAO)
      SessionDAOSessionの永続化(CRUD)操作を実行するためのSessionManagerとのインタフェースです。このクラスを使うことで任意のデータストアをセッション管理インフラに組み込めます。
  • CacheManager (org.apache.shiro.cache.CacheManager)
    CacheManagerはShiroのコンポーネントが使用するCacheインスタンスのライフサイクルの生成と管理を行います。Shiroは多数のバックエンドデータソースにアクセスして認証・認可・セッション管理を行うため、キャッシュはフレームワーク内で主要機能であり、それらのデータソースを使用する場合のパフォーマンスを向上させるために存在します。高速かつ効果的なユーザ体験を提供するために、Shiroには最近のオープンソースまたはエンタープライズのキャッシュプロダクトを組み込むことが可能です。
  • Cryptography (org.apache.shiro.crypto.*)
    暗号化はエンタープライズのセキュリティフレームには当然存在してしかるべきものです。Shiroのcryptoパッケージには理解しやすく使いやすい暗号・ハッシュ(ダイジェスト)・コーデック実装が含まれています。このパッケージのすべてのクラスは使いやすく理解しやすくなるよう特に注意を払って設計されています。Javaの暗号化サポートを知る人であれば、野獣の調教に挑むような経験をしているでしょう。Shiroの暗号化APIは複雑なJavaのメカニズムを単純化して一般的な人類*2にとって使いやすい形にしています。
  • Realms (org.apache.shiro.realm.Realm)
    上述の通り、レルムはShiroとアプリケーションデータ間の'ブリッジ'あるいは'コネクタ'として振る舞います。認証(ログイン)と認可(アクセス制御)を処理するのにユーザアカウントなどのセキュリティ関連データと相互作用する段階になると、Shiroはアプリケーションに設定されている一つ以上のレルムから各種データを参照します。必要な数(通常はデータソースごとに一つ)のRealmsを設定可能で、Shiroは必要に応じて認証と認可でレルムを使用します。

The SecurityManager

ShiroのAPISubject中心のプログラミングアプローチを取っているため、SecurityManagerを直接触るのは、無くは無いですが、滅多にありません(ただしフレームーワーク開発者は直接SecurityManagerを見るのが良い場合があります)。しかし、SecurityManagerの動きを知ることは重要で、アプリケーションでこれを設定する場合には特に重要です。

Design

前述のとおり、アプリケーションのSecurityManagerはセキュリティ操作を実行し、すべてのアプリケーションユーザの状態管理を行います。ShiroのデフォルトSecurityManager実装には以下が含まれます。

  • 認証(Authentication)
  • 認可(Authorization)
  • セッション管理(Session Management)
  • キャッシュ管理(Cache Management)
  • レルム間調整(Realm coordination)
  • イベント伝播(Event propagation)
  • ‘Remember Me'サービス('Remember Me’ Services)
  • サブジェクト生成(Subject creation)
  • ログアウトなど(Logout and more)

なお、上記の機能の多くは単一コンポーネントを管理しやすくするための機能です。また、単一の実装クラスにすべてを詰め込もうとすると、柔軟性を持たせてカスタマイズしやすくするのは難しくなります。

設定/プラグインを柔軟にして単純化するため、Shiroの実装は設計に高いモジュール性を設けています。このモジュール性により、SecurityManagerの実装(とそのクラス階層)がすべての処理を行うわけではありません。一枚岩にする代わりに、SecurityManager実装はいわゆるライトウェイトな'コンテナ'コンポーネントの振る舞いをし、ネストないしラップするコンポーネントに多くの振る舞いをデリゲートします。この'ラッパー'設計は上述のDetailed Architectureの図にある通りです。

デリゲート先のコンポーネントが実際にロジックを実行するので、SecurityManagerの実装は、何らかの振る舞いを行うコンポーネントをいつ・どのように実行するか、に責任を持ちます。

SecurityManagerの実装はJavaBeans互換のため、JavaBeans標準のgetter/setterメソッドでプラガブルなコンポーネントを簡単にカスタマイズできます。Shiroアーキテクチャのモジュール性は振る舞いをカスタマイズするための設定容易性に表れています。

Easy Configuration
JavaBeans互換のため、JavaBeansスタイルの設定をサポートするSpring, Guice, JBossなどで、カスタムコンポーネントによるSecurityManagerの設定を簡単に行えます。

設定については次のConfigurationを参照してください。

Lend a hand with documentation

Apache Shiroで何かを作る際にこのドキュメントが役に立つことを願いますが、コミュニティが成長すればドキュメントも常に拡張していきます。もしShiroプロジェクトに興味がある場合、必要だと感じたドキュメントの追加・修正・収集をお願いしたいと思います。ほんの少しの助けであってもコミュニティは前進し、結果としてShiroも前進します。

ドキュメントをコントリビュートする最も簡単な方法はこのページ下のEditリンクをクリックしてプルリクエストをサブミットするか、User ForumあるいはUser Mailing List送信します。

*1:Subject instances are all bound to (and require) a SecurityManagerが原文なんだけど(and require)が良く分かんなくて訳文には含めていない

*2:原文はnormal mortal human beingsで、マジメに訳せば、普通のいつか死ぬ人間だが、言うまでもなくシャレあるいは複雑なジャバに対する皮肉と思われるが、訳文は無難にしておいた。

Java Authorization Guide with Apache Shiroをテキトーに訳した

Apache Shiroのチュートリアルの一部でAuthorizationに関する部分の https://shiro.apache.org/java-authorization-guide.html をテキトーに訳した。

Java Authorization Guide with Apache Shiro

認証もしくはアクセス制御とは、リソースへのアクセス権を特定する機能です。つまり、誰が何にアクセスするのか、ということです。

認証チェックの例を挙げると、ユーザに対し、webページの閲覧・データ編集・ボタンの可視性・プリンターへの出力、を許可するかどうかをチェックします。これらはすべて、ユーザが何にアクセスできるかどうかを決定しています。

Elements of Authorization

認証には三つの中核要素があり、パーミッション・ロール・ユーザで、これらはShiroでは頻繁に参照します。

Permissions Defined

パーミッションセキュリティポリシーのうち最もアトミックなレベルで、 パーミッションは機能性の表明です*1パーミッションはアプリケーションで何が可能なのかの表現です。well formed*2なパーションはリソースタイプと、そのリソースとの相互作用時に可能なアクションを記述しています。ドアを開けられるか、ファイル読み込み可能か、顧客データを削除可能か、ボタンを押せるか、など。

データ系リソースで一般的なアクションは、作成・読み込み・更新・削除で、いわゆるCRUDです。

重要な点は、パーミッションは誰がそのアクションを実行可能かを持つのではなく、何に対してそのアクションが実行可能かを表明する、を理解することです。

Levels of permission granularity

上で挙げたパーミッションはすべて、リソース(ドア・ファイル・データレコードなど)に対する、アクション(開く・読み込み・削除など)を定義しています。Shiroでは、任意の深さでパーミッションを定義可能です。以下はいくつかの一般的なパーミッションレベルを粒度(granularity)順に示したものです。

パーミッションに関する詳細はPermissions Documentationを参照してください。

Roles Defined

認証のコンテキストでは、ロールは実質的にはパーミッションの集合で、その集合はパーミッションとユーザの管理を単純化するのに使われます。パーミッションを直接割り当てるのではなく、ユーザにロールを割り当てられます。多数のユーザを抱えていたり複雑なアプリケーションでは、パーミッションはややこしくなりがちです。例としては、銀行アプリケーションでは管理者(administrator)ロールや出納係(bank teller)ロールが挙げられます。

ロールには二種類あり、Shiroは両方ともサポートします。

Implicit Roles

ほとんどの人はロールを、アプリケーションがパーミッションの組み合わせを暗示するような暗黙的なロール(implicit role)という形を取る、と理解しています。そうなる理由は、明示的なパーミッションが付与されたロールではなく、ユーザが特定のロールを持つか、あるいはアプリケーションでそれらのパーミッションをチェックしているためです。コードでのロールチェックは基本的に暗黙的なロールの反映となります。あるユーザは患者データを閲覧(view patient data)可能で、それは管理者(administrator)ロールを持つからです。あるユーザはアカウントを作成(create an account)可能で、それは出納係(bank teller)ロールを持つからです。こうした役割などの名称が存在することと、ソフトウェアが実際に実行可能なことの間に、相関性はありません。たいていの人はこのやり方でロールを使用します。使うのが簡単ではあるものの、ごく単純なアプリケーションを除いて、メンテナンスの手間と管理上の問題を多数生み出します。

Explicit Roles

明示的なロール(explicit role)は明示的に付与されたパーミッションを持ちます。よって、そのロールはパーミッションの明示的な集合になります。コード中のパーミッションチェックは明示的なロールの反映となります。あるユーザは患者データを閲覧(view patient data)可能で、それは管理者ロールの一部であるview patient dataパーミッションを持つからです。あるユーザはアカウントを作成(create an account)可能で、それは出納係ロールの一部であるcreate accountパーミッションを持つからです。ユーザがこれらのアクションを実行可能なのは、文字列ベースの暗黙的なロール名を持つからではなく、そのアクションに対応するパーミッションがロールに明示的に付与されているからです。

明示的なロールの大きな利点は管理の容易さとアプリケーションのメンテナンスコストを低下させることです。ロールを追加・削除・変更する必要が出てきたとしても、ソースコードを修正する必要はありません。また、Shiroでは、実行時に動的にロールを追加・削除・変更することが可能で、認証チェックは常に最新の値を用います。つまり、新しいパーミッションのためにユーザにログアウト&ログインを強いる必要がない、ということです。

Users Defined

アプリケーションを使うのは誰かといえばユーザです。しかし、Shiroではユーザの概念は実際にはSubjectインスタンスになります。ユーザは基本的には人間を指し、ShiroのSubjectは人間かサービスかどうかを問わずアプリケーションと相互作用するモノになるので、ユーザの代わりにSubjectという単語を使います。

ロールもしくは直接パーミッションを付与することでアプリケーションで特定のアクション実行をユーザが可能となります。よって、あるユーザが顧客データを開けるのはopen customer recordパーミッションが付与されているから、となります。パーミッション付与は、ロールをユーザに割り当てるか、直接パーミッションを割り当てます。

ユーザもといサブジェクトの詳細についてはSubject Documentationを参照してください。

Note
Realmの実装は何らかのデータソース(RDBMS, LDAPなど)と通信するものになります。よって、そのレルムがロールやパーミッションが存在するかどうかをShiroに伝えることになります。認証モデルの動作はすべて制御が可能です。

How to perform Authorization in Java with Shiro

Shiroでの認証の利用は4通りのやり方があります。

Programmatic Authorization

認証処理のパーミッションとロールのチェックをJavaのコードで行うのは古くからあるやり方です。以下はShiroでパーミッションやロールのチェックを行う方法の解説です。

Role Check

以下のサンプルはアプリケーションでロールチェックをするコードの例です。いま、あるユーザがadministratorロールを持つかどうかをチェックし、持っていれば専用ボタンを表示し、そうでなければ表示しない、ようにしたいとします。

まず、現在のユーザのSubjectを取得します。それから、Subjectの.hasRole()メソッドにadminstratorを渡します。このメソッドはTRUEFALSEを返します。

//Subjectを取得
Subject currentUser = SecurityUtils.getSubject();

if (currentUser.hasRole("administrator")) {
    //専用ボタンを表示
} else {
    //専用ボタンを表示しない(か、それ以外の処理?)
}

ロールベースのチェックはすぐに実装出来て簡単ですが大きな欠点があり、それは暗黙的になる点です。

後からロールを追加・削除・再定義したい場合に何が起きるでしょうか。ソースコードをすべて調べて、セキュリティモデルの変更を反映するようにすべてのロールチェックを修正する必要が出てきます。アプリケーションをシャットダウンして、ソースコードを調査して、テストして、再起動が必要となります。

極めて単純なアプリケーションであればこれでも十分ですが、大規模アプリケーションではアプリケーションが使われ続ける限り重大なトラブルの種となり、ソフトウェアのメンテナンスコストが高くつき続けることになります。

Permission Check

以下のサンプルはパーミッションを用いてセキュリティチェックをするコードの例です。いま、あるユーザがlaserjet3000n*3にプリントアウトするパーミッションを持つかどうかをチェックし、持っていればプリントボタンを表示し、そうでなければ表示しない、ようにしたいとします。以下はインスタンスレベルパーミッションもしくはインスタンスレベル認証の例です。

先の例と同じく、まず現在のユーザのSubjectを取得します。それから、Permissionオブジェクトか、リソースに対するアクションを表すインスタンスを生成します。この例の場合、printerPermissionというインスタンスがあり、リソースに相当するのがlaserjet3000nで、アクションはprintです。その次に、サブジェクトの.isPermitted()メソッドにprinterPermissionを渡します。このメソッドはtrueかfalseを返します。

Subject currentUser = SecurityUtils.getSubject();

Permission printPermission = new PrinterPermission("laserjet3000n","print");

If (currentUser.isPermitted(printPermission)) {
    //何らかの処理(プリントボタンの表示など)
} else {
    //ボタンを非表示にするなど。
}
Permission Check (String-based)

パーミッションクラスではなく単純に文字列を用いてパーミッションチェックをすることも出来ます。

Shiroのpermission interfaceの実装がひとまず面倒な場合はただ単に文字列を渡します。この例の場合、.isPermitted()メソッドに文字列printer:print:LaserJet4400nを渡します。

String perm = "printer:print:laserjet4400n";

if(currentUser.isPermitted(perm)){
    //何らかの処理(プリントボタンの表示など)
} else {
    //ボタンを非表示にするなど。
}

何らかのパーミッションと連動する自前のRealmを用意すれば、後は個々の実装でパーミッション文字列を構築します。このチュートリアルではShiroのパーミッションシンタックスWildCardPermissionsを使用しています。WildCardPermissionsは強力で直感的に使えます。詳細についてはPermissions Documentationをチェックしてください。

文字列ベースパーミッションチェックで出来ることはそうでない場合と変わりません。これの利点は、permission interfaceの実装をせずに済むのと、ただ単に文字列でパーミッションを構築できる点です。欠点は、タイプセーフではなくなり、将来的に文字列ベースでは表現が困難な複雑なパーミッション機能が必要となった場合、permission interfaceを実装するパーミッションオブジェクトを作っておけば良かった、になると思われます。

Annotation Authorization

コードによる認証チェックを書きたくない場合はアノテーションを使います。Shiroはメソッドに付与するJava annotationsをいくつか提供しています。

Enabling Annotation Support

ShiroのJavaアノテーションを使い始める前にアプリケーションでAOPサポートを有効化する必要があります。AOPフレームワークは複数存在しますが、残念なことに、アプリケーションでAOPを有効化する標準的な方法はありません。

AspectJについては、AspectJ sample applicationを参照してください。

Springについては、Spring Integrationドキュメントを参照してください。

Guiceについては、Guice Integrationドキュメントを参照してください。

Permission Check

以下の例では、openAccountメソッドの実行前にそのユーザがaccount:createパーミッションを持つかをチェックしています。もしチェックOKであればメソッドは期待通り呼び出され、そうでない場合は例外がスローされます。

コードを書いてのチェックと同様に、アノテーションに指定するものはPermissionオブジェクトか、単なる文字列を使う方法があります。

//呼び出し側のロールがどれもAccountの'create'パーミッションに該当しない場合
//AuthorizationExceptionをスローします。
@RequiresPermissions("account:create")
public void openAccount( Account acct ) {
    //アカウントを作成する。
}
Role Check

以下の例では、openAccountメソッドの実行前にそのユーザがtellerロールを持つかをチェックしています。もしチェックOKであればメソッドは期待通り呼び出され、そうでない場合は例外がスローされます。

//呼び出し側が'teller'ロールを持たない場合はAuthorizationExceptionをスロー
//します。
@RequiresRoles( "teller" )
public void openAccount( Account acct ) {
    //tellerだけが実行するべき何らかの処理。
}

JSP TagLib Authorization

JSP/GSPベースのwebアプリケーション用のtag libraryをShiroで用意しています。

以下の例では、users:manageパーミッションを持つユーザに対してはManage Usersページへのリンクを表示しています。このパーミッションを持たない場合は適当なメッセージを表示します。

この機能を使うにはまず、Shiroのtablibをwebアプリケーションに追加します。次に、users:manageのチェックに用いる<shiro:hasPermission>タグを追加します。<shiro:hasPermission>タグ内に、ユーザがそのパーミッションを持つ場合に実行したいコードを記述します。逆に、ユーザがそのパーミッションを持たない場合に何らかの処理をしたい場合、<shiro:lacksPermission>タグを追加します。その際は再度users:manageのチェックを書きます。

<%@ taglib prefix="shiro" uri=http://shiro.apache.org/tags %>
<html>
<body>
    <shiro:hasPermission name="users:manage">
        <a href="manageUsers.jsp">
            Click here to manage users
        </a>
    </shiro:hasPermission>
    <shiro:lacksPermission name="users:manage">
        No user management for you!
    </shiro:lacksPermission>
</body>
</html>

また、ロールやその他のユーザデータ・状態をチェックするタグもあります。

JSP/GSP Tagsの詳細についてはJSP Tag Libraryを参照してください。また、webアプリケーションとの統合サポートについてはWeb Integration Documentationを参照してください。

Caching Authorization

TBD*4

Lend a hand with documentation

Apache Shiroで何かを作る際にこのドキュメントが役に立つことを願いますが、コミュニティが成長すればドキュメントも常に拡張していきます。もしShiroプロジェクトに興味がある場合、必要だと感じたドキュメントの追加・修正・収集をお願いしたいと思います。ほんの少しの助けであってもコミュニティは前進し、結果としてShiroも前進します。

ドキュメントをコントリビュートする最も簡単な方法はこのページ下のEditリンクをクリックしてプルリクエストをサブミットするか、User ForumあるいはUser Mailing Listに送信します。

*1:they are statements of functionality. が原文

*2:良い日本語が思いつかないんだが、xmlでwell-formedっていうとXMLの仕様に則っているとかそういう意味なんで、作法にきちんと則って定義されたパーミッション、くらいの意味合いで良いと思われる。

*3:ぐぐれば出てくるけどHP Color LaserJet 3000n Printerというプリンタのこと

*4:これを書いている時点では本家がTBDになっている