# HTTP 認証アダプタ

## 導入

`Zend_Auth_Adapter_Http` は、 RFC-2617 や ベーシック、 ダイジェスト HTTP 認証にほぼ準拠した実装を提供します。ダイジェスト認証とは HTTP 認証方式のひとつで、パスワードを平文でネットワークに送信する必要がないという点で ベーシック認証より優れています。

主な機能

- ベーシック認証およびダイジェスト認証の両方のサポート

- サポートしているすべてのスキームを試みるので クライアントは、サポートする任意のスキームで応答可能

- プロキシ認証のサポート

- テキストファイルを用いた認証のサポート、 あるいはデータベースなどのその他のソースによる認証用インターフェイスの提供

RFC-2617 の機能のうち、以下についてはまだ実装されていません。

- nonce 値を追いかけることによる "stale" のサポート、 および再試行攻撃への防御

- 整合性チェックを含む認証 "auth-int"

- Authentication-Info HTTP ヘッダ

## 設計の概要

このアダプタはふたつのサブコンポーネントで構成されています。 ひとつは HTTP 認証クラス自身、そしてもうひとつはいわゆる "リゾルバ" です。 HTTP 認証クラスは、ベーシック認証およびダイジェスト認証を扱うロジックをカプセル化します。 このクラスは、リゾルバを使用してなんらかの保存データ (デフォルトはテキストファイル) からクライアントの ID を探します。認証データが "解決" されると、クライアントから送信された値に基づいて認証が成功したかどうかを判断します。

## 設定オプション

`Zend_Auth_Adapter_Http` クラスのコンストラクタには、 設定配列を渡す必要があります。使用可能なオプションはいくつかあり、 その中には必須のものもあります。

### 設定オプション

オプション名 | 必須かどうか | 説明
--- | --- | ---
accept_schemes | Yes | そのアダプタがクライアントからどの認証スキームを受け取るのかを設定します。 'basic' や 'digest' を含む空白区切りの文字列でなければなりません。
realm | Yes | 認証レルムを設定します。ユーザ名は、指定したレルム内で一意でなければなりません。
digest_domains | accept_schemes が digest を含む場合は Yes | 空白区切りの URI のリストで、 同じ認証情報が有効となる場所を指定します。 URI は同一サーバ上でなくてもかまいません。
nonce_timeout | accept_schemes が digest を含む場合は Yes | nonce の有効期限を秒数で指定します。以下の注意を参照ください。
proxy_auth | No | デフォルトでは無効です。有効にすると、 元のサーバの認証のかわりにプロキシで認証を行います。

現在の nonce_timeout の実装には、いくつかの副作用があります。 この設定は、指定した nonce の有効期限、 つまり事実上はクライアントの認証情報の有効期限を指定するためのものです。 現在は、これを (たとえば) 3600 に設定すると、 一時間ごとに新しい認証をクライアントに要求するようアダプタに設定します。 これは将来のリリースで nonce の追跡と stale のサポートを実装した時点で解決する予定です。

## リゾルバ

リゾルバの仕事は、ユーザ名とレルムを受け取って何らかの証明を返すことです。 ベーシック認証では、ユーザのパスワードを Base64 でエンコードしたものを受け取ります。 ダイジェスト認証では、ユーザ名、レルムおよびパスワード (をコロンでつなげたもの) のハッシュを受け取ります。 現在サポートしているハッシュアルゴリズムは MD5 のみです。

`Zend_Auth_Adapter_Http` `Zend_Auth_Adapter_Http_Resolver_Interface` を実装したオブジェクトを使用しています。 このアダプタにはテキストファイル用のリゾルバクラスが含まれていますが、 リゾルバインターフェイスを実装することで、 その他のリゾルバも簡単に作成できます。

### File リゾルバ

ファイルリゾルバは、非常にシンプルなクラスです。 ファイル名を指定するプロパティを保持しており、 コンストラクタでこれを指定できます。 `resolve()` メソッドはテキストファイルを走査し、 ユーザ名とレルムにマッチする行を探します。テキストファイルのフォーマットは Apache の htpasswd ファイルと似た形式で

    <username>:<realm>:<credentials>\n

のようになります。個々の行は ユーザ名、レルムおよび認証情報の三つのフィールドで構成されており、 それらがコロンで区切られています。リゾルバは認証情報フィールドの内容を理解することはできません。 取得した値をそのまま呼び出し元に返します。したがって、 同じ形式でベーシック認証およびダイジェスト認証の両方に対応できます。 ベーシック認証では、このフィールドは平文テキストで書く必要があります。 ダイジェスト認証では、これは先ほど説明したような MD5 ハッシュとなります。

ファイルリゾルバを作成する方法は次の二通りで、どちらも同じくらい簡単です。まずは

    $path     = 'files/passwd.txt';
    $resolver = new Zend_Auth_Adapter_Http_Resolver_File($path);

もうひとつは

    $path     = 'files/passwd.txt';
    $resolver = new Zend_Auth_Adapter_Http_Resolver_File();
    $resolver->setFile($path);

指定したパスが空だったり読み込みできなかったりした場合は、 例外をスローします。

## 基本的な使用法

まず、必須設定項目を含む配列を作成します。

    $config = array(
        'accept_schemes' => 'basic digest',
        'realm'          => 'My Web Site',
        'digest_domains' => '/members_only /my_account',
        'nonce_timeout'  => 3600,
    );

この配列は、アダプタに対してベーシック認証およびダイジェスト認証の両方を受け付けるように指定します。 また、`/members_only` および `/my_account` の配下では認証済みアクセスが必要となるようにします。 realm の値は、通常はブラウザのパスワードダイアログボックスに表示されます。 nonce_timeout は、もちろん、先ほど説明したとおりの振る舞いをします。

次に、`Zend_Auth_Adapter_Http` オブジェクトを作成します。

    require_once 'Zend/Auth/Adapter/Http.php';
    $adapter = new Zend_Auth_Adapter_Http($config);

ベーシック認証およびダイジェスト認証の両方をサポートしているので、 ふたつのリゾルバオブジェクトを作成する必要があります。 これは、単にふたつの異なるクラスを作成するだけの簡単なことです。

    $basicResolver = new Zend_Auth_Adapter_Http_Resolver_File();
    $basicResolver->setFile('files/basicPasswd.txt');

    $digestResolver = new Zend_Auth_Adapter_Http_Resolver_File();
    $digestResolver->setFile('files/digestPasswd.txt');

    $adapter->setBasicResolver($basicResolver);
    $adapter->setDigestResolver($digestResolver);

最後に、認証を行います。このアダプタは、 リクエストオブジェクトおよびレスポンスオブジェクトの両方を参照する必要があります。

    assert($request instanceof Zend_Controller_Request_Http);
    assert($response instanceof Zend_Controller_Response_Http);

    $adapter->setRequest($request);
    $adapter->setResponse($response);

    $result = $adapter->authenticate();
    if (!$result->isValid()) {
        // ユーザ名/パスワードが間違っている、あるいはパスワード入力をキャンセルした
    }