本格派エンジニアの工具箱

第20回Javaアプリケーション向けの認証フレームワーク「Apache Shiro」

使いやすい認証機構を実現する「Apache Shiro」

今回取り上げるApache Shiroは、Javaアプリケーション向けに開発された認証と承認のためのオープンソースのフレームワークです。Shiroを使うことで、ログインなどの認証の仕組みや、アクセス管理、セッション管理などといった機構を、容易にアプリケーションに付け加えることができるようになります。

JDKにはJAAS(Java Authentication and Authorization Service)という認証・承認サービスが用意されていますが、JAASで提供されるAPIはあまり使い勝手が良くなく、わかりにくいという意見が大多数を占めていました。ShiroはJAASよりも理解しやすく、簡単に利用できる認証・承認の仕組みを提供する目的で開発されました。Shiroを利用するメリットとしては次のようなものが挙げられています。

  • 理解しやすい簡潔なAPI
  • 認証・承認に必要な一通りの機能を包括的にカバー
  • さまざまな環境に対応するフレキシビリティ
  • Webアプリケーションへの組込みとが可能
  • 他のフレームワークやアプリケーションとの統合が容易
  • 依存関係が少ない
  • 設定が容易

Shiroでは、大きく分けて以下の4種類の機能が用意されています。

  • 本人認証(Authentication)
  • リソースのアクセス権管理(Authorization)
  • セッション管理(Session Management)
  • キャッシュ管理(Cache Management)

それぞれ後述するセキュリティマネージャを通して利用できるようになっており、複雑な認証機構はセキュリティマネージャによって隠蔽されている点が大きな特徴です。

Apache Shiroのアーキテクチャ

Apache Shiroは大別すると次の3つのパートから構成されます。

サブジェクト(Subject)
アプリケーションからShiroのセキュリティ機構にアクセスするための"ビュー"となるオブジェクト
セキュリティマネージャ(SecurityManager)
セキュリティのためのさまざまなコンポーネントを提供・管理する
認証レルム(Realm)
さまざまなセキュリティ・データと橋渡しの役目をもつコネクタ
図1 Apache Shiroは3つのパートから成る
図1 Apache Shiroは3つのパートから成る
出典:http://shiro.apache.org/architecture.html

前述の4つの機能はコンポーネント化されてセキュリティマネージャによって管理されます。認証レルムはセキュリティ・データの種類ごとに用意されます。JDBC用のレルム、LDAP用のレルム、Active Directory用のレルム、といった具合です。それぞれのレルムは共通のインターフェースを持つため、任意に入れ替えて使用できるようになっています。つまり、使用する認証レルムを変えれば、共通の方法で異なるセキュリティデータにアクセスできるということです。

図2 Apache Shiroのアーキテクチャ
図2 Apache Shiroのアーキテクチャ
出典:http://shiro.apache.org/architecture.html

Apache Shiroでユーザ認証を行う

Shiroはこのページよりダウンロードできます。全機能を含むバイナリは「shiro-all」で、それ以外に個別のフレームワークやツール向けのバイナリが用意されています。ソースコードをダウンロードした場合、Mavenを使ってビルドできます。

今回はshiro-all(ファイル名shiro-all-1.1.0.jar)を使うものとして解説を進めます。shiro-allを使う場合、Shiro本体以外にSLF4JApache Commons BeanUtilsApache Commons Loggingの各ライブラリを別途ダウンロードしてクラスパスに追加する必要があります。

Shiroを使った認証の起点となるのはSecurityUtilsクラスです。このクラスのstaticメソッドによって、セキュリティマネージャの設定とサブジェクトの取得が行えます。セキュリティマネージャはorg.apache.shiro.mgt.SecurityManagerインターフェース(java.langパッケージに同名のクラスがあるので、必ずフルパスで記述する必要があります)をimplementsしたクラスとして実装されています。たとえばAuthenticatingSecurityManagerやSessionsSecurityManagerなどです。

今回は、.iniファイルからセキュリティマネージャの設定を読み込む方法を使ってみます。.iniファイルからSecurityManagerオブジェクトを作成するには、IniSecurityManagerFactoryクラスを利用して次のように行います。

Factory<org.apache.shiro.mgt.SecurityManager> factory = 
                                             new IniSecurityManagerFactory("shiro.ini");
org.apache.shiro.mgt.SecurityManager manager = factory.getInstance();

SecurityManagerが作成できたら、それをSecurityUtilsにsetSecurityManager()メソッドを使って設定します。

SecurityUtils.setSecurityManager(manager);

サブジェクトはSubjectクラスとして実装されています。これを取得するには、SecurityUtilsのgetSubject()メソッドを呼び出します。

Subject user = SecurityUtils.getSubject();

ユーザ認証はSubjectを介して行うことができるのですが、そのためには認証に使うためのトークンを作成しなければなりません。ユーザ名とパスワードによる認証のためのトークンであればUsernamePasswordTokenクラスで作成します。次のように、第1引数にユーザ名、第2引数にパスワードを引数にしてコンストラクタを呼び出します。

UsernamePasswordToken token = 
		      new UsernamePasswordToken("gihyo", "gihyopass");

このTokenオブジェクトをSubjectのlogin()メソッドに渡して実行することでログイン認証が行われます。次のプログラムは、ログイン認証のための一連の流れを示したものです。

public class FirstShiroSample {
  public static void main(String[] args) {
    // セキュリティマネージャの設定
    Factory<org.apache.shiro.mgt.SecurityManager> factory = 
	            new IniSecurityManagerFactory("classpath:shiro.ini");
    org.apache.shiro.mgt.SecurityManager manager = factory.getInstance();
    SecurityUtils.setSecurityManager(manager);
    
    // Subjectの取得
    Subject user = SecurityUtils.getSubject();
    
    if (!user.isAuthenticated()) {
      try {
        // Tokenの作成
        UsernamePasswordToken token = new UsernamePasswordToken("gihyo", "gihyopass");
        
        // ログイン
        user.login(token);
        
        System.out.println("Login successful.");
      } catch (AuthenticationException ex) {
        System.out.println("Authentication failed.\n" + ex);
      }
    } else {
      System.out.println("This user is authenticated.");
    }
  }
}

login()メソッドは認証に失敗するとAuthenticationException(またはそのサブクラスのException)をスローします。また、すでに認証が完了しているSubjectに関しては、isAuthenticated()メソッドがtrueを返すようになっています。

.iniファイルの記述方法ですが、ユーザ名とパスワードの設定であれば、次に示すように[user]セクションにユーザ名とパスワードを「=」でつなげて記述します。この例の場合はユーザ名が「gihyo⁠⁠、パスワードが「gihyopass」です。今回はとりあえずこの設定だけでOKです。その他に.iniファイルの設定項目に関してはリファレンスマニュアルを参照してください。

[users]
gihyo = gihyopass

.iniファイルが用意できたら、FirstShiroSampleを実行してみましょう。⁠Login successful.』という表示が出れば認証成功です。認証に失敗した場合には、次のようにIncorrectCredentialsExceptionがスローされます。

Authentication failed.
org.apache.shiro.authc.IncorrectCredentialsException: 
    The credentials provided for account 
    [org.apache.shiro.authc.UsernamePasswordToken - gihyo, rememberMe=false]
     did not match the expected credentials.

もし『[main] INFO org.apache.shiro.session.mgt.AbstractValidatingSessionManager - Enabling session validation scheduler...』ようなメッセージが表示される場合には、.iniファイルの[main]セクションに以下の設定を追加することでメッセージは表示されなくなります。

[main]
securityManager.sessionManager.sessionValidationSchedulerEnabled = false

次回は、セッションの使用やWebアプリケーションでの利用方法を解説します。

おすすめ記事

記事・ニュース一覧