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