HomeTravel ReportLocal FoodRail&BusAirportMileagemiscAbout Me
TechWiki
Updated : January 2011

Apache2.2 mod_authn_mysql 2.2.3

Basic認証、Digest認証での認証機構であり、MySQLデータベース上のパスワード管理テーブルとの照合を行う。

  

ダウンロード

Current unofficial CVS Apache webserver binaries and module binaries

http://www.gknw.net/development/apache/httpd-2.2/win32/modules/

mod_authn_mysql-2.2.3-w32.zip 17-Aug-2006 15:26  138K  ZIP compressed archive
Windows版のライブラリが同梱されているが、MySQLのライブラリのバージョンが異なっている(場合が多い)ので、自分でビルドすることとなる。

データベース中のパスワードが平文であることが気にならなければ、ソースコードの修正の必要はない。

       

パスワードのhash方法

データベース中に格納されているパスワードは平文であり、セキュリティ上好ましくないため、MD5でhashしたものを格納することとする。

Basic認証の場合

パスワードをMD5でhashしてそのままデータベースに格納する。

ブラウザからはパスワードが平文で送られてくる。

(セキュリティ上好ましくはないが気になる場合はDigest認証となるが、利用できるブラウザの制約がある。)

Digest認証の場合

 (ユーザ名)+”:”+(レルム)+”:”+(パスワード)を連結した文字列をMD5でhashして格納する。

Digest認証の場合、ブラウザで上記のようにHashされた値が渡されてくる。

       

モジュールの修正

Basic認証の場合

認証モジュール(mod_authn_mysql)の「check_mysql_pw」関数でパスワードの比較をする前に入力されたパスワードをMD5 Hashする処理を追加する。


static authn_status check_mysql_pw(request_rec *r, const char *user,
                                 const char *password)
{
    authn_status ARV = AUTH_DENIED;
    int blah = 0;
    mysql_config *conf;
    mysql_dconfig *dconf = ap_get_module_config(r->per_dir_config,
                                                      &authn_mysql_module);

    char* mysql_password;
    char* query;
    MYSQL_ROW sql_row;
    MYSQL_RES *result = NULL;
    mysql_res *mysql_res;
    const char* esc_user = mysql_escape(user, r->pool);
    char* passwdhash; // Added



    conf = apr_hash_get(authn_mysql_config, dconf->id, APR_HASH_KEY_STRING);
    if(conf == NULL) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
      "[mod_authn_mysql.c] - Server Config for \"%s\" was not found", dconf->id);
        return ARV;
    }

    apr_reslist_acquire(conf->pool,  (void **)&mysql_res);

    /* make the query to get the user's password */

    if (conf->rec.isactive_field) {
        query = apr_psprintf(r->pool, "SELECT %s FROM %s WHERE %s='%s' AND %s!=0 LIMIT 0,1",
                                         conf->rec.password_field, conf->rec.mysql_table,
                                         conf->rec.username_field, esc_user, conf->rec.isactive_field);
    }
    else {
        query = apr_psprintf(r->pool, "SELECT %s FROM %s WHERE %s='%s' AND %s!=0 LIMIT 0,1",
                                         conf->rec.password_field, conf->rec.mysql_table,
                                         conf->rec.username_field, esc_user);
    }

    /* perform the query */

    if (safe_mysql_query(mysql_res,  &result,  r, query) == 0){
        /* store the query result */
        if (result && mysql_num_rows(result) == 1) {
            sql_row = mysql_fetch_row(result);
 
           /* ensure we have a row, and non NULL value */
            if (!sql_row || !sql_row[0]) {
                ARV = AUTH_USER_NOT_FOUND;
            }
            else {
     passwdhash = (char *) ap_md5(r->pool, (const unsigned char*)password); // Added
                mysql_password = (char *) apr_pstrcat(r->pool, sql_row[0], NULL);
// Replaced     if (strcmp(mysql_password,password) != 0) {
                if (strcmp(mysql_password,passwdhash) != 0) {
      ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
       "[mod_authn_mysql.c] - Password Unmatch(%s:%s", mysql_password, password);
                    ARV = AUTH_DENIED;
                }
                else {
                    ARV = AUTH_GRANTED;
                }
            }
        }
    }
    mysql_free_result(result);
    safe_mysql_rel_server(conf->pool, mysql_res, r);
    return ARV;
}

Digest認証の場合

認証モジュール(mod_authn_mysql)の「authn_status get_mysql_realm_hash」関数で、入力されたパスワードをDigest認証用にMD5 Hashしている箇所を削除する。(データベース中のデータが既にHashされているから不要となる。)


static authn_status get_mysql_realm_hash(request_rec *r, const char *user,
                                       const char *realm, char **rethash)
{
    int blah = 0;
    mysql_config *conf;
    authn_status ARV = AUTH_DENIED;
    mysql_dconfig *dconf = ap_get_module_config(r->per_dir_config,
                                                      &authn_mysql_module);
    char* mysql_hash;
    char* mysql_pass;
    char* query;
    const char* esc_user = mysql_escape(user, r->pool);
    MYSQL_ROW sql_row;
    MYSQL_RES *result;
    mysql_res *mysql_res;
 
    conf = apr_hash_get(authn_mysql_config, dconf->id, APR_HASH_KEY_STRING);
    if(conf == NULL) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
      "[mod_authn_mysql.c] - Server Config for \"%s\" was not found", dconf->id);
        return ARV;
    }

    apr_reslist_acquire(conf->pool,  (void **)&mysql_res);

    /* make the query to get the user's password */
    if (conf->rec.isactive_field) {
        query = apr_psprintf(r->pool, "SELECT %s FROM %s WHERE %s='%s' AND %s!=0 LIMIT 0,1",
                                         conf->rec.password_field, conf->rec.mysql_table,
                                         conf->rec.username_field, esc_user, conf->rec.isactive_field);
    }
    else {
        query = apr_psprintf(r->pool, "SELECT %s FROM %s WHERE %s='%s' LIMIT 0,1",
                                         conf->rec.password_field, conf->rec.mysql_table,
                                         conf->rec.username_field, esc_user);
    }

    /* perform the query */

    if (safe_mysql_query(mysql_res, &result,  r, query) == 0) {
        if (mysql_num_rows(result) > 0) {
             sql_row = mysql_fetch_row(result);
             /* ensure we have a row, and non NULL value */
             if (!sql_row || !sql_row[0]) {
                 ARV = AUTH_USER_NOT_FOUND;
             }
             else {
                 mysql_pass = (char *) apr_pstrcat(r->pool, sql_row[0], NULL);
//     mysql_hash = (char *) ap_md5(r->pool, (const unsigned char*)apr_pstrcat(r->pool, mysql_pass, NULL));
//               *rethash = mysql_hash;
                 *rethash = mysql_pass; // Modified

                 ARV = AUTH_USER_FOUND;
             }
        }
    }
    mysql_free_result(result);
    safe_mysql_rel_server(conf->pool, mysql_res, r);
    return ARV;
}

ビルド(Visual Studio 2005)

コンパイルオプション指定例


/O2 /Ob1 /I "C:\Develop\ref\httpd-2.2.9\include" /I "C:\Develop\ref\httpd-2.2.9\os\win32" /I "C:\Develop\ref\httpd-2.2.9\srclib\apr\include" /I "C:\Develop\ref\httpd-2.2.9\srclib\apr-util\include" /I "C:\Develop\ref\httpd-2.2.9\modules\aaa" /I "C:\Develop\ref\mysql-5.1.25-rc-win32\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_VC80_UPGRADE=0x0600" /D "_WINDLL" /GF /FD /EHsc /MD /Gy /Fp".\Release/mod_authn_mysql.pch" /Fo".\Release/" /Fd"Release\mod_authn_mysql" /W3 /nologo /c /TC /errorReport:prompt

リンカオプション指定例


/OUT:"Release/mod_authn_mysql.so" /INCREMENTAL:NO /NOLOGO /LIBPATH:"C:\Develop\ref\Apache2.2\lib" /LIBPATH:"C:\Develop\ref\mysql-5.1.25-rc-win32\lib\opt" /DLL /MANIFEST /MANIFESTFILE:".\Release\mod_authn_mysql.so.intermediate.manifest" /NODEFAULTLIB:"msvcrt.lib" /PDB:".\Release/mod_authn_mysql.pdb" /MAP:".\Release/mod_authn_mysql.map" /SUBSYSTEM:WINDOWS /BASE:"@C:\Develop\ref\httpd-2.2.9\os\win32\BaseAddr.ref,mod_authn_mysql" /IMPLIB:".\Release/mod_authn_mysql.lib" /MACHINE:X86 /ERRORREPORT:PROMPT libhttpd.lib libapr-1.lib libaprutil-1.lib wsock32.lib mysqlclient.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib

Apache2.2の設定

  conf/httpd.confを修正して設定する。

Basic認証の例


LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authn_mysql_module modules/mod_authn_mysql.so
 
<IfModule mod_authn_mysql.c>
  AuthnMySQLDBHost SRV1 localhost
  AuthnMySQLDBUsername SRV1 (MySQLユーザ)
  AuthnMySQLDBPassword SRV1 (MySQLパスワード)
  AuthnMySQLDB SRV1 (MySQLデータベース)
  AuthnMySQLTable SRV1 (テーブル名)
  AuthnMySQLUsernameField SRV1 (ユーザID列名)
  AuthnMySQLPasswordField SRV1 (パスワード列名)
  AuthnMySQLIsActiveField SRV1 active_flag
  AuthnMySQLConnMin SRV1 3
  AuthnMySQLConnSoftMax SRV1 12
  AuthnMySQLConnHardMax SRV1 20
  AuthnMySQLConnTTL SRV1 600
  
 <Location />
    AuthName "名称"
    AuthType Basic
    AuthBasicProvider mysql
    AuthnMySQLServerConfig SRV1
    require valid-user
  </Location>
</IfModule>

Digest認証の例


LoadModule auth_digest_module modules/mod_auth_digest.so
LoadModule authn_mysql_module modules/mod_authn_mysql.so
 
<IfModule mod_authn_mysql.c>
  AuthnMySQLDBHost SRV1 localhost
  AuthnMySQLDBUsername SRV1 (MySQLユーザ)
  AuthnMySQLDBPassword SRV1 (MySQLパスワード)
  AuthnMySQLDB SRV1 (MySQLデータベース)
  AuthnMySQLTable SRV1 (テーブル名)
  AuthnMySQLUsernameField SRV1 (ユーザID列名)
  AuthnMySQLPasswordField SRV1 (パスワード列名)
  AuthnMySQLIsActiveField SRV1 active_flag
  AuthnMySQLConnMin SRV1 3
  AuthnMySQLConnSoftMax SRV1 12
  AuthnMySQLConnHardMax SRV1 20
  AuthnMySQLConnTTL SRV1 600
  
 <Location />
    AuthName "名称"
    AuthType Digest
    AuthDigestProvider mysql
   AuthBasicProvider off
    AuthnMySQLServerConfig SRV1
    require valid-user
  </Location>
</IfModule>


Copyright(c) 2012-2013 T.F.T. All rights reserved.