Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

「patterns & practices Enterprise Library」認証プロバイダの拡張

IAuthenticationProviderを実装したXML Authentication Providerの作成

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2005/10/19 16:00

Enterprise Libraryは様々な機能を提供しています。しかし、提供されていない機能が必要となった場合には、何らかの拡張を行う必要があります。本稿では、Enterprise Libraryの機能を拡張する方法を例を挙げて説明します。

はじめに

 Enterprise Libraryは様々な機能を提供しています。しかし、提供されていない機能が必要となった場合には、何らかの拡張を行う必要があります。

 本稿では、拡張を行う際の方法を例を挙げて説明します。

対象読者

 Enterprise Libraryを用いている開発者。

必要な環境

Enterprise Libraryの構成

 Enterprise Libraryの機能は、大きく分けると2つのレベルで定義されています。

  • Application Block
  • 全体の構造を定義し、選択可能な機能ごとにProviderのインタフェースを定義します。
    Factoryが構成に基づいて選択されたProviderを生成します。
  • Provider
  • 特定の機能を実装します。
    固有の設定項目を定義します。

 例えば、Security Application BlockというApplication Blockは、Authentication、Authorization、Profile、Role、Security CacheといったProviderを用いています。このうち、Authentication Providerとしては、Database Authentication Providerが提供されています。

 今回は、新しい種類のAuthentication ProviderとしてXML Authentication Providerを作成します。

Authentication Providerについて

 まずは、Security Application BlockにおけるAuthentication Providerのインタフェースを確認します。

 「(インストール ディレクトリ)\src\Security\AuthenticationProvider.cs」で定義されるIAuthenticationProviderが対象のインタフェースです。

bool Authenticate(object credentials, out IIdentity identity);

 リファレンスを参照すると、

  1. credentialに認証情報が渡されます。
  2. identityにアイデンティティを格納します。
  3. 認証に成功したらtrueを、失敗したらfalseを返します。

 ということがわかります。

プログラムの作成

 では、プログラムを作成してみましょう。

呼び出し側プログラム

 まずは、呼び出し側プログラムを作成しておきます。この部分は、既存のProviderを使用する場合と全く同じコードです。したがって、既存のProviderを使用するコードが既にあれば、そのまま(再コンパイルも不要)使用することが可能です。この場合、新規に作成するProviderを単に別アセンブリとして作成し、同じディレクトリに配置すれば動作します。

 参照設定に、Enterprise Libraryで提供される「Microsoft.Practices.EnterpriseLibrary.Security.dll」と「Microsoft.Practices.Enterpriselibrary.Configuration.dll」を加えておきます。

using System.Security.Principal;
using Microsoft.Practices.EnterpriseLibrary.Security;
private bool Authenticate(string user, string password,
                          out IIdentity identity)
{
    IAuthenticationProvider authenticationProvider
        = AuthenticationFactory.GetAuthenticationProvider();
    NamePasswordCredential credential
        = new NamePasswordCredential(user, password);
    return authenticationProvider
        .Authenticate(credential, out identity);
}

対象のXMLファイル

 ユーザ・パスワードを「authentication.xml」に定義しておきます。

authentication.xml
<?xml version="1.0" encoding="utf-8" ?>
<users>
    <user id="test1" password="password1" />
    <user id="test2" password="password2" />
</users>

構成ツールでの設定

 通常通り構成ツールを起動して、「app.config」(あるいは「web.config」)を開き、[Security Application Block]を追加します。

 Authenticationで[New]-[Custom Authentication Provider]を選択します。参照しやすくするため、名前を変更します。

Custom Authentication Providerを追加
Custom Authentication Providerを追加

 その後、Providerが参照する構成情報を設定します。Custom Providerの場合、構成情報はExtensionsプロパティで設定します。Extensionsプロパティを選択すると右端に[…]ボタンが表示されますので、クリックして[コレクション エディタ]を開きます。

 ここにProvider独自の名前と値の組を設定することができます。これを、Providerのコード内から参照することになります。

 今回は、以下の値を設定しました。

名前用途今回の設定値
FileName対象のXMLファイル名を指定します。authentication.xml
Pathユーザ全体を表すXPath式を指定します。/users/user
UserPathユーザIDを表す、Pathからの相対XPath式を指定します。@id
PasswordPathパスワードを表す、Pathからの相対XPath式を指定します。@password
Extensionsの設定
Extensionsの設定

 最後に、対象のCustom Providerのクラスを参照します。まだ実装を行っていなければ参照ができないので、その場合は実装後に再度構成ツールを実行する必要があります。

 TypeNameプロパティを選択すると右端に[…]ボタンが表示されますので、クリックして[Type Selector]を開きます。

 ここで、実装を行ったアセンブリとクラスを選択します。

Providerの参照設定
Providerの参照設定

 これで設定ができましたので、保存します。

設定を行った状態
設定を行った状態

設定を取得する部分

 既存のAuthenticationProviderを参考にして、以下のようなコードを作成しました。この部分のコードは、対象となるProviderによってConfigurationViewの型が変わること以外は、あまり変わらないのではないかと思います。

Initializeメソッド
private SecurityConfigurationView securityConfigurationView;

public override void Initialize(ConfigurationView configurationView)
{
    // 引数にSecurityConfigurationViewが渡されていることを確認します
    ArgumentValidation.CheckForNullReference(configurationView,
        "configurationView");
    ArgumentValidation.CheckExpectedType(configurationView,
        typeof(SecurityConfigurationView));

    // 渡されたSecurityConfigurationViewを保持します
    securityConfigurationView
        = (SecurityConfigurationView)configurationView;
}

処理本体

 処理本体です。まずは、引数のチェックと構成情報の取得を行います。Providerによって引数の型や構成情報の型が異なりますが、この部分もあまり変わらないと思います。

Authenticateメソッド(1)
public bool Authenticate(object credentials, out IIdentity identity)
{
    // 引数にNamePasswordCredentialが渡されていることを確認します
    ArgumentValidation.CheckForNullReference(credentials,
                                             "credentials");
    ArgumentValidation.CheckExpectedType(credentials,
                                     typeof(NamePasswordCredential));

    NamePasswordCredential namePasswordCredential
        = (NamePasswordCredential)credentials;

    // SecurityConfigurationViewから設定情報を取得します
    // 「Custom Authentication Provider」として設定された場合、
    // CustomAuthenticationProviderDataが作成されます
    CustomAuthenticationProviderData providerData
        = (CustomAuthenticationProviderData)securityConfigurationView
            .GetAuthenticationProviderData(ConfigurationName);

 その後、実際の処理を行います。ここで、カスタム構成情報のExtensionsプロパティに設定した名前と値の組がproviderData.Extensions[名前]で参照できます。

Authenticateメソッド(2)
    // 対象となるXMLファイルをロードします
    // 構成ツールでは、ファイル名をExtensionsのFileNameに設定します
    XmlDocument document = new XmlDocument();
    document.Load(providerData.Extensions["FileName"]);
    
    // 構成ツールでは、ユーザ全体へのXPath式を
    // ExtensionsのPathに設定します
    string path = providerData.Extensions["Path"];
    // 構成ツールでは、pathで指定されるノードから
    // ユーザIDへのXPath式をExtensionsのUserPathに設定します
    string userPath = providerData.Extensions["UserPath"];
    // 構成ツールでは、pathで指定されるノードから
    // パスワードへのXPath式をExtensionsのPasswordPathに設定します
    string passwordPath = providerData.Extensions["PasswordPath"];

    // 各ユーザを取得し、与えられたユーザIDと
    // パスワードが存在するかどうかを確認します
    foreach (XmlNode node in document.SelectNodes(path))
    {
        XmlNode userNode = node.SelectSingleNode(userPath);
        if (userNode == null ||
            userNode.Value != namePasswordCredential.Name)
            continue;
        
        XmlNode passwordNode = node.SelectSingleNode(passwordPath);
        if (passwordNode == null ||
            passwordNode.Value != namePasswordCredential.Password)
            continue;

        // 見つかったので、GenericIdentityオブジェクトを生成します
        identity = new GenericIdentity(namePasswordCredential.Name);
        return true;
    }
    identity = null;
    return false;
}

最後に

 本稿では、既存のApplication Blockに用意されていないProviderを追加する方法を示しました。

 今後は、追加した機能を構成ツールから利用できるようにする方法や、Application Blockそのものを作成する方法などを扱っていきたいと思います。

参考資料

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • にしざき(にしざき)

    Team EntLib.jp - enterpriselibrary.jp を拠点として、国内における Enterprise Library の普及に向けて活動中。

All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5