Windows Server に Apache を利用して Subversion サーバーを構築して ActiveDirectory 認証を設定する

タイトルの通り。以下の環境・アプリケーションを使用して Subversion サーバーを構築する。

1. 準備

ApacheHaus の Web ページから、Apache および Subversion のモジュールをダウンロードする。 Windows 向けのパッケージは ApacheHaus 以外のサイトでも公開されているが、ApacheHaus だと Subversion のモジュールも一緒に提供されているので安心感がある。

http://www.apachehaus.com/cgi-bin/download.plx

今回は以下のモジュールをダウンロード。 Apache および Subversion のモジュールは VC9 でコンパイルされたものと VC11 でコンパイルされたものの 2 種類があるので揃えるように注意する。

2. モジュールを展開する

ダウンロードしたモジュールを展開する。今回はそれぞれ以下のディレクトリに展開する。

D:\
  `- Application\
     `- Apache\
        `- httpd-2.4.16-x64\

3. リポジトリを配置するディレクトリを作成する

Subversionリポジトリを配置するディレクトリを作成する。今回は D:\Application\Apache\_svn\repositories というディレクトリを作成。

4. Apache の設定ファイルを修正

Apache の設定ファイルを修正。主な修正内容は以下のとおり。

httpd.conf

  • デフォルトの設定だと ServerRoot が存在しないディレクトリをを指しているので修正
  • 必要なモジュールを有効化
  • 今回用に作成する設定ファイルを読み込むように設定

svn.conf (新規作成)

httpd.conf

修正する箇所のみ記載。

(デフォルトの設定だと `ServerRoot` が存在しないディレクトリをを指しているので修正)
- Define SRVROOT "/Apache24"
+ Defile SRVROOT "D:/Application/Apache/httpd-2.4.16-x64"

(必要なモジュールを有効化。それぞれ先頭の # を削除してコメント解除。)
- #LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
+ LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
- #LoadModule ldap_module modules/mod_ldap.so
+ LoadModule ldap_module modules/mod_ldap.so

(今回用に作成する設定ファイルを読み込むように設定)
+ Include conf/svn.conf

svn.conf

httpd-2.4.16-x64\conf ディレクトリ内に新規ファイルとして作成する。

#### Subversion サーバー
# モジュールロード
LoadModule dav_module       modules/mod_dav.so
LoadModule dav_fs_module    modules/mod_dav_fs.so
LoadModule dav_svn_module   modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
# バーチャルホスト設定
<VirtualHost *:80>
    ServerAdmin administrator@example.com
    ServerName svn.example.com
    CustomLog "logs/svn.example.com/access.log" common
    ErrorLog "logs/svn.example.com/error.log"
    Timeout 1200
    ProxyTimeout 1200

    <Location /svn/>
        DAV                 svn
        SVNParentPath       "D:/Application/Apache/_svn/repositories"
        SVNListParentPath   on
        AuthzSVNAccessFile  "D:/Application/Apache/_svn/access-rule.txt"
        
        # LDAP認証
        AuthType Basic
        AuthName "Subversion Repository"
        AuthBasicProvider ldap
        AuthLDAPUrl "ldap://ad.example.com:389/DC=example,DC=com?sAMAccountName?sub?(objectClass=user)"
        AuthLDAPBindDN  Administrator@example.com
        AuthLDAPBindPassword  administrator-password
        Require valid-user
        LDAPReferrals Off
    </Location>
</VirtualHost>

以下、簡単にディレクティブの設定を解説。詳しくはお調べください。

  • CustomLog, ErrorLog
    該当のバーチャルホストにアクセスされた際のアクセスログとエラーログの出力先を指定。
    今回は logs\svn.example.com ディレクトリにログを出力するように設定しているが、svn.example.com ディレクトリを事前に作成していないと apache の起動に失敗するので注意。
  • SVNParentPath
    Subversion リポジトリが配置されているディレクトリを指定。
  • AuthzSVNAccessFile
    リポジトリごとにアクセス権限を設定するためのファイルを指定。権限の設定方法は後述。
  • AuthLDAPUrl, AuthLDAPBindDN, AuthLDAPBindPassword
    LDAP サーバー (今回は ActiveDirectory) に接続するための情報を指定。
  • LDAPReferrals Off
    よくわからないけど付けないとエラーが発生する。

5. リポジトリの作成

D:/Application/Apache/_svn/repositories ディレクトリにリポジトリを作成する。他のサーバーに作成済みの Subversion リポジトリをコピーしてきても OK 。 リポジトリを作成するためのコマンドは、Apache ディレクトリに統合した際に httpd-2.4.16-x86\bin に展開されているので、パスを通すか直接呼び出す。

初期ディレクトリの作成が長くて打ち間違えると大変なので、バッチ化した方がいい。

(リポジトリのルートディレクトリに移動)
> cd D:\Application\Apache\_svn\repositories

(リポジトリ hoge を作成)
> D:\Application\Apache\httpd-2.4.16-x64\bin\svnadmin.exe create hoge

(初期ディレクトリ作成)
> D:\Application\Apache\httpd-2.4.16-x64\bin\svn.exe mkdir ^
    file:///D:/Application/Apache/_svn/repositories/hoge/trunk ^
    file:///D:/Application/Apache/_svn/repositories/hoge/branches ^
    file:///D:/Application/Apache/_svn/repositories/hoge/tags ^
    -m "Create base directories"

6. リポジトリの権限設定

D:/Application/Apache/_svn/access-rule.txtリポジトリのアクセス権限を設定するためのファイルを作成する。

[groups]
hoge = rabitarochan, user_aaa, user_bbb
fuga = user_aaa, user_bbb

[repo_hoge:/]
* = 
@hoge = rw

[repo_fuga:/]
* = 
@fuga = rw

以下、簡単に解説。詳細は AuthzSVNAccessFile でググろう。

  • [groups] 以下にグループを定義することができる。<グループ名> = <ユーザー名> の形式で記述し、ユーザー名はカンマで区切る。
  • [<リポジトリ(ディレクトリ)名>:<パス>] 以下にアクセス権限を定義できる。パスは /hoge のように詳細に設定することも可能。
    • * = をはじめに定義し、全てのユーザーからのアクセスを禁止する。
    • @hoge = rw を定義し、hoge グループのユーザーに対して read / write 権限を追加。
      読み取り専用の権限を設定する場合は @hoge = r と記述する。
    • グループは必ず作成する必要はなく、user_ccc = rw とユーザーの権限を直接定義することも可能。

7. ApacheWindows サービスに登録する。

コマンドプロンプトにて以下のコマンドを実行。

(Windows サービスに登録)
> D:\Application\Apache\httpd-2.4.16-x64\bin\httpd.exe -k install

以下、オプションなど補足。

  • -n <サービス名> とすると、サービス名を指定できる。デフォルトは Apache2.4
  • Windows サービスを解除する場合は -k uninstall を実行する。もし -n オプションでサービス名を指定して登録した場合は、名前を揃える必要があるので注意する。

8. 起動, 動作確認

Windows サービスの管理画面から、登録したサービスを開始する。Apache の設定ファイルの記載ミスや、必要なファイル, ディレクトリがない場合は起動に失敗するため、Apache のログファイルを参照して解決する。

まとめ

Apache + Subversion on Windows Server の手順をほぼ 1 から解説してみました。 Collabnet Subversion Edge が遅いと苦情を受けた方 (おれおれ!!) は、ぜひお試しください。

タプルをそれぞれの変数に展開するときにも `@` が使える

FP in Scala の日本語訳読んでます。

読んでることとは直接関係ないですが、例えばこんな関数があったとします。

// 第6章 純粋関数型の状態から
// RNG は乱数生成の状態を表すオブジェクトだと思ってください。

def nextInt: (Int, RNG) = ???

この関数を変数に取る際、それぞれ別の変数に分割して取ることができます。

// i には生成した乱数が、nextRng には状態が取れる。
val (i, nextRng) = nextInt

「べつの変数にも分割して取りたいけど、パターンマッチみたいにタプルも一緒に取りたいなー」と思ってたら、同じ書き方で取ることができるようです。知らなかった・・・。

// tpl には結果のタプルがそのまま取れる。
val tpl @ (i, nextRng) = nextInt

私が知らなかっただけかもしれませんが、少し感動したのでブログ書きました。

C#の「nameof」をScalaで実装してみる

C# vNext に、nameofという演算子が追加されています。

blog.xin9le.net

どういうものかというと、指定したメンバー名を string 型で受け取ることができるというとてもイケてる演算子です。

// こんなクラスがあって
class Person {
  public string Name { get; set; }
  public int Age { get; set; }
}

// こんなことができる
var p = new Person();

Console.WriteLine(nameof(p.Name));  // => "Name"

Console.WriteLine(nameof(p.Age));   // => "Age"

参照先の記事にあるように、文字列を指定してリフレクションをしていたコードが安全に記述できるようになります。

「これって Scala のマクロ使えば似たようなことができるんじゃ?」と思ったので、実験してみました。

目標

インスタンスのメンバー名を取れるよりは、型を指定してそのメンバーを取れる方がいいなと思ったので、以下のコードでメンバー名を取得できることを目標にしました。

// こんなクラスがあって
case class Person(name: String, age: Int)


// こんな定義で
def nameOf[A](f: A => Any): String = macro...


// こんなことができる
nameOf[Person](_.name)  // => "name"

コード

注)Scala のマクロを書くのはほぼ初めてです。実験ですのでエラーハンドリング等はちゃんとやってません。

あまり説明もできませんので、コードを張って終わりにしたいと思います・・・。

nameOf macro

まとめ

マクロの勉強不足なのでうまくかけていないところもありますが、とりあえず取得できるということが分かりました。 実用的に使えるようにしたいところです。

ScalaでC#のasync, awaitを実現するライブラリ「async」の紹介

この記事は Iwate Advent Calendar 2014 の22日目の記事です。昨日はnana4gontaさんのFirefox Developer Editionを使って他ブラウザをリモートデバッグする - Qiitaでした。明日はayokuraさんです。

岩手関連の記事を書こうと思い、仕事で使おうとしてるD3.jsを使って岩手県を書こうとしたらズバリそのままのサイトを発見して挫折しました。

岩手県ぬりえ
http://acuerdo.m18u.net/iwate_nurie/

結局思いつかなかったので全然関係ない話題を書きます。

続きを読む

型パラメータ付きメソッドを持つトレイトとコンパニオンオブジェクト

タイトルはなんだか難しいですが、要は以下のコードのコンパイルを通したいということです。

trait Test {
  def apply[A](value: A): String
}

object Test {
  def apply[A](f: A => String): Test = new Test {
    def apply[A](value: A): String = f(value)
  }
}

上記のソースだと、Testオブジェクト#applyの型パラメータAとTestトレイト#applyの型パラメータが別々のものなので、コンパイルが通りません。

error: type mismatch;
found   : value.type (with underlying type A)
required: A
        def apply[A](value: A): String = f(value)
                                           ^

どうにかする方法はないでしょうか・・。

Play2.3でSecureSocialを使う(2014年6月時点)

※(2014年6月27日)この情報はすでに古く、Play2.3に対応した公式モジュールがリリースされている可能性があります。公式サイトやリポジトリをご確認ください。

PlayFrameworkに認証/認可機能を追加できるSecureSocialというモジュールがあります。

SecureSocialの特徴は以下のとおりで、必要とされている機能はひと通り用意されており、認証機能を手軽に構築できるモジュールです。(ほぼ上記ページの内容ですが。)

  • ScalaだけでなくJavaでも使える。
  • Play2だけでなくPlay1でも使える。
  • ユーザ/パスワード認証だけでなく、OAuth1,2やOpenIDにも対応。また、TwitterFacebookなど向けのモジュールも用意されている。
  • 既存アプリへの組込みも簡単。
  • 拡張性があり、新たな認証にも対応できる。
  • ユーザ登録時やパスワードリセット時などにメールを送信する機能が使える。

さて、このモジュールですが残念ながら現在(2014/06/27)時点でPlay2.3向けのモジュールが提供されていません。 現在の状況としては、PRは投げられていますがメイン開発者が他の機能に注力しているため、レビュー・取り込みされていません。

ですが、PR元のプロジェクトをsbtで参照することで、Play2.3に対応したSecureSocialが使えますので、今回はその手順をまとめてみました。

  1. Playプロジェクトを作成する
  2. Play2.3対応版SecureSocialをプロジェクト参照する

1. Playプロジェクトを作成する

まずは、空のプロジェクトを作成してきます。Play2.3からはplayコマンドではなく、Typesafe Activatorを利用してプロジェクトを作成するように変更されていますのでご注意ください。 今回は、play23-securesocialというプロジェクト名でplay-scalaというテンプレートを利用して作成します。

> activator new play23-securesocial play-scala

Typesafe Activatorとは?

Typesafe Activatorとは、Scalaプロジェクトをあらかじめ用意されたひな形を利用して作成できるツールです。実際には、Webからソースコードを編集するUIなども用意されているようですが、ここでは説明しません。

Typesafe Activatorをインストールしていない方は、公式サイトZIPファイルをダウンロードし、任意の場所に展開します。 その後、実行ファイルにPATHを通せばactivatorコマンドが利用できるようになります。

Typesafe Activatorをインストールしたくない!

Typesafe Activatorをインストールしたくない方は、@xuwei_kさんがズバリのブログ記事を公開していますので、そちらを参考にしましょう。

ただし、この記事ではTypesafe Activatorを利用して作成したプロジェクトを元に話を進めます。build.sbtの中身がTypesafe Activatorを利用した場合と@xuwei_kさんの記事とで若干異なりますのでご注意ください。

2. Play2.3対応版SecureSocialをプロジェクト参照する

プロジェクトが作成できましたので、Play2.3に対応したSecureSocialを参照するように設定します。

といっても、冒頭に記載したとおりPlay2.3に対応したモジュールはまだリリースされていませんので、libraryDependenciesでは参照できません。そのため、GitHubリポジトリを直接参照するように、build.sbtを書いていきます。

//build.sbtの一部
lazy val root = (project in file(".")).enablePlugins(PlayScala)
  .dependsOn(ProjectRef(uri("https://github.com/ewiner/securesocial.git#play-2.3"), "mainModule"))

dependsOn以降を追加することにより、uriで指定した、Play2.3対応SecureSocialのGitプロジェクトが参照されます。

まとめ

Play2.3対応のSecureSocialについて調査していたところ、上記の方法で使えるという情報があったのでまとめてみました。 それより、sbtにGitプロジェクトを直接参照する機能があることを知らず感動しました。知らないことはまだまだいっぱいありますね・・。

認証/認可に必要な機能はひと通り揃っているモジュールですので、興味のある方はSecureSocialを使ってみてください。

FluentdのWindowsブランチに対してテストを流してみた

Rubyはほとんど触ったことありません。

FluentdのWindowsブランチに結構手が入ってるようでしたので、テストを流してみました。

結果はこちら。

FluentdをWindows環境でテストしてみた。

実行環境

2013-12-19現在のWindowsブランチのHEADに対してテストを実施しました。

  • OS: Windows 8 x64
  • Ruby: ruby 1.9.3p362 (2012-12-25) [i386-mingw32]
  • Bundler: Bundler version 1.2.3
  • Rake: rake, version 10.1.0

実行方法

何も考えずにbundle exec rake testを実行すると、すぐエラーが発生してしまうので、以下のバッチファイルを作成して1ファイルずつテストを流しました。

@echo off

@call bundle install

for %%f in ("test\*.rb") do (
  echo [Test start: %%f]
  @call bundle exec rake --trace test TEST='"%%f"' >test_log\%%f.log 2>&1
)

for %%f in ("test\plugin\*.rb") do (
  echo [Test start: %%f]
  @call bundle exec rake --trace test TEST='"%%f"' >test_log\%%f.log 2>&1
)

pause
exit /b 0

結果

プラグインで結構失敗が多いですね。中にはRuby側?なのか、[BUG] win32_mutex_lock: WAIT_ABANDONEDと出力されていました。

in_tail.rbのテストで発生したエラーを追いかけてみると、shutdownメソッドの@thread.joinを実行した際に上記のエラーが発生していました。Cool.io絡みなのかとおもいつつ、それを使っているプラグインにはテストが成功しているものもあるので、一概には言えない感じですね・・。Unixにひもづく処理だったり、ファイルを扱う処理なのでしょうか。

あと、そのままテストを流すと、おそらく$platformwinがうまく設定されていない感じだったので、それも原因の一つかもしれないです。Issueに、Windows版の場合はソースを分けるというものが上がっていたので、その対応次第では通るテストも増えるかもしれません。

まとめ

やはりWindows対応は大変そうだなーという印象でした。もう少しRuby力をあげて、直せそうなところから手をつけていきたいです。