昼寝帝国の逆襲

適当に書きます

CentoOS7でRedmineのアカウントを使ってSubeversionとGitの認証をしてみるのすけ

そういえばCentOS7ってどんなもんなんだろうということで個人で使ってるサーバのOSをCentOS7に変えてやりました。

結果:早まった感がある。

Redmine入れるときもgem入れるときにゴネられたりとかSelinuxであれこれありましたけど、その辺はわりと簡単に処理できるので割愛。

RedmineSubversionとGitの認証を共通化したいのは、Apache+Subversionだとパスワードの変更するのにいちいちsshしてファイル書き換えてという面倒があるので、認証をRedmineのアカウントでやってしまえるようにしたいという感じです。

そんで、結構色々な人が書いてるのですが、やり方は2パターンあります。

1.Redmine.pmを使う
2.mod_auth_mysqlを使う

個人的な好みとして、apacheのモジュールでやる方がかっこいいということで、後者の方法でやるんですが、CentOS7でやるとネックなのが

apacheが2.4系
MySQLじゃなくてMariaDB(実際大して変わってないけど)

mod_auth_mysql自体枯れているというか充足しちゃってるので、2005年6月以降更新がないです。

mod_auth_mysql


なので、apache2.4系で素直に動いてくれるわけもないので、パッチ当てたり色々必要になります。

mod_auth_mysql / Patches / #13 Patch for Apache 2.4

2.4系のパッチはここにあります。
その後にRedmineのsaltに対応するパッチを当てないといけないので、余計に面倒さが増すんですが、

SubversionとRedmineのアカウント共通化(プロジェクト毎にグループ化可能) - iWA’s 雑記@はてな出張所

その辺はこちらを参考に。

ソースからコンパイルしちゃえば楽なんですが、rpmあるんだし使いたいということで、rpmをビルドしちゃいたい。

というわけで、

  1. ソース拾ってくる
  2. パッチ当てる
  3. rpmbuild
  4. インストール

という手順でやります。
コマンドの記録するの忘れてたので順番だけですいません。

ソース拾ってくる

本家サイトからだろSPEC書いたり面倒なので、ここはCentOS6.6のsrpmは拝借。

http://vault.centos.org/6.6/os/Source/SPackages/mod_auth_mysql-3.0.0-11.el6_0.1.src.rpm

wget ftp://ftp.pbone.net/mirror/vault.centos.org/6.2/os/Source/SPackages/mod_auth_mysql-3.0.0-11.el6_0.1.src.rpm
rpm -ivh mod_auth_mysql-3.0.0-11.el6_0.1.src.rpm 
パッチ当てる

パッチは先ほど上げた2種なんですが、CentOS6のソースで2.2系に対応するパッチが含まれていて、2.4系対応パッチと内容が一部重複します。
それらのパッチ適用後の内容に合わせてパッチの中身を編集するとこんな感じになります。

内容を編集するとこんな感じ。

--- mod_auth_mysql-3.0.0/mod_auth_mysql.c       2005-06-22 12:17:45.000000000 -0400
+++ mod_auth_mysql-3.0.0_patch_apache_2.4/mod_auth_mysql.c      2013-12-30 18:07:27.646704470 -0500
@@ -237,7 +237,7 @@
   #define SNPRINTF ap_snprintf
   #define PSTRDUP ap_pstrdup
   #define PSTRNDUP ap_pstrndup
-  #define STRCAT ap_pstrcat
+  #define STRCAT apr_pstrcat
   #define POOL pool
   #include <stdlib.h>
   #include "ap_sha1.h"
@@ -907,7 +907,7 @@
 }

 static char * format_remote_ip(request_rec * r, char ** parm) {
-  return r->connection->remote_ip;
+  return r->connection->client_ip;
 }
 
 static char * format_filename(request_rec * r, char ** parm) {
@@ -1272,7 +1272,7 @@
   int method = r->method_number;
 
 #ifdef APACHE2
-  const apr_array_header_t *reqs_arr = ap_requires(r);
+  const apr_array_header_t *reqs_arr = NULL;
 #else
   const array_header *reqs_arr = ap_requires(r);
 #endif

diffの結果はこんな感じ

2a3,11
> @@ -206,7 +206,7 @@
>    #define SNPRINTF apr_snprintf
>    #define PSTRDUP apr_pstrdup
>    #define PSTRNDUP apr_pstrndup
> -  #define STRCAT ap_pstrcat
> +  #define STRCAT apr_pstrcat
>    #define POOL apr_pool_t
>    #include "http_request.h"   /* for ap_hook_(check_user_id | auth_checker)*/
>    #include "ap_compat.h"
12c21,130
< @@ -907,7 +907,7 @@
---
> @@ -589,87 +589,87 @@
>  static
>  command_rec mysql_auth_cmds[] = {
>       AP_INIT_TAKE1("AuthMySQLHost", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlhost),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlhost),
>       OR_AUTHCFG, "mysql server host name"),
>  
>       AP_INIT_TAKE1("AuthMySQLPort", ap_set_int_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlport),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlport),
>       OR_AUTHCFG, "mysql server port number"),
>  
>       AP_INIT_TAKE1("AuthMySQLSocket", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlsocket),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlsocket),
>       OR_AUTHCFG, "mysql server socket path"),
>  
>       AP_INIT_TAKE1("AuthMySQLUser", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqluser),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqluser),
>       OR_AUTHCFG, "mysql server user name"),
>  
>       AP_INIT_TAKE1("AuthMySQLPassword", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlpasswd),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlpasswd),
>       OR_AUTHCFG, "mysql server user password"),
>  
>       AP_INIT_TAKE1("AuthMySQLDB", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlDB),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlDB),
>       OR_AUTHCFG, "mysql database name"),
>  
>       AP_INIT_TAKE1("AuthMySQLUserTable", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlpwtable),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlpwtable),
>       OR_AUTHCFG, "mysql user table name"),
>  
>       AP_INIT_TAKE1("AuthMySQLGroupTable", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlgrptable),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlgrptable),
>       OR_AUTHCFG, "mysql group table name"),
>  
>       AP_INIT_TAKE1("AuthMySQLNameField", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlNameField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlNameField),
>       OR_AUTHCFG, "mysql User ID field name within User table"),
>  
>       AP_INIT_TAKE1("AuthMySQLGroupField", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlGroupField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlGroupField),
>       OR_AUTHCFG, "mysql Group field name within table"),
>  
>       AP_INIT_TAKE1("AuthMySQLGroupUserNameField", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlGroupUserNameField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlGroupUserNameField),
>       OR_AUTHCFG, "mysql User ID field name within Group table"),
>  
>       AP_INIT_TAKE1("AuthMySQLPasswordField", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlPasswordField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlPasswordField),
>       OR_AUTHCFG, "mysql Password field name within table"),
>  
>       AP_INIT_TAKE1("AuthMySQLPwEncryption", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlEncryptionField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlEncryptionField),
>       OR_AUTHCFG, "mysql password encryption method"),
>  
>       AP_INIT_TAKE1("AuthMySQLSaltField", ap_set_string_slot,
> -     (void*) APR_XtOffsetOf(mysql_auth_config_rec, mysqlSaltField),
> +     (void*) APR_OFFSETOF(mysql_auth_config_rec, mysqlSaltField),
>       OR_AUTHCFG, "mysql salfe field name within table"),
>  
>  /*   AP_INIT_FLAG("AuthMySQLKeepAlive", ap_set_flag_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlKeepAlive),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlKeepAlive),
>       OR_AUTHCFG, "mysql connection kept open across requests if On"),
>  */
>       AP_INIT_FLAG("AuthMySQLAuthoritative", ap_set_flag_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlAuthoritative),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlAuthoritative),
>       OR_AUTHCFG, "mysql lookup is authoritative if On"),
>  
>       AP_INIT_FLAG("AuthMySQLNoPasswd", ap_set_flag_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlNoPasswd),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlNoPasswd),
>       OR_AUTHCFG, "If On, only check if user exists; ignore password"),
>  
>       AP_INIT_FLAG("AuthMySQLEnable", ap_set_flag_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlEnable),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlEnable),
>       OR_AUTHCFG, "enable mysql authorization"),
>  
>       AP_INIT_TAKE1("AuthMySQLUserCondition", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlUserCondition),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlUserCondition),
>       OR_AUTHCFG, "condition to add to user where-clause"),
>  
>       AP_INIT_TAKE1("AuthMySQLGroupCondition", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlGroupCondition),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlGroupCondition),
>       OR_AUTHCFG, "condition to add to group where-clause"),
>  
>       AP_INIT_TAKE1("AuthMySQLCharacterSet", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlCharacterSet),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlCharacterSet),
>       OR_AUTHCFG, "mysql character set to be used"),
>  
>    { NULL }
> @@ -905,7 +905,7 @@
14c132
< 
---
>  
21c139
< @@ -1272,7 +1272,7 @@
---
> @@ -1270,7 +1270,7 @@

で、Redmine対応パッチも行数だけ直しておきます。

--- mod_auth_mysql-3.0.0/mod_auth_mysql.c.redmine
+++ mod_auth_mysql-3.0.0/mod_auth_mysql.c
@@ -288,6 +288,7 @@
 static short pw_aes(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
 #endif
 static short pw_sha1(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
+static short pw_sha1_rm(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
 static short pw_plain(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
 
 static char * format_remote_host(request_rec * r, char ** parm);
@@ -318,7 +319,8 @@
 #if _AES
                                           {"aes", SALT_REQUIRED, pw_aes},
 #endif
-                                          {"sha1", NO_SALT, pw_sha1}};
+                                          {"sha1", NO_SALT, pw_sha1},
+                                          {"sha1-rm", SALT_OPTIONAL, pw_sha1_rm}};
 typedef struct {               /* User formatting patterns */
   char pattern;                        /* Pattern to match */
   char * (*func)(request_rec * r, char ** parm);
@@ -858,6 +858,42 @@
   return  strcasecmp(bin2hex(pool, scrambled_sent_pw, enc_len), real_pw) == 0;
 }
 
+/* checks SHA1 passwords - adjusted for use with redmine */
+static short pw_sha1_rm(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt) {
+  char salt_and_pw[500];
+  char scrambled_pw[500];
+  char *scrambled_sent_pw, *buffer=PCALLOC(pool, 128);
+  char *scrambled_salt_pw, *buffer01=PCALLOC(pool, 128);
+  short enc_len = 0;
+  short enc_len01 = 0;
+#ifdef APACHE2
+  apr_sha1_base64(sent_pw, strlen(sent_pw), buffer);
+  buffer += 5;   /* go past {SHA1} eyecatcher */
+  scrambled_sent_pw = PCALLOC(pool, apr_base64_decode_len(buffer) + 1);
+  enc_len = apr_base64_decode(scrambled_sent_pw, buffer);
+  //scramble (salt+scrambled_pw) for redmine:
+  strcpy(salt_and_pw,salt);
+  strcpy(scrambled_pw,bin2hex(pool, scrambled_sent_pw, enc_len));
+  //conver scrambled_pw to lower:
+  int i;
+  for (i = 0; scrambled_pw[i]; i++)
+  scrambled_pw[i] =tolower(scrambled_pw[ i ]);
+  //cat salt + scrambled_pw:
+  strcat(salt_and_pw,scrambled_pw);
+  apr_sha1_base64(salt_and_pw, strlen(salt_and_pw), buffer01);
+  buffer01 += 5;   /* go past {SHA1} eyecatcher */
+  scrambled_salt_pw = PCALLOC(pool, apr_base64_decode_len(buffer01) + 1);
+  enc_len01 = apr_base64_decode(scrambled_salt_pw, buffer01);
+#else
+  ap_sha1_base64(sent_pw, strlen(sent_pw), buffer);
+  buffer += 5;   /* go past {SHA1} eyecatcher */
+  scrambled_sent_pw = PCALLOC(pool, ap_base64decode_len(buffer) + 1);
+  enc_len = ap_base64decode(scrambled_sent_pw, buffer);
+#endif
+  scrambled_sent_pw[enc_len] = '\0';
+  return  strcasecmp(bin2hex(pool, scrambled_salt_pw, enc_len01), real_pw) == 0;
+}
+
 /* checks plain text passwords */
 static short pw_plain(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt) {
   return strcmp(real_pw, sent_pw) == 0;
rpmbuild

適当にSPECを編集して2.4系対応パッチの後にRedmine対応パッチの順でパッチが当たるようにしてください。

インストール

ビルドしたらインストール。
あとはconfをちゃんと書いてあげればいいです。

    AuthBasicAuthoritative off
    AuthMySQLAuthoritative On
    AuthUserFile /dev/null

も書いておかないとエラー出ます。

以上。備忘のため。