環境変数は各自で書き変えてほしいのと何かあっても責任は負いません。

DIGEST認証(BASIC認証)にユーザを追加するためには、以下の2点が考えられる。

  • htdigestコマンドを個人に実行させ、共通のパスワードファイルを編集させる
  • 管理者がコマンドを実行し、ユーザを追加する

ただし前者は共通ファイルへの編集権限が必要となりサーバ管理上望ましくなく、また後者は管理者の負荷増と管理者にパスワードを知らせる問題がある。これらの問題はWebシステムを構築し、管理するのであれば解決可能であるが、構築に環境や時間を要するため現実的ではない。

ここではバッチ処理によるDIGEST認証のユーザの更新方法について説明する。

①OSユーザが追加したいユーザ情報を持つパスワードファイルを作成する(digest_user.sh)

②ユーザのパスワードファイルを回収し、更新処理を定時実行させる(digest_syn.sh)

③同時にLacationディレクティブにユーザを追加する(digest_location.sh)

①OSユーザが追加したいユーザ情報を持つパスワードファイルを作成する(digest_user.sh)
htdigestコマンドをOSユーザ個別に実行させても情報を回収利用できないので、シェルを実行させユーザ情報の作成を行う。ただしシェルは一般のOSユーザが実行できる必要あり。

なおユーザ情報作成後にユーザ名を編集し、不正にアクセスを試みる可能性がある。このため後でパスワードファイルを回収し、追加/更新する際にはOSユーザと一致していることをチェックする。OSユーザ名以外のユーザを作成したい場合は、管理者が手動に行う。なぜかというとファイル権限の関係上、限界があるため。

シェル:digest_user.sh

#!/bin/bash

#ファイル作成ディレクトリを作成(pオプションで存在する場合は無視)
mkdir -p {ファイル作成ディレクトリ}

#htdigestを実行し、OSユーザのホームディレクトリにファイル作成
htdigest -c "/home/"`whoami`"/"{ユーザのパスワードファイル} "" `whoami`

注意:今後の処理でこけるのでレルムは指定してはならない。

例:/usr/local/bin/digest_user.sh

#!/bin/bash

mkdir -p "/home/"`whoami`"/digest/"
htdigest -c "/home/"`whoami`"/digest/.digest" "" `whoami`

 
実行

[user1 ~]$ /usr/local/bin/digest_user.sh
Adding password for user1 in realm .
New password:
Re-type new password:
[user1 ~]$ cd digest/
[user1 digest]$ pwd
/home/user1/digest
[user1 digest]$ less .digest
user1::feac37c08d087b9a687c1988f36e2272


 
②ユーザのパスワードファイルを回収し、更新処理を定時実行させる(digest_syn.sh)

OSユーザがdigest_user.shを実行して作成したユーザのパスワードファイルを回収する。回収先はdigest_user.shで定義したディレクトリで、存在していれば追加/更新を行い、存在していなければ削除される。

まずレルムごとに許可するユーザを定義したレルム定義ファイルを作成する。理由はOSユーザ側で不正に特定のレルムに対してアクセスすることを防ぐためである。レルム定義ファイルに定義されていないOSユーザは、いくら追加しようとしても追加はできない。レルム定義ファイルの情報で、ダイジェスト認証の情報が作成される。

レルム定義ファイル:.digest_realm

:レルム名A
ユーザ名A1
ユーザ名A2

:レルムB
ユーザ名B1

 
例:

:REALM1
user1
user2

:REALM2
user2

注意:user1はREALM2に対し、追加することはできない。

またOSユーザが作成する以外のユーザ情報を管理者が事前ユーザ定義ファイルに定義しておく。このファイルの情報は通常のDIGEST認証のファイルでよく、digest_syn.shの実行時にそのまま追加される。

事前ユーザ定義ファイル:.digest_user_base

userA:REALM1:feac37c08d087b9a687c1988f36e227a
userB:REALM1:feac37c08d087b9a687c1988f36e227b
userC:REALM1:feac37c08d087b9a687c1988f36e227c

レルム定義ファイルの情報からパスワードを作成する。レルム名と定義されるユーザからユーザのパスワードを探し、レルム名とパスワードの情報を付け合わせる。最終的に事前ユーザ情報と付け合わせて情報を合わせたパスワードファイルが作成されるので、Apacheでこのファイルを指定する。

注意として定義されているユーザのパスワードファイルが存在しないとエラーをはくので気になる場合は対処する。対処としてはシェルを呼び出す側で “> /dev/null 2 >&1″ でも付ければ対処可能だ。

シェル:digest_syn.sh(環境変数の値は合わせて変更してください。)

#!/bin/bash

# 実行ディレクトリ
HDN_DIGEST_DIRECTORY="/usr/local/batch/digest"

# DIGEST認証関係定義
HDN_DIGEST_USER=${HDN_DIGEST_DIRECTORY}"/.digest_user_base"
HDN_DIGEST_REALM=${HDN_DIGEST_DIRECTORY}"/.digest_realm"

# 定義
HDN_DIGEST_TMP=${HDN_DIGEST_DIRECTORY}"/.digest.tmp"
HDN_DIGEST_USER_FILE="/digest/.digest"
HDN_DIGEST_APACHE_FILE="/usr/local/digest/.passwd"

# 事前ユーザ定義のコピー
rm -f $HDN_DIGEST_TMP > /dev/null 2>&1
cp -p $HDN_DIGEST_USER $HDN_DIGEST_TMP > /dev/null 2>&1

# レルム定義ファイルからレルムを読み込む変数
HDN_VAL_REALM=""

# DIGEST認証の認証ファイルの作成
while read LINE; do

    # レルム定義ファイルの読込
    LINE=`echo $LINE | sed -e "s/ //"`

    if [ ${#LINE} -eq 0 ]
    then
        continue
    elif [ ${LINE:0:1} = ":" ]
    then
        HDN_VAL_REALM=${LINE:1:${#LINE}-1}
        continue
    elif [ ${#HDN_VAL_REALM} -eq 0 ]
    then
        continue
    fi
    # ユーザ名
    HDN_VAL_USER=$LINE
    # ユーザが作成したパスワードファイル
    HDN_VAL_USER_FILE="/home/"${HDN_VAL_USER}"${HDN_DIGEST_USER_FILE}"
    # ユーザが作成した情報
    HDN_VAL_USER_DIGEST=""

    # ユーザのパスワードファイルの読込
    while read LINE2; do
        HDN_VAL_USER_DIGEST=$LINE2
        HDN_VAL_USER_DIGEST=`echo $HDN_VAL_USER_DIGEST | sed -e "s/ //"`
    done < $HDN_VAL_USER_FILE
    if [ ! ${HDN_VAL_USER_DIGEST} ]
    then
        continue
    fi

    # ユーザのパスワードファイルのチェック
    # ユーザ名
    HDN_VAL_LEN=${#HDN_VAL_USER}
    if [ ${HDN_VAL_USER_DIGEST:0:$HDN_VAL_LEN} != $HDN_VAL_USER ]
    then
        HDN_VAL_USER_DIGEST=""
        continue
    fi

    # ':'の1番目位置確認
    if [ ${HDN_VAL_USER_DIGEST:$HDN_VAL_LEN:1} != ":" ]
    then
        HDN_VAL_USER_DIGEST=""
        continue
    fi

    # ':'の2番目位置確認
    HDN_VAL_LEN=`expr $HDN_VAL_LEN + 1`
    if [ ${HDN_VAL_USER_DIGEST:$HDN_VAL_LEN:1} != ":" ]
    then
        HDN_VAL_USER_DIGEST=""
        continue
    fi

    # ':'を含む場合は不正
    HDN_VAL_LEN=`expr $HDN_VAL_LEN + 1`
    HDN_VAL_LEN2=${#HDN_VAL_USER_DIGEST}
    HDN_VAL_PASSWD=${HDN_VAL_USER_DIGEST:$HDN_VAL_LEN:HDN_VAL_LEN2-HDN_VAL_LEN}
    if [ $HDN_VAL_PASSWD = *:* ]
    then
        HDN_VAL_USER_DIGEST=""
        continue
    fi

    # 一時パスワードファイルに追加
    echo $HDN_VAL_USER":"$HDN_VAL_REALM":"$HDN_VAL_PASSWD >> $HDN_DIGEST_TMP

done < $HDN_DIGEST_REALM

# Apacheで読み込むパスワードファイルに置き換え
cat $HDN_DIGEST_TMP > $HDN_DIGEST_APACHE_FILE
rm -f $HDN_DIGEST_TMP

 
実行

[root digest]# ./digest_syn.sh
./digest_syn.sh: line 93: /home/user2/digest/.digest: そのようなファイルやディレクトリはありません
./digest_syn.sh: line 93: /home/user2/digest/.digest: そのようなファイルやディレクトリはありません
[root digest]# less /usr/local/digest/.passwd
userA:REALM1:feac37c08d087b9a687c1988f36e227a
userB:REALM1:feac37c08d087b9a687c1988f36e227b
userC:REALM1:feac37c08d087b9a687c1988f36e227c
user1:REALM1:feac37c08d087b9a687c1988f36e2272


 
③同時にLacationディレクティブにユーザを追加する(digest_location.sh)

パスワードファイルを作成しただけではApache側でDIGEST認証のユーザの制御はできない。DIGEST認証では指定したユーザのみアクセス権を与えることが可能である。ここの部分をシェルで自動化する(Location設定ファイルを自動で作成する)方法をここで説明する。

ここでの説明にはApacheのhttpd.confに以下の設定をし、設定ファイルをconf.dへ外だしできるものとする。

Include conf.d/*.conf

 
パスワードファイル同様にLocation設定ファイルも、Location情報定義ファイルを作成する。

Location情報定義ファイル:.dialog_location_define

:CONFファイル名A(.conf除く)
LOCATION=対象URL A(Location xxxxx)
AUTHNAME=レルムA(AuthName xxxxx)
REQUIRE=許可するユーザA(Require user xxxxx)

:CONFファイル名B(.conf除く)
LOCATION=対象URL-B(Location xxxxx)
AUTHNAME=レルムB(AuthName xxxxx)
REQUIRE=許可するユーザB(Require user xxxxx)

例:

:REALM1_AUTH
LOCATION=/sample
AUTHNAME=REALM1
REQUIRE=user1

:REALM2_AUTH
LOCATION=/a/b/c
AUTHNAME=REALM2
REQUIRE=user2

 
処理はLocation情報定義ファイルの情報を元に実行される。CONFファイル名を1単位とし、各項目値が読み込まれるとLocation設定ファイルが作成される。このとき項目漏れがあると不正な定義とみなし、読み飛ばされるので注意。

Location設定ファイル名はCONFファイル名.confとなり、指定したconf.dディレクトリに出力されるシェルの実行後、httpd.confの設定が正しければApacheをreloadすれば読み込まれる。

シェル:digest_location.sh(環境変数の値は合わせて変更してください。)

#!/bin/bash

# 実行ディレクトリ
HDN_DIGEST_DIRECTORY="/usr/local/batch/digest"

# Location関係定義(digest_location.sh)
HDN_DIGEST_LOCATION_MAKE=${HDN_DIGEST_DIRECTORY}"/digest_location_make.sh"
HDN_DIGEST_LOCATION_DEFINE=${HDN_DIGEST_DIRECTORY}"/.digest_location_define"
HDN_DIGEST_LOCATION="LOCATION"
HDN_DIGEST_REQUIRE="REQUIRE"
HDN_DIGEST_AUTHNAME="AUTHNAME"

# 定義
HDN_DIGEST_CONFD="/etc/httpd/conf.d/"
HDN_DIGEST_USER_FILE="/digest/.digest"
HDN_DIGEST_APACHE_FILE="/usr/local/digest/.passwd"

HDN_VAL_CONFFILE=""
HDN_VAL_LOCATION=""
HDN_VAL_REQUIRE=""
HDN_VAL_AUTHNAME=""
HDN_VAL_LOCATION_LEN=`expr ${#HDN_DIGEST_LOCATION} + 1`
HDN_VAL_REQUIRE_LEN=`expr ${#HDN_DIGEST_REQUIRE} + 1`
HDN_VAL_AUTHNAME_LEN=`expr ${#HDN_DIGEST_AUTHNAME} + 1`

# Location情報定義ファイル
while read LINE; do

    if [ ${#LINE} -eq 0 ]
    then
        continue

    elif [ ${LINE:0:1} = ":" ]
    then

        # セクション読込完了後
        if [ ${#HDN_VAL_CONFFILE} > 0 -a ${#HDN_VAL_LOCATION} > 0 -a ${#HDN_VAL_REQUIRE} > 0 -a ${#HDN_VAL_AUTHNAME} > 0 ]
        then
            # conf.dファイルパス
            HDN_VAL_CONFFILE2=${HDN_DIGEST_CONFD}${HDN_VAL_CONFFILE}".conf"
            
            ${HDN_DIGEST_LOCATION_MAKE} $HDN_VAL_CONFFILE2 $HDN_VAL_LOCATION $HDN_VAL_AUTHNAME $HDN_DIGEST_APACHE_FILE $HDN_VAL_REQUIRE
            chown apache:apache $HDN_VAL_CONFFILE2
            chmod 700 $HDN_VAL_CONFFILE2
        fi

        HDN_VAL_LOCATION=""
        HDN_VAL_REQUIRE=""
        HDN_VAL_AUTHNAME=""
        HDN_VAL_CONFFILE=${LINE:1:${#LINE}-1}
        continue

    # 1行目
    elif [ ${LINE:0:HDN_VAL_LOCATION_LEN} = ${HDN_DIGEST_LOCATION}"=" ]
    then
        HDN_VAL_LOCATION=${LINE:HDN_VAL_LOCATION_LEN:${#LINE}-HDN_VAL_LOCATION_LEN}
        continue

    # 2行目
    elif [ ${LINE:0:HDN_VAL_REQUIRE_LEN} = ${HDN_DIGEST_REQUIRE}"=" ]
    then
        HDN_VAL_REQUIRE=${LINE:HDN_VAL_REQUIRE_LEN:${#LINE}-HDN_VAL_REQUIRE_LEN}
        continue

    # 3行目
    elif [ ${LINE:0:HDN_VAL_AUTHNAME_LEN} = ${HDN_DIGEST_AUTHNAME}"=" ]
    then
        HDN_VAL_AUTHNAME=${LINE:HDN_VAL_AUTHNAME_LEN:${#LINE}-HDN_VAL_AUTHNAME_LEN}
        continue
    fi

done < $HDN_DIGEST_LOCATION_DEFINE

if [ ${#HDN_VAL_CONFFILE} > 0 -a ${#HDN_VAL_LOCATION} > 0 -a ${#HDN_VAL_REQUIRE} > 0 -a ${#HDN_VAL_AUTHNAME} > 0 ]
then
    HDN_VAL_CONFFILE2=${HDN_DIGEST_CONFD}${HDN_VAL_CONFFILE}".conf"
    ${HDN_DIGEST_LOCATION_MAKE} $HDN_VAL_CONFFILE2 $HDN_VAL_LOCATION $HDN_VAL_AUTHNAME $HDN_DIGEST_APACHE_FILE $HDN_VAL_REQUIRE
    chown apache:apache $HDN_VAL_CONFFILE2
    chmod 700 $HDN_VAL_CONFFILE2
fi

 
シェル:digest_location_make.sh

#!/bin/bash

HDN_FILE=""
HDN_LOCATION=""
HDN_AUTHNAME=""
HDN_PASSWDFILE=""
HDN_REQUIRE=""

count=1
for a in "$@"
do
    if [ $count -eq 1 ]
    then
        HDN_FILE=$a
    elif [ $count -eq 2 ]
    then
        HDN_LOCATION=$a
    elif [ $count -eq 3 ]
    then
        HDN_AUTHNAME=$a
    elif [ $count -eq 4 ]
    then
        HDN_PASSWDFILE=$a
    else
        HDN_REQUIRE=$HDN_REQUIRE" "$a
    fi
    count=`expr $count + 1`
done


echo "<Location "${HDN_LOCATION}">" > $HDN_FILE
echo "    SSLRequireSSL" >> $HDN_FILE
echo "    AuthName "${HDN_AUTHNAME} >> $HDN_FILE
echo "    AuthType Digest" >> $HDN_FILE
echo "    AuthUserFile "${HDN_PASSWDFILE} >> $HDN_FILE
echo "    AuthGroupFile /dev/null" >> $HDN_FILE
echo "    Require user "${HDN_REQUIRE} >> $HDN_FILE
echo "</Location>" >> $HDN_FILE

 
実行

[root digest]# ./digest_location.sh
[root digest]# ls /etc/httpd/conf.d/
REALM1_AUTH.conf  REALM2_AUTH.conf
[root digest]# less /etc/httpd/conf.d/REALM1_AUTH.conf
<Location /sample>
    SSLRequireSSL
    AuthName REALM1
    AuthType Digest
    AuthUserFile /usr/local/digest/.passwd
    AuthGroupFile /dev/null
    Require user  user1
</Location>
[root digest]# less /etc/httpd/conf.d/REALM2_AUTH.conf
<Location /a/b/c>
    SSLRequireSSL
    AuthName REALM2
    AuthType Digest
    AuthUserFile /usr/local/digest/.passwd
    AuthGroupFile /dev/null
    Require user  user2
</Location>


Leave a Reply

preload preload preload