Excerpt |
---|
This HOWTO describes how to set up CAS to authenticate to LDAP using the GSSAPI mechanism with a Kerberos 5 backend. |
Environment:
Server: Fedora Core 6 + CAS 3.1 + Tomcat 5.5.20 + OpenLDAP 2.3.30 + Cyrus SASL 2.1.22 + Kerboeros 1.5-23
Client: Fedora Core 6 + Firefox 2
Windows XP + IE6 SP2
Config DNS:
To make SSL and Kerberos work, I have to config DNS at the very beginning.
1. Edit /etc/named.conf, add langhua zone:
Code Block | ||||
---|---|---|---|---|
| ||||
zone "1.168.192.IN-ADDR.ARPA." IN { type master; file "192.168.1.db"; }; zone "langhua." IN { type master; file "named.langhua"; }; |
2. Create /var/named/named.langhua
Code Block | ||||
---|---|---|---|---|
| ||||
$TTL 1H @ SOA localhost. root.localhost. ( 2 3H 1H 1W 1H ) NS localhost. auth.langhua. IN 1H A 192.168.1.110 _kerberos IN TXT "AUTH.LANGHUA" _kerberos._udp.auth.langhua. IN SRV 0 0 88 auth.langhua. _kerberos-master._udp.auth.langhua. IN SRV 0 0 88 auth.langhua. _kerberos-adm._tcp.auth.langhua. IN SRV 0 0 749 auth.langhua. _kpasswd._udp.auth.langhua. IN SRV 0 0 464 auth.langhua. _ldap._tcp.auth.langhua. IN SRV 0 0 389 auth.langhua. _ldap._tcp.dc._msdcs.auth.langhua. IN SRV 0 0 389 auth.langhua. _kerberos._tcp.dc._msdcs.auth.langhua. IN SRV 0 0 88 auth.langhua. |
3. Create /var/name/192.168.1.db
Code Block | ||||
---|---|---|---|---|
| ||||
$TTL 1H @ SOA localhost. root.localhost. ( 2 3H 1H 1W 1H ) NS localhost. 110 PTR auth.langhua. |
4. nslookup auth.langhua
Server: 192.168.1.110
Address: 192.168.1.110#53
Name: auth.langhua
Address: 192.168.1.110
5. dig -x 192.168.1.110
; <<>> DiG 9.3.4-P1 <<>> -x 192.168.1.110
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3829
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; QUESTION SECTION:
;110.1.168.192.in-addr.arpa. IN PTR
;; ANSWER SECTION:
110.1.168.192.in-addr.arpa. 3600 IN PTR auth.langhua.
;; AUTHORITY SECTION:
1.168.192.in-addr.arpa. 3600 IN NS localhost.
;; ADDITIONAL SECTION:
localhost. 86400 IN A 127.0.0.1
localhost. 86400 IN AAAA ::1
;; Query time: 1 msec
;; SERVER: 192.168.1.110#53(192.168.1.110)
;; WHEN: Thu Nov 29 04:53:02 2007
;; MSG SIZE rcvd: 137
Config Kerberos:
1. Config /etc/krb5.conf
Code Block | ||||
---|---|---|---|---|
| ||||
[logging] default = FILE:/var/log/krb5libs.log kdc = FILE:/var/log/krb5kdc.log admin_server = FILE:/var/log/kadmind.log [libdefaults] default_realm = AUTH.LANGHUA dns_lookup_realm = false dns_lookup_kdc = false ticket_lifetime = 24h forwardable = true [realms] AUTH.LANGHUA = { kdc = auth.langhua:88 admin_server = auth.langhua:749 default_domain = langhua } [domain_realm] .langhua = AUTH.LANGHUA [kdc] profile = /var/kerberos/krb5kdc/kdc.conf [appdefaults] pam = { debug = false ticket_lifetime = 36000 renew_lifetime = 36000 forwardable = true krb4_convert = false } |
2. kdb5_util create -s
3. Add users to Kerberos
kadmin.local -q "addprinc krbadm@AUTH.LANGHUA"
kadmin.local -q "addprinc ldapadm@AUTH.LANGHUA"
kadmin.local -q "addprinc host/auth.langhua@AUTH.LANGHUA"
kadmin.local -q "addprinc ldap/auth.langhua@AUTH.LANGHUA"
If you face this error in this step, delete the files under /var/kerberos/krb5kdc/ and redo the above step 2 and 3:
kadmin.local: Cannot find/read stored master key while initializing kadmin.local interface
4. Edit /var/kerberos/krb5kdc/kdc.conf
This file is configed in /etc/krb5.conf.
Code Block | ||||
---|---|---|---|---|
| ||||
[kdcdefaults] acl_file = /var/kerberos/krb5kdc/kadm5.acl dict_file = /usr/share/dict/words admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab v4_mode = nopreauth [realms] AUTH.LANGHUA = { master_key_type = des3-hmac-sha1 supported_enctypes = des3-hmac-sha1:normal des-cbc-crc:normal } |
5. Edit /var/kerberos/krb5kdc/kadm5.acl
This file is configed in /var/kerberos/krb5kdc/kdc.conf.
Code Block | ||||
---|---|---|---|---|
| ||||
kadmin/admin@AUTH.LANGHUA * ldap/auth.langhua@AUTH.LANGHUA * krbadm@AUTH.LANGHUA * */*@AUTH.LANGHUA i host/auth.langhua@AUTH.LANGHUA * |
6. Config /var/kerberos/krb5kdc/kadm5.keytab
This file is configed in /var/kerberos/krb5kdc/kdc.conf.
kadmin.local -q "ktadd -k /var/kerberos/krb5kdc/kadm5.keytab kadmin/admin"
kadmin.local -q "ktadd -k /var/kerberos/krb5kdc/kadm5.keytab kadmin/changepw"
7. Edit /etc/krb.realms
Code Block | ||||
---|---|---|---|---|
| ||||
auth.langhua AUTH.LANGHUA .langhua AUTH.LANGHUA |
8. Edit /etc/krb.conf
Code Block | ||||
---|---|---|---|---|
| ||||
AUTH.LANGHUA AUTH.LANGHUA auth.langhua:88 AUTH.LANGHUA auth.langhua:749 admin server |
9. Start Kerberos
/etc/init.d/kadmin start
/etc/init.d/krb5kdc start
Test Kerberos
1. kadmin.local -q "ktadd -k /etc/krb5.keytab host/auth.langhua"
2. kinit -k host/auth.langhua
If the error "kinit(v5): Password incorrect while getting initial credentials" found, delete /etc/krb5.keytab, and redo step 1 and 2.
3. klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: host/auth.langhua@AUTH.LANGHUA
Valid starting Expires Service principal
11/29/07 02:44:44 11/30/07 02:44:44 krbtgt/AUTH.LANGHUA@AUTH.LANGHUA
Kerberos 4 ticket cache: /tmp/tkt0
klist: You have no tickets cached
4. Make sure kvno numbers are the same
4.1 kvno host/auth.langhua
host/auth.langhua@AUTH.LANGHUA: kvno = 5
4.2 klist -k /etc/krb5.keytab
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
--- -------------------------------------------------------------------
5 host/auth.langhua@AUTH.LANGHUA
5 host/auth.langhua@AUTH.LANGHUA
If the numbers are not same, redo step 1, 2, 3.
5. Test ktelnetd, krlogind, krshd
5.1 Edit ~/.k5login
host/auth.langhua@AUTH.LANGHUA
5.2 Start xinetd
chkconfig klogin on
chkconfig kshell on
chkconfig eklogin on
chkconfig krb5-telnet on
/etc/init.d/xinetd restart
5.3 krlogin auth.langhua -k AUTH.LANGHUA
This rlogin session is encrypting all data transmissions.
Last login: Thu Nov 29 04:46:08 from auth.langhua
You have new mail.
5.4 telnet -x 192.168.1.110 -k AUTH.LANGHUA
Trying 192.168.1.110...
Connected to auth.langhua (192.168.1.110).
Escape character is '^]'.
Waiting for encryption to be negotiated...
[ Kerberos V5 accepts you as ``host/auth.langhua@AUTH.LANGHUA'' ]
done.
Last login: Thu Nov 29 04:46:23 from auth.langhua
You have new mail.
5.5 rsh 192.168.1.110 -k AUTH.LANGHUA
Last login: Thu Nov 29 04:47:00 from auth.langhua
You have new mail.
Kerberos configuration is OK now.
Config Cyrus SASL GSSAPI
1. Add ldap service
1.1 kadmin.local -q "addprinc -randkey ldap/auth.langhua@AUTH.LANGHUA"
1.2 check /var/kerberos/krb5kdc/kadm5.acl has ldap service configed
1.3 kadmin.local -q "ktadd -k /etc/krb5.keytab ldap/auth.langhua"
2. Add a test user
2.1 kadmin.local -q "addprinc test@AUTH.LANGHUA"
2.2 kadmin.local -q "ktadd -k /etc/krb5.keytab test"
2.3 Edit ~/.k5login
test@AUTH.LANGHUA
3. Verify GSSAPI works on your system
3.1 sasl2-sample-server -s ldap -m GSSAPI
trying 10, 1, 6
trying 2, 1, 6
bind: Address already in use
3.2 sasl2-sample-client -s ldap -m GSSAPI auth.langhua
Code Block | ||||
---|---|---|---|---|
| ||||
receiving capability list... recv: {6} GSSAPI GSSAPI please enter an authorization id: test send: {6} GSSAPI send: {1} Y send: {525} `\[82\]\[2\]\[9\]\[6\]\[9\]*\[86\]H\[86\]\[F7\]\[12\]\[1\]\[2\]\[2\]\[1\]\[0\]n\[82\]\[1\]\[F8\]0\[82\]\[1\]\[F4\]\[A0\]\[3\]\[2\]\[1\]\[5\]\[A1\]\[3\]\[2\]\[1\]\[E\]\[A2\]\[7\]\[3\]\[5\]\[0\] \[0\]\[0\]\[0\]\[A3\]\[82\]\[1\]\[10\]a\[82\]\[1\]\[C\]0\[82\]\[1\]\[8\]\[A0\]\[3\]\[2\]\[1\]\[5\]\[A1\]\[E\]\[1B\]\[C\]AUTH.LANGHUA\[A2\]\[1F\]0\[1D\]\[A0\]\[3\]\[2\]\[1\]\[3\]\[A1\]\[16\]0\[14\]\[1B\]\[4\]ldap\[1B\]\[C\]auth.langhua\[A3\]\[81\]\[CF\]0\[81\]\[CC\]\[A0\]\[3\]\[2\]\[1\]\[10\]\[A1\]\[3\]\[2\]\[1\]\[4\]\[A2\]\[81\]\[BF\]\[4\]\[81\]\[BC\].\[A3\],FO\[CC\]\[12\]P* {r_l\[D5\]\[A1\]\[9F\]\[D9\]\[7F\]\[FF\]A2\[9C\]\[E1\]\[DB\]KZ%\[D9\]\[83\]\[AD\]\[C5\]j\[84\]\[87\]\[FD\]\[EB\]\[C9\]\]DGS\[8C\]%\[16\]\[7F\]&0\[BC\]r(\[BD\]\[11\]\[FF\]v\[EE\]V\[DD\]I\[EA\]E<\[B8\]\[B\]\[1D\]2\[D4\]>\[CB\]~1\[FB\]\[1\]fC\[1F\]5\[EA\]\[CD\]\[7\]\[E7\]\[DB\]\[B9\]\[B1\]\[14\]S\[95\]6?8Ea\[F5\]6\[8A\]\[BB\]\[8D\]V\[B9\]\[C1\]\[A5\]\[8\]\[C2\]LH,5\[1A\]\[BC\]"\[91\]v\[CC\]\[B2\]\[2\]QJd} *\[97\]V\[A9\]g\[B5\]\[F6\]\[D0\]\[C4\]\[C9\],\!\[DF\]\[F8\]\[8E\]\[A3\]\[16\]\[7\]\[E5\])N\[E6\]\[11\] \[8\]+\[85\]\[FD\]\[1B\]\[11\]\[C3\]\[96\]\[98\]\[80\]}g<\[A3\]5\[1E\]\[BC\]si\[8A\]c9\[8A\]\[1A\]w\[13\]\[1E\]\[18\]\[87\](\[98\]\[E5\]\[E7\]\[89\]\[85\]W\[AC\]s\[A5\]v\[D6\]5v\[80\]\[A3\]\[FA\]\[A4\]\[81\]\[CA\]0\[81\]\[C7\]\[A0\]\[3\]\[2\]\[1\]\[10\]\[A2\]\[81\]\[BF\]\[4\]\[81\]\[BC\]\[15\]>\[D6\]\[CB\]h\[1B\]\[9\]Y\[AC\]\[C8\]hh\[F1\]**_\[D4\]\[82\]GD\[FD\]4\[AA\]"$\[EC\]\[7F\]&\[B8\]\[F\]D\[7\]\[97\]\[82\]\[D\]\[A7\]\[D\]\[A2\]9\[8C\]\[88\]\[C0\]-\[DC\]\[E6\]\[A\]\[EB\]D6\[1F\]\[A4\]\[E2\]\[EE\]\[D1\]\[6\]x\[15\]\[D1\]\[EE\]4d\[86\]\[84\]\[99\]\[16\]\[AC\]\[F5\]C\[E8\]\[A9\]u#\[CE\]\[C5\]\[E1\]\[9B\]_*_\[E8\]\[B4\]\[93\]z\[E9\])\[15\]\[D\]L/E\[BD\]\[E6\]`\[1F\]_\[F2\]\[BC\]\[1A\]\[D7\]1\[BF\]\[C1\]\[2\]O\[8C\]\[1D\]\[A0\]\[C\]\[AB\]\[8B\]\[AB\]\[F5\]\[DB\]\[D4\]\[B1\]\[ED\]\[A\]\[AF\]\[9\]\[B\]s\[E9\]\[10\]\[FB\]u\[11\]\[E\]N\[1F\]*\[15\]\[AE\]h\[F5\]\[1C\]\[8E\]\[92\]\[AA\]6\|0\[F4\]\[FE\]\[CB\]\[9A\]\[9D\]c^o4\[CB\]\[8C\]\[B8\]\[99\]\[89\]\[A5\]\[18\]\[EA\]pE\[B1\]\[C7\]\[E8\]\[90\]\[82\]\[EE\]\[A6\](\[1A\]1Q\[D0\]\[81\]X\[C6\]q\[9B\]\[EA\]v\[C\]\[FA\]\[E9\]jd\[84\]\[BD\]\[CF\]\[90\]S\[8E\]P recv: {153} `\[81\]\[96\]\[6\]\[9\]*\[86\]H\[86\]\[F7\]\[12\]\[1\]\[2\]\[2\]\[2\]\[0\]o\[81\]\[86\]0\[81\]\[83\]\[A0\]\[3\]\[2\]\[1\]\[5\]\[A1\]\[3\]\[2\]\[1\]\[F\]\[A2\]w0u\[A0\]\[3\]\[2\]\[1\]\[10\]\[A2\]n\[4\]l\[5\],\[B7\]\[F6\]\[CD\]\[C\]\[BF\]\[1\]{*\[E0\]\[1F\]\[92\]\[FC\]\[10\]\[94\]U\[DF\]\[9E\]\[BA\]k_\[A4\]G&\[EC\]g:\[BA\]J\[C6\]\[C1\]sQ:'\[87\]/\[95\]\[C8\]W\[C5\]^47N\[9B\]im`\[BB\]\[B4\]\[C5\]\[EB\]\[BC\]w\[80\]\[A7\]\[1D\]Q\[89\]\[8B\]L\[8D\]N\[E7\]\[87\]\[C2\]\[EB\]\[D9\]k{j\[D\]\[AD\]\[A3\]w\[B1\]\[A2\]\[B3\]X\[FD\]"\[99\]LG\[88\]^\[DE\]\[CD\]\[ED\]\[AC\]\[F8\]\[10\](\[FA\]h\[2\]\[B7\]L\[E2\]K6\[2\]\[F5\]C\[91\]u send: {0} recv: {65} `?\[6\]\[9\]*\[86\]H\[86\]\[F7\]\[12\]\[1\]\[2\]\[2\]\[2\]\[1\]\[4\]\[0\]\[FF\]\[FF\]\[FF\]\[FF\]\[91\]w\[FA\]J\[96\]\[9D\]4\[8F\]Is\[90\]\[89\]\[F\]\[B2\]\[BC\]X\[2\].\[C\];\[89\]\[9A\]\[3\]\[F9\]\[CF\]DU\[BA\]\[98\]x#\[CF\]\[FF\]G\[9E\]:\[1\]\[0\]\[0\]\[0\]\[4\]\[4\]\[4\]\[4\] send: {73} `G\[6\]\[9\]*\[86\]H\[86\]\[F7\]\[12\]\[1\]\[2\]\[2\]\[2\]\[1\]\[4\]\[0\]\[FF\]\[FF\]\[FF\]\[FF\]\[CB\]\[9F\]K\[D1\]\[81\]m\[E4\]\[A2\]\[A6\]\[E2\]\[C\]\[7F\]a\[8C\]\[1B\]\[A5\]\[CC\]m\[E6\]\[BB\]\[E4\]\[A4\]\[9F\]s\[B5\]\[F8\]\[1F\]\[D1\]\[3\]}\[95\]\[F1\]\[5\]\[C2\]s\[16\]\[1\]\[0\]\[0\]\[0\]test\[8\]\[8\]\[8\]\[8\]\[8\]\[8\]\[8\]\[8\] successful authentication closing connection |
GSSAPI is OK now.
If the server and client can communicate but cannot authen successfully, perhaps it's caused by the driver of your ethernet card.
Config OpenLDAP GSSAPI
1. ldapsearch -Y GSSAPI -b 'o=langhua,c=cn' '(ou=worldwide)'
SASL/GSSAPI authentication started
SASL username: test@AUTH.LANGHUA
SASL SSF: 56
SASL installing layers
# extended LDIF
#
# LDAPv3
# base <o=langhua,c=cn> with scope subtree
# filter: (ou=worldwide)
# requesting: ALL
#
# worldwide, langhua, cn
dn: ou=worldwide,o=langhua,c=cn
objectClass: organizationalUnit
objectClass: top
ou: worldwide
# martin.peschke, worldwide, langhua, cn
dn: uid=martin.peschke,ou=worldwide,o=langhua,c=cn
uid: martin.peschke
ou: worldwide
objectClass: organizationalPerson
objectClass: uidObject
objectClass: person
objectClass: top
sn: Martin Peschke
cn: Martin Peschke
# search result
search: 4
result: 0 Success
# numResponses: 3
# numEntries: 2
2. Edit /etc/slapd.conf
Code Block | ||||
---|---|---|---|---|
| ||||
# # See slapd.conf(5) for details on configuration options. # This file should NOT be world readable. # include /etc/openldap/schema/core.schema include /etc/openldap/schema/cosine.schema include /etc/openldap/schema/inetorgperson.schema include /etc/openldap/schema/nis.schema include /etc/openldap/schema/krb5-kdc.schema # Allow LDAPv2 client connections. This is NOT the default. allow bind_v2 # Do not enable referrals until AFTER you have a working directory # service AND an understanding of referrals. #referral ldap://root.openldap.org pidfile /var/run/openldap/slapd.pid argsfile /var/run/openldap/slapd.args # Load dynamic backend modules: # modulepath /usr/lib/openldap # moduleload back_bdb.la # moduleload back_ldap.la # moduleload back_ldbm.la # moduleload back_passwd.la # moduleload back_shell.la # The next three lines allow use of TLS for encrypting connections using a # dummy test certificate which you can generate by changing to # /etc/pki/tls/certs, running "make slapd.pem", and fixing permissions on # slapd.pem so that the ldap user or group can read it. Your client software # may balk at self-signed certificates, however. # TLSCACertificateFile /etc/pki/tls/certs/ca-bundle.crt # TLSCertificateFile /etc/openldap/slapd.pem # TLSCertificateKeyFile /etc/pki/tls/certs/slapd.pem TLSCACertificateFile /etc/pki/demoCA/cacert.pem TLSCertificateFile /etc/pki/demoCA/certs/ldap-cert.pem TLSCertificateKeyFile /etc/pki/demoCA/certs/ldap-key.pem # TLSVerifyClient demand # Sample security restrictions # Require integrity protection (prevent hijacking) # Require 112-bit (3DES or better) encryption for updates # Require 63-bit encryption for simple bind # security ssf=1 update_ssf=112 simple_bind=64 # disallow bind_simple # Sample access control policy: # Root DSE: allow anyone to read it # Subschema (sub)entry DSE: allow anyone to read it # Other DSEs: # Allow self write access # Allow authenticated users read access # Allow anonymous users to authenticate # Directives needed to implement policy: # access to dn.base="" by * read # access to dn.base="cn=Subschema" by * read # # if no access controls are present, the default policy # allows anyone and everyone to read anything but restricts # updates to rootdn. (e.g., "access to * by * read") # # rootdn can always read and write EVERYTHING! # access to * by * read ####################################################################### # ldbm and/or bdb database definitions ####################################################################### database bdb suffix "o=langhua,c=cn" # rootdn "uid=root,o=langhua,c=cn" # Cleartext passwords, especially for the rootdn, should # be avoided. See slappasswd(8) and slapd.conf(5) for details. # Use of strong authentication encouraged. # rootpw {SSHA}mpfjTVX6cJ+oMgoB1wIjJ8HTR/2kyBga # The database directory MUST exist prior to running slapd AND # should only be accessible by the slapd and slap tools. # Mode 700 recommended. directory /var/lib/ldap # Indices to maintain for this database index objectClass eq,pres index ou,cn,mail,surname,givenname eq,pres,sub index uidNumber,gidNumber,loginShell eq,pres index uid,memberUid eq,pres,sub index nisMapName,nisMapEntry eq,pres,sub # Replicas of this database # replogfile /var/lib/ldap/openldap-master-replog # replica host=ldap-1.example.com:389 starttls=critical # bindmethod=sasl saslmech=GSSAPI # authcId=host/ldap-master.example.com@EXAMPLE.COM # authzTo: uid=[HOWTO Setup LDAP GSSAPI+Kerberos Authentication in CAS^,]*,o=langhua,c=cn sasl-realm AUTH.LANGHUA sasl-host auth.langhua access to attrs=userPassword by self write by dn="uid=test,cn=auth.langhua,cn=gssapi,cn=auth" write by anonymous auth by * none access to * by dn="uid=test,cn=auth.langhua,cn=gssapi,cn=auth" write by self write by * read |
3. /etc/init.d/ldap restart
4. Use JXplorer, select GSSAPI to login auth.langhua:389
If successful login, the OpenLDAP configuration is complete.
Config CAS
1. Create /cas-server-support-ldap/src/main/java/org/jasig/cas/adaptors/ldap/BindLdapGssapiAuthenticationHandler.java
Code Block | ||||
---|---|---|---|---|
| ||||
/* * Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license * distributed with this file and available online at * http://www.ja-sig.org/products/cas/overview/license/ */ package org.jasig.cas.adaptors.ldap; import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; import org.jasig.cas.authentication.handler.AuthenticationException; import org.jasig.cas.authentication.principal.UsernamePasswordCredentials; import org.jasig.cas.util.annotation.IsIn; /** * Handler to do LDAP GSSAPI bind. * * @author Scott Battaglia * @version $Revision: 42053 $ $Date: 2007-06-10 09:17:55 -0400 (Sun, 10 Jun 2007) $ * @since 3.0.3 * @author Shi Yusen, shiys@langhua.cn */ public class BindLdapGssapiAuthenticationHandler extends AbstractLdapGssapiAuthenticationHandler { /** The default maximum number of results to return. */ private static final int DEFAULT_MAX_NUMBER_OF_RESULTS = 1000; /** The default timeout. */ private static final int DEFAULT_TIMEOUT = 1000; /** The search base to find the user under. */ private String searchBase; /** The scope. */ @IsIn({SearchControls.OBJECT_SCOPE, SearchControls.ONELEVEL_SCOPE, SearchControls.SUBTREE_SCOPE}) private int scope = SearchControls.SUBTREE_SCOPE; /** The maximum number of results to return. */ private int maxNumberResults = DEFAULT_MAX_NUMBER_OF_RESULTS; /** The amount of time to wait. */ private int timeout = DEFAULT_TIMEOUT; /** Boolean of whether multiple accounts are allowed. */ private boolean allowMultipleAccounts; protected final boolean authenticateUsernamePasswordInternal( final UsernamePasswordCredentials credentials) throws AuthenticationException { DirContext context; context = this.getContextSource().getDirContext(credentials.getUsername(), credentials.getPassword()); if (context == null) { return false; } return true; } protected String composeCompleteDnToCheck(final String dn, final UsernamePasswordCredentials credentials) { return dn + "," + this.searchBase; } /** * Method to return whether multiple accounts are allowed. * @return true if multiple accounts are allowed, false otherwise. */ protected boolean isAllowMultipleAccounts() { return this.allowMultipleAccounts; } /** * Method to return the max number of results allowed. * @return the maximum number of results. */ protected int getMaxNumberResults() { return this.maxNumberResults; } /** * Method to return the scope. * @return the scope */ protected int getScope() { return this.scope; } /** * Method to return the search base. * @return the search base. */ protected String getSearchBase() { return this.searchBase; } /** * Method to return the timeout. * @return the timeout. */ protected int getTimeout() { return this.timeout; } public final void setScope(final int scope) { this.scope = scope; } /** * @param allowMultipleAccounts The allowMultipleAccounts to set. */ public void setAllowMultipleAccounts(final boolean allowMultipleAccounts) { this.allowMultipleAccounts = allowMultipleAccounts; } /** * @param maxNumberResults The maxNumberResults to set. */ public final void setMaxNumberResults(final int maxNumberResults) { this.maxNumberResults = maxNumberResults; } /** * @param searchBase The searchBase to set. */ public final void setSearchBase(final String searchBase) { this.searchBase = searchBase; } /** * @param timeout The timeout to set. */ public final void setTimeout(final int timeout) { this.timeout = timeout; } } |
2. Create /cas-server-support-ldap/src/main/java/org/jasig/cas/adaptors/ldap/AbstractLdapGssapiAuthenticationHandler.java
Code Block | ||||
---|---|---|---|---|
| ||||
/* * Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license * distributed with this file and available online at * http://www.ja-sig.org/products/cas/overview/license/ */ package org.jasig.cas.adaptors.ldap; import org.jasig.cas.adaptors.ldap.util.AuthenticatedLdapGssapiContextSource; import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler; import org.jasig.cas.util.annotation.NotNull; import org.springframework.beans.factory.InitializingBean; import org.springframework.ldap.LdapTemplate; import org.springframework.util.Assert; /** * Abstract class to handle common LDAP functionality. * * @author Scott Battaglia * @version $Revision: 42053 $ $Date: 2007-06-10 09:17:55 -0400 (Sun, 10 Jun 2007) $ * @since 3.0.3 * * @author Shi Yusen, shiys@langhua.cn */ public abstract class AbstractLdapGssapiAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler implements InitializingBean { /** LdapTemplate to execute ldap queries. */ @NotNull private LdapTemplate ldapTemplate; /** Instance of ContextSource */ @NotNull private AuthenticatedLdapGssapiContextSource contextSource; /** The filter path to the uid of the user. */ @NotNull private String filter; /** Whether the LdapTemplate should ignore partial results. */ private boolean ignorePartialResultException = false; /** * Method to set the datasource and generate a JdbcTemplate. * * @param dataSource the datasource to use. */ public final void setContextSource(final AuthenticatedLdapGssapiContextSource contextSource) { this.contextSource = contextSource; this.ldapTemplate = new LdapTemplate(contextSource); } public final void setIgnorePartialResultException(final boolean ignorePartialResultException) { this.ignorePartialResultException = ignorePartialResultException; } /** * Method to return the LdapTemplate * * @return a fully created LdapTemplate. */ protected final LdapTemplate getLdapTemplate() { return this.ldapTemplate; } protected final AuthenticatedLdapGssapiContextSource getContextSource() { return this.contextSource; } protected final String getFilter() { return this.filter; } public final void afterPropertiesSet() throws Exception { Assert.isTrue(this.filter.contains("%u"), "filter must contain %u"); this.ldapTemplate.setIgnorePartialResultException(this.ignorePartialResultException); } /** * @param filter The filter to set. */ public final void setFilter(final String filter) { this.filter = filter; } } |
3. Create /cas-server-support-ldap/src/main/java/org/jasig/cas/adaptors/ldap/util/AuthenticatedLdapGssapiContextSource.java
Code Block | ||||
---|---|---|---|---|
| ||||
/* * Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license * distributed with this file and available online at * http://www.ja-sig.org/products/cas/overview/license/ */ package org.jasig.cas.adaptors.ldap.util; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import javax.naming.Context; import javax.naming.directory.DirContext; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.ldap.support.LdapContextSource; import sun.security.krb5.Credentials; public class AuthenticatedLdapGssapiContextSource extends LdapContextSource { private DirContext context; public Hashtable<String, String> environment; public DirContext getDirContext(final String principal, final String credentials) { if (context == null) { environment = (Hashtable) getAnonymousEnv().clone(); Enumeration keys = environment.keys(); while (keys.hasMoreElements()) { String key = (String)keys.nextElement(); System.setProperty(key, environment.get(key)); } environment.put(Context.SECURITY_PRINCIPAL, principal); environment.put(Context.SECURITY_CREDENTIALS, credentials); LoginContext lc = null; try { lc = new LoginContext(AuthenticatedLdapGssapiContextSource.class.getName(), new UsernamePasswordCallbackHandler(principal, credentials)); lc.login(); } catch (LoginException ex) { ex.printStackTrace(); throw new DataAccessResourceFailureException("GSSAPI login problem: " + ex); } context = (DirContext) Subject.doAs(lc.getSubject(), new LDAPAction(environment)); if (context == null) { throw new DataAccessResourceFailureException("a problem with GSSAPI occurred - couldn't create a GSSAPI directory context"); } else { Iterator i = lc.getSubject().getPrivateCredentials().iterator(); while (i.hasNext()) { Credentials creds = (Credentials) i.next(); if (creds.isForwardable()) { return context; } } throw new DataAccessResourceFailureException("a problem with GSSAPI occurred - please make sure your Credentials is forwardable. Try to use \"kinit -f yourpricinpal\"."); } } else { return context; } } /** * A simple JAAS CallbackHandler which accepts a Name String and Password * String in the constructor. Only NameCallbacks and PasswordCallbacks are * accepted in the callback array. This code based loosely on example given * in Sun's javadoc for CallbackHandler interface. * * Copied from org.jasig.cas.authentication.handler.support.JaasAuthenticationHandler */ protected class UsernamePasswordCallbackHandler implements CallbackHandler { /** The username of the principal we are trying to authenticate. */ private final String userName; /** The password of the principal we are trying to authenticate. */ private final String password; /** * Constuctor accepts name and password to be used for authentication. * * @param userName name to be used for authentication * @param password Password to be used for authentication */ protected UsernamePasswordCallbackHandler(final String userName, final String password) { this.userName = userName; this.password = password; } public void handle(final Callback[] callbacks) throws UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { final Callback callback = callbacks[i]; if (callback.getClass().equals(NameCallback.class)) { ((NameCallback) callback).setName(this.userName); } else if (callback.getClass().equals(PasswordCallback.class)) { ((PasswordCallback) callback).setPassword(this.password .toCharArray()); } else { throw new UnsupportedCallbackException(callback, "Unrecognized Callback"); } } } } } |
4. Create /cas-server-support-ldap/src/main/java/org/jasig/cas/adaptors/ldap/util/LDAPAction.java
Code Block | ||||
---|---|---|---|---|
| ||||
/* * Copyright 2008 The JA-SIG Collaborative. All rights reserved. See license * distributed with this file and available online at * http://www.ja-sig.org/products/cas/overview/license/ */ package org.jasig.cas.adaptors.ldap.util; import java.security.PrivilegedAction; import java.util.Hashtable; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; /** * @author Shi Yusen * * Ref: http://forum.java.sun.com/thread.jspa?threadID=395518&messageID=2444444 */ public class LDAPAction implements PrivilegedAction { private Hashtable env; public LDAPAction(Hashtable env){ this.env = env; } /* (non-Javadoc) * @see java.security.PrivilegedAction#run() */ public Object run() { DirContext result = null; try{ result = new InitialDirContext(env); }catch(NamingException ex){ ex.printStackTrace(); } return result; } } |
5. build and deploy CAS 3.1
6. Create $CAS/WEB-INF/gssapi.conf
Code Block | ||||
---|---|---|---|---|
| ||||
org.jasig.cas.adaptors.ldap.util.AuthenticatedLdapGssapiContextSource { com.sun.security.auth.module.Krb5LoginModule required client=TRUE useTicketCache=TRUE; }; |
7. Edit $CAS/WEB-INF/deployerConfigContext.xml
Code Block | ||||
---|---|---|---|---|
| ||||
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <!-- | deployerConfigContext.xml centralizes into one file some of the declarative configuration that | all CAS deployers will need to modify. | | This file declares some of the Spring-managed JavaBeans that make up a CAS deployment. | The beans declared in this file are instantiated at context initialization time by the Spring | ContextLoaderListener declared in web.xml. It finds this file because this | file is among those declared in the context parameter "contextConfigLocation". | | By far the most common change you will need to make in this file is to change the last bean | declaration to replace the default SimpleTestUsernamePasswordAuthenticationHandler with | one implementing your approach for authenticating usernames and passwords. +--> <beans> <!-- | This bean declares our AuthenticationManager. The CentralAuthenticationService service bean | declared in applicationContext.xml picks up this AuthenticationManager by reference to its id, | "authenticationManager". Most deployers will be able to use the default AuthenticationManager | implementation and so do not need to change the class of this bean. We include the whole | AuthenticationManager here in the userConfigContext.xml so that you can see the things you will | need to change in context. +--> <bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl"> <!-- | This is the List of CredentialToPrincipalResolvers that identify what Principal is trying to authenticate. | The AuthenticationManagerImpl considers them in order, finding a CredentialToPrincipalResolver which | supports the presented credentials. | | AuthenticationManagerImpl uses these resolvers for two purposes. First, it uses them to identify the Principal | attempting to authenticate to CAS /login . In the default configuration, it is the DefaultCredentialsToPrincipalResolver | that fills this role. If you are using some other kind of credentials than UsernamePasswordCredentials, you will need to replace | DefaultCredentialsToPrincipalResolver with a CredentialsToPrincipalResolver that supports the credentials you are | using. | | Second, AuthenticationManagerImpl uses these resolvers to identify a service requesting a proxy granting ticket. | In the default configuration, it is the HttpBasedServiceCredentialsToPrincipalResolver that serves this purpose. | You will need to change this list if you are identifying services by something more or other than their callback URL. +--> <property name="credentialsToPrincipalResolvers"> <list> <!-- | UsernamePasswordCredentialsToPrincipalResolver supports the UsernamePasswordCredentials that we use for /login | by default and produces SimplePrincipal instances conveying the username from the credentials. | | If you've changed your LoginFormAction to use credentials other than UsernamePasswordCredentials then you will also | need to change this bean declaration (or add additional declarations) to declare a CredentialsToPrincipalResolver that supports the | Credentials you are using. +--> <bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" /> <!-- | HttpBasedServiceCredentialsToPrincipalResolver supports HttpBasedCredentials. It supports the CAS 2.0 approach of | authenticating services by SSL callback, extracting the callback URL from the Credentials and representing it as a | SimpleService identified by that callback URL. | | If you are representing services by something more or other than an HTTPS URL whereat they are able to | receive a proxy callback, you will need to change this bean declaration (or add additional declarations). +--> <bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" /> </list> </property> <!-- | Whereas CredentialsToPrincipalResolvers identify who it is some Credentials might authenticate, | AuthenticationHandlers actually authenticate credentials. Here we declare the AuthenticationHandlers that | authenticate the Principals that the CredentialsToPrincipalResolvers identified. CAS will try these handlers in turn | until it finds one that both supports the Credentials presented and succeeds in authenticating. +--> <property name="authenticationHandlers"> <list> <!-- | This is the authentication handler that authenticates services by means of callback via SSL, thereby validating | a server side SSL certificate. +--> <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" /> <!-- | This is the authentication handler declaration that every CAS deployer will need to change before deploying CAS | into production. The default SimpleTestUsernamePasswordAuthenticationHandler authenticates UsernamePasswordCredentials | where the username equals the password. You will need to replace this with an AuthenticationHandler that implements your | local authentication strategy. You might accomplish this by coding a new such handler and declaring | edu.someschool.its.cas.MySpecialHandler here, or you might use one of the handlers provided in the adaptors modules. +--> <bean class="org.jasig.cas.adaptors.ldap.BindLdapGssapiAuthenticationHandler"> <property name="filter" value="uid=%u" /> <property name="searchBase" value="o=langhua,c=cn" /> <property name="contextSource" ref="contextSource" /> </bean> </list> </property> </bean> <bean id="contextSource" class="org.jasig.cas.adaptors.ldap.util.AuthenticatedLdapGssapiContextSource"> <property name="anonymousReadOnly" value="true" /> <property name="password" value="{password_goes_here}" /> <property name="pooled" value="true" /> <property name="urls"> <list> <value>ldap://auth.langhua:389/</value> </list> </property> <property name="userName" value="{username_goes_here}" /> <property name="baseEnvironmentProperties"> <map> <entry> <key><value>java.naming.factory.initial</value></key> <value>com.sun.jndi.ldap.LdapCtxFactory</value> </entry> <entry> <key><value>java.naming.referral</value></key> <value>ignore</value> </entry> <entry> <key><value>java.naming.ldap.attributes.binary</value></key> <value>photo jpegphoto jpegPhoto</value> </entry> <entry> <key><value>java.naming.ldap.version</value></key> <value>3</value> </entry> <entry> <key><value>java.naming.ldap.deleteRDN</value></key> <value>false</value> </entry> <entry> <key><value>java.naming.ldap.derefAliases</value></key> <value>searching</value> </entry> <entry> <key><value>javax.security.sasl.qop</value></key> <value>auth-conf</value> </entry> <entry> <key><value>java.naming.provider.url</value></key> <value>ldap://auth.langhua</value> </entry> <entry> <key><value>java.naming.security.authentication</value></key> <value>GSSAPI</value> </entry> <entry> <key><value>java.security.auth.login.config</value></key> <value>/usr/share/tomcat5/webapps/cas/WEB-INF/gssapi.conf</value> </entry> <entry> <key><value>javax.security.sasl.server.authentication</value></key> <value>true</value> </entry> <entry> <key><value>javax.security.auth.useSubjectCredsOnly</value></key> <value>false</value> </entry> </map> </property> </bean> </beans> |
8. restart tomcat
9. kadmin.local -q "cpw -pw 111111 test"
Make CAS use password to authorize test.
Visit https://auth.langhua:8443/cas/
In client, use IE6 or firefox to visit https://auth.langhua:8443/cas/
username: test or test@AUTH.LANGHUA
password: 111111
Here is a picture to show the login process.
Good Luck!
Shi Yusen/Beijing Langhua Ltd.
http://www.langhua.cn/