• tracプロジェクト全域で認証

    前回のパッチで、「tracdによるtracプロジェクトをhttpsでapacheの認証下(basic/digest以外)で公開する。そしてapacheで認証したユーザでtracにログインする」というところまで出来た。
    tracプロジェクトでanonymousを許す場合、apacheの認証を「/login」にだけに設定しておけばよい。だけど、自分の環境では「tracプロジェクト全域」に認証をかけているため、事実上anonymousを利用することはない。したがって、一度認証を通過しているにも関わらずいちいち「ログイン」を選択しないとログイン状態にできないのは面倒だ(特に、チケットの発行や「私のチケット」を見るとき)

    ということで、tracプロジェクト全域を認証して使う場合に、いちいち"ログイン"を選ばなくてもいいようにする。
    ちなみに、権限をdropしてanonymousで利用できなくする、というのとは目的が違うので注意。

    1. 以下のパッチをあてる。
      --- trac-0.9.5-ja-1/trac/web/auth.py 2006-01-09 16:48:09.000000000 +0900
      +++ trac-0.9.5-ja-1kai/trac/web/auth.py 2006-06-18 01:54:37.000000000 +0900
      @@ -64,7 +64,8 @@
           def get_navigation_items(self, req):
               if req.authname and req.authname != 'anonymous':
                   yield ('metanav', 'login', '%s としてログイン中' % req.authname)
      -            yield ('metanav', 'logout',
      +            if not self.config.getbool('trac' , 'must_login'):
      +                yield ('metanav', 'logout',
                          Markup('<a href="%s">ログアウト</a>' 
                                 % escape(self.env.href.logout())))
               else:
      url: archives/2006/06/trac-2.html --- trac-0.9.5-ja-1/trac/web/standalone.py 2006-01-09 16:48:09.000000000 +0900
      +++ trac-0.9.5-ja-1kai/trac/web/standalone.py 2006-06-18 01:16:14.000000000 +0900
      @@ -288,7 +288,8 @@
                   return
       
               req.remote_user = None
      -        if path_info == '/login':
      +        if path_info == '/login' or \
      +           env.config.getbool('trac' , 'must_login') :
                   auth = self.server.auths.get(project_name) or \
                          self.server.auths.get('*')
                   if not auth:
      常にログインした状態で利用させるのでログアウトは選択できないようにした(選択しても、またログイン状態になるので意味がない)
    2. trac.iniの[trac]セクションに設定を追加する。
      [trac]
       :
      must_login = true
  • tracを使う

    「subversionのリポジトリブラウザとBTSとWikiが一緒になった」というtracを使ってみる。というか以前から使っていたのだが環境の問題かあちこちいじらないと動かなかったのでメモ。

    当初はmod_pythonを用いようとしたのだが、Segmentation FaultまたはAbortでapacheが死んでしまった。以下の要求を満たす形で構築したい、ので試行錯誤した。

    • ブラウザだけ用意できればアクセスできるようにしたい。httpsでアクセスしたい。
    • 外から見た場合に、https://xxxx.exmple.com:2222/のようなポート番号指定のURLではなくhttps://xxxx.example.com/project/のように表現したい。→穴を開けるポートを増やしたくない。
      • ウチではサーバにlinuxを使っている。外部公開しているポイントの穴を増やすことも避けたいが、iptablesによる許可ポートもできるだけ増やしたくない。
    • 認証はapacheの機能で行いたい。
      • これは「セキュリティはインフラサイドで確保するもの」という自身のポリシーもあるけど、Active DirectoryでSubversionのリポジトリとtracの認証を共通化したかった+apacheの認証モジュールの多さと設定の柔軟さを活かしたいから、という理由
    • 外部からはhttpsで接続したい
      • プライベートなプロジェクトを管理したいから。
    • CGI型はかなりレスポンスが遅くなるので採用しない。
      • なのでmod_pythonを選択したいところだが、apacheが死んでしまう問題を解決できなかったのでスタンドアロン型を選んだ。
      • また、スタンドアロン型といっても管理するアクセスログが増えるのはイヤで、apacheのログとひっくるめて管理できるようにしたい。
    で、
    • フロントエンドはapacheで、認証もここで行う。ついでにSSLも可に。
    • 内部でtracdを動かし、apache→tracd間はmod_proxyでリバースプロクシでつなぐ
    という方向に決めた。
    tracenv

    導入

    • trac本家はここ(http://www.edgewall.com/trac/)だが、日本語化したものをインタアクト株式会社が公開しているのでありがたく使わせてもらう。
    • ClearSilver、SQLite、パイソンバインディングなどもろもろ用意せねばならんのだが、このあたりは既に詳しいページが多数あるので割愛。

    設定

    • SSLの設定はあちこちに情報があるので割愛。
    • tracの設定もあちこちに情報があるので割愛。ただ、今回想定している環境は「外向きにはhttps」なので、デフォルトのままだとtracdが返す情報(特にLocationヘッダ)でhttpスキームを使われてしまうのでbase_urlを指定した。
      (projectenv)/conf/trac.ini

      [trac]
      base_url = https://外向け/trac
    • リバースプロクシは以下のような感じ。(Location内にリバースプロクシ設定を書いているので、パラメータが略されている点に注意)
      <Location /trac>
      ProxyPass http://tracdのIP:tracdのポート/trac
      ProxyPassReverse http://tracdのIP:tracdのポート/trac
      </Location>
    • 認証の設定もあちこちに情報があるので割愛。ふつーにtracのURL範囲を認証要に設定すればよい。BasicでもKerberosでも任意選択できる。
    • ここまででhttps://外向け/trac/へのアクセスがapacheにより認証されたうえで、内部で動作しているtracdにプロクシされるはず。ウチの環境の場合、内部は内部ネットワーク向けのDNSを動かしていて、外向けのFQDNと内部ホストのFQDNを同じにしているので(IPは異なる)、これが異なる場合はcookie関係の設定が必要かも。

    tracユーザの識別問題

    • trac上のユーザ識別も必要だ。なぜならチケットの発行やマイルストーンの編集などの権限判断は「trac上のユーザ」で行われるから。したがってapacheで認証したユーザをなんとかしてtracdにも認識させたい。tracdで使う認証がBasicまたはDigestであれば、apacheとtracdの間で認証データベースを共有することで解決できる。しかし今回のように「BasicでもDigestでもなくKerberosが使いたい」「mod_proxyを介している」という条件が加わると、tracdの認証オプションだけは解決できないようだ。
    • で、「apacheで認証したリクエストだけがtracdに到達する」という状況から「tracdへのアクセスは認証済み」と考える。Authorizationフィールドからユーザ名を抜き出してtracユーザとして使用することにする。
    • 下のようなパッチをあてて、tracdのコマンドラインオプションと「認証しない認証クラス」を捏造する。
      --- trac-0.9.5-ja-1/scripts/tracd   2005-12-02 10:10:17.000000000 +0900
      +++ trac-0.9.5-ja-1kai/scripts/tracd    2006-06-04 20:38:59.000000000 +0900
      @@ -16,6 +16,7 @@
       # Author: Jonas Borgstr 

       from trac.web.standalone import BasicAuth, DigestAuth, TracHTTPServer
      +from trac.web.TrustedAuth import *

       import getopt
       import locale
      @@ -56,6 +57,7 @@
           try:
               opts, args = getopt.getopt(sys.argv[1:], "a:p:b:de:",
                                          ["auth=", "port=", "hostname=","daemonize",
      +                                   "trusted-auth=",
                                           "env-parent-dir=", "basic-auth="])
           except getopt.GetoptError, e:
               print e
      @@ -66,6 +68,8 @@
                   add_auth(auths, a, DigestAuth)
               if o == '--basic-auth':
                   add_auth(auths, a, BasicAuth)
      +        if o == '--trusted-auth':
      +            add_auth(auths, a, TrustedAuth)
               if o in ("-p", "--port"):
                   port = int(a)
               elif o in ("-b", "--hostname"):
      url: archives/2006/06/trac.html --- trac-0.9.5-ja-1/trac/web/TrustedAuth.py 1970-01-01 09:00:00.000000000 +0900
      +++ trac-0.9.5-ja-1kai/trac/web/TrustedAuth.py  2006-06-04 20:40:22.000000000 +0900
      @@ -0,0 +1,67 @@
      +# -*- coding: utf-8 -*-
      +#
      +# This is adhoc auth?-module under tracd.
      +#
      +# If you are using tracd and external proxy(ex. mod_proxy) with some auth
      +#   method, the access for tracd is already authorized.
      +#
      +# TrustedAuth regard the user as already trusted.
      +# The user extraced from Authorization field.
      +#
      +# Author: tckz<tckz@nifty.com>
      +#
      +
      +from trac import util, __version__
      +from trac.web.api import Request
      +from trac.web.cgi_frontend import TracFieldStorage
      +
      +import urllib2
      +
      +try:
      +    from base64 import b64decode
      +except ImportError:
      +    from base64 import decodestring as b64decode
      +
      +
      +class TrustedAuth:
      +    def __init__(self, dummy, realm):
      +        self.realm = realm
      +
      +    def send_auth_request(self, req):
      +        req.send_response(401)
      +        req.end_headers()
      +
      +    def parse_auth_header(self, authorization):
      +        values = {}
      +        for value in urllib2.parse_http_list(authorization):
      +            n, v = value.split('=', 1)
      +            if v[0] == '"' and v[-1] == '"':
      +                values[n] = v[1:-1]
      +            else:
      +                values[n] = v
      +        return values
      +
      +    def do_auth(self, req):
      +        if not 'Authorization' in req.headers:
      +            self.send_auth_request(req)
      +            return None
      +
      +        user = ""
      +        if req.headers['Authorization'].startswith('Basic'):
      +            auth = req.headers['Authorization'][len('Basic')+1:]
      +            auth = b64decode(auth).split(':')
      +            if len(auth) == 2:
      +                user, password = auth
      +        elif req.headers['Authorization'].startswith('Digest'):
      +            auth = self.parse_auth_header(req.headers['Authorization'][7:])
      +            if auth.has_key('username'):
      +                user = auth['username']
      +        else:
      +            self.send_auth_request(req)
      +
      +        if user == "":
      +            self.send_auth_request(req)
      +            return None
      +
      +        return user
      +
    • tracd起動時のコマンドラインは↓のような感じで。--trusted-authの引数にカンマ区切りの3要素を指定しなければならないのは、元々tracdのadd_authメソッドに手を入れていないから。「*」部分はtracプロジェクト名。「*」にすると全部のプロジェクトが対象となる(元々の仕様)
      /usr/bin/tracd --trusted-auth '*,,' -p ポート -b localhostとか -d -e parent-dir-of-envs
    ちなみにCGI型の場合、apacheで認証したユーザすなわちREMOTE_USERがtracユーザとして扱われるようで特別なことはなにも必要ない。(だけど遅い、と)

    python触るのは初めてなのでもっといい書き方を教えて欲しいところだが、あんましpython好きくないかも。「元々のソースに存在するブロックに対応して追加したelseブロックがautoindentでHTが使われたために対応するブロックとして認識されずsyntax error」というのは好きになれそうもない。でもgeekには人気があるっていうよね。

  • 縦に長いページをキャプチャ キャプブラ .NET 2.0

    キャプブラアイコン キャプブラ(Windowsインストーラ形式:約400KB)
    • 画面をはみ出る大きなページ、縦長ページを一枚のスクリーンショットにキャプチャ。
    • PNG/JPEG/ビットマップで出力
    • IEコンポーネントを使っているので、レンダリングはIEと同じ
    こういうものです。
    • 「戻るボタン」も「ツールバー」もない(笑)
    • 進む、戻るはそれぞれ「ALT+→」「ALT+←」でしのぐ。
    • フリーソフト。無料、無償、無保証。
    • .NET Framework 2.0必須。開発環境をVS2005に変えただけ。なぜかセットアップのサイズが大幅に減少(約2MB→約400KB)
    • NOD32-パターン1.1551(20060521)でチェック済み
    キャプブラ画面キャプチャ例
  • IISで「.exe」を要求すると404

    Virtual Server 2005 R2をインストールした。
    管理ツールがwebアプリのためブラウザから指定URL(http://ホスト名/VirtualServer/VSWebApp.exe?view=1)にアクセスするが404。
    IISの管理コンソールから仮想ディレクトリを見ても問題がない。

    IIS Lockdown Tool(URLScan)を導入している場合、(導入時の選択次第だとは思うが)デフォルトでexeやdllへの参照が404になる。

    URLScanを外すか、urlscan.iniで許可してしまう。
    C:\WINDOWS\system32\inetsrv\urlscan\urlscan.ini
    ※パスは環境により色々。

    ざっと見た感じ、拡張子単位で許可/不許可を設定できるだけで、サイト単位/仮想ディレクトリ単位での制御は不可能の様子。結局URLScan的にはexeをスルーした上で、仮想ディレクトリ単位で「実行アクセス権」を設定してあげねばならんということか。
  • PostgreSQLにWindowsからODBCで接続する

    linux上で動いているPostgreSQLサーバにWindowsからODBC経由でアクセスする。
    本家でODBCドライバが提供されているのでこれを導入すればOK

    導入

    • PostgreSQL: FTP Browser(Top → odbc → versions → msi)からアーカイブをダウンロードする。今回使ったのは、psqlodbc-08_01_0200.zip
    • ダウンロードしたアーカイブを適当な場所において展開。中身はセットアップ(msi)なので、いつものようにセットアップ。インストール先など適宜選択。

    データソース設定

    • (XP Proの場合)コントロールパネル→管理ツール→データソース(ODBC)
    • 登録先がいくつかあるが、今回は「ユーザDSN」を選択。「システムDSN」を選択すれば他のユーザからも使える。
    • 「ユーザDSN」タブを選択して、「追加ボタン」。ODBCドライバのリストから「PostgreSQL Unicode」を選択。
      ドライバ選択
    • データソース名もろもろを設定。データソース名はいずれ接続文字列として選択するのでわかりやすい名称に。
      データソース設定
    • navicatなどのツールだと接続設定のダイアログから抜けないで接続確認ができるのだが、ODBCデータソースの設定からは出来ず。不便だ。

    接続確認

    • ExcelかAccessがあれば、簡単にODBCデータソースに接続してアクセスできるかどうか確認できる。ここではAccessを使った。
    • Accessを起動して適当な空のデータベースを作る。で、テーブルの新規作成→テーブルのリンク。ファイルの種類で「ODBCデータベース」を選ぶ。
    • データソース選択のダイアログを現れるので、先に登録したデータソースを選ぶ。(ここで「新規作成」してもいいようだ)
      データソース選択
    • PostgreSQLテーブルの一覧からリンクを作成したいテーブルを選ぶ。
    • テーブル一覧に新たなテーブルリンクアイコンが表示されるので、適宜中身をいじくる。