Kerberosを使ったsingle sign onで mod_auth_kerbを使って認証する方法について説明しました。 ここでは、Apacheで認証したuserをRuby on Railsで取得してみます。
Apacheのhttpd.confに以下のような記述をしてあるとします。
... <Location "/myapp/"> require valid-user AuthName "My Application Login" AuthType Kerberos KrbMethodNegotiate on KrbAuthRealms WORK.HANABUSA.NET Krb5Keytab /etc/httpd/httpd.keytab ProxyRequests Off ProxyPreserveHost On ProxyPass http://localhost:3000/myapp ProxyPassReverse http://localhost:3000/myapp RequestHeader set X-Forwarded-User %{REMOTE_USER}s RequestHeader set X-Forwarded-SSL on </Location>
TCP 3000番で走っているapplication serverには、 X-Forwarded-UserというHTTP header経由でuser情報が渡されます。 Railsではrequest objectからHTTP headerを取得できるため、以下のような Ruby codeで認証情報を取得できます。
remote_user = request.headers['X-Forwarded-User']
mod_auth_kerbで認証すると account@domain という形式で user が渡されます。 これをLDAPの domain component と account に変換して、LDAPからuser情報を取得してみます。 LDAPから情報を取得するには、Rubyのnet-ldapを使います。
$ gem install net-ldap
でinstallできます。 Active Directoryであれば、accountがLDAPのsAMAccountNameと、 domainがLDAPのDCとそれぞれ対応しますので、以下のようなRuby codeで Kerberos の user principal name から LDAP の情報を引くことができます。
require 'net/ldap' def get_user_info result = [ nil, nil, nil ] upn = request.headers['X-Forwarded-User'] if upn then basedn, account = upn2ldap(upn) ldap = Net::LDAP.new( :host=>'localhost', :port=>389 ) filter = Net::LDAP::Filter.eq('sAMAccountName', account) attrs = [ :cn, :mail ] ldap.search( :base=>basedn, :filter=>filter, :attributes=>attrs) { |entry| result = [ account, entry[:cn][0], entry[:mail][0] ] } end result end # # '[email protected]' to # 'DC=WORK,DC=HANABUSA,DC=NET', 'myuser' # def upn2ldap(upn) account, domain = upn.split('@', 2) if domain then # 'WORK.HANABUSA.NET' => 'DC=WORK,DC=HANABUSA,DC=NET' dcs = domain.split('.') dcs.map! { |dc| 'DC='+dc } dn = dcs.join(',') else dn = nil end # returns dn and account [ dn, account ] end