SPNEGO
ちょっと時間がなくなってきたので,自分用メモメモ。
SPNEGO 認証にまつわる RFC
SPNEGO 認証 / Kerberos について
SPNEGO 認証を行うのなら,mod_auth_ntlm_winbind を使わなくても mod_spnego というものがある。ただし,NTLM 認証や Basic 認証に fallback できない,と思われる。
mod_spnego の設定方法については juk(くわむら じゅん)さんの【http://www.linet.gr.jp/~juk/puki/?%5B%5BApache2-SPNEGO%5D%5D】が詳しい。Kerberos keytab を使う方法なんだけど,ActiveDirectory で keytab をマネージメントする方法についてはやはり同じ著者による【SPNEGO Setup with Active Directory】が詳しい。残念ながら文字化けが多々発生してるのと画像がないのでよくわからない。
他 Kerberos についてはやはり juk さんによるページが日本語でかつまとまっている。
後者はおもに Kerberos 4 についての話だけど,歴史から仕組みまで網羅してある。暇ができたら前者も全部読みたい。
IE 6 が SPNEGO(Negotiate)認証する時のシーケンス
キャプチャして調べた。ActiveDirectory にログイン済で,初めてサーバにアクセスする際。
- Server => Client: 401 / WWW-Authenticate: Negotiate
- Client => KDC(AS): want TGT(Realm: DOMAIN, Sname: krbtgt/DOMAIN)
- KDC(AS) => Client: return TGT(Realm: DOMAIN.FQDN Sname: krbtgt/DOMAIN.FQDN)
- Client => KDC(TGS): want Ticket(Realm: DOMAIN.FQDN Sname: HTTP/ServerName)
- KDC(TGS) => Client: return Ticket(Cname: UserName)
- Client => Server: Authenticate: Negotiate Ticket
すでに KDC とやりとりして TGT or Ticket を持っていれば 2〜5 は行われない。確かに RFC 4459 の通り。
ほんとはこの後 Server が Ticket の内容を確認して 200 OK になるはずなんだけど,今のところうまくできてない。
mod_auth_ntlm_winbind
Ticket は Apache → mod_auth_ntlm_winbind → ntlm_auth の順に流される。
ntlm_auth の処理の流れ。
- util/ntlm_auth.c::manage_gss_spnego_request()
- libads/kerberos_verify.c::ads_verify_ticket()
- libads/kerberos_verify.c::ads_secrets_verify_ticket()
- libads/kerberos_verify.c::ads_verify_ticket()
smb_conf で use kerberos keytab = True の場合,ads_secrets_verify_ticket() の代わりに ads_keytab_verify_ticket() を使う。この場合,前述の mod_spnego のように KDC で keytab を作ってウェブサーバにもってこないといけない。試していない。
libads/kerberos_verify.c::ads_secrets_verify_ticket() の流れ。
- got mutex for replay cache
- libsmb/clikrb5.c::create_kerberos_key_from_string(context, host principal(ServerName$), secrets_fetch_machine_password(DOMAIN), key, enctype)
- krb5_auth_con_setuseruserkey(context, auth_context, key)
- krb5_rd_req(context, auth_context)
- release mutex for replay cache
実際には様々な方式で ticket は暗号化されている。libads/kerberos_verify.c では des-cbc-crc, des-cbc-md5, rc4-hmac について2〜4を試みる。
今のところ,この3つの暗号化方式で krb5_rd_req() が Invalid message type となってしまい,結局 not authorized になってしまう。
ntlm_auth を手で立ち上げてためす
念のために root で作業すること。kdestroy で全チケットを破棄しておく。同じサーバで端末を 2 つ開く。
- Server 側端末で「ntlm_auth --helper-protocol=gss-spnego --domain=DOMAIN.FQDN」を入力。
- Client 側端末で「ntlm_auth --helper-protocol=gss-spnego-client --domain=DOMAIN.FQDN --username=UserName --password=Password」を入力
- Server 側に「YR」と入力
- Server が「TT HOGEHOGE...」と出力するのでコピペして Client 側に入力
- Client が「KK HUGAHUGA...」と出力する(NTLMSSP よりめっちゃ長い)のでコピペして Server 側に入力
- うまくいくと Server が「AF HOGEHOGE... DOMAIN.FQDN\UserName」を返す
- ちなみにこれを Client に入力すると「AF」とだけ返す
- 認証完了〜
SPNEGO のシーケンスと違うけど。好意的に解釈すると 1〜2 は KDC と Client のやりとりを代行してる?
なお klist すると「krbtgt/DOMAIN.FQDN」と「ServerName$@DOMAIN.FQDN」というプリンシパルのチケットが発行されている。これは Server ではなく Client が要求したチケットだと思われる。
感想
keytab 使わないとうまくいかないのかなぁ〜