Your SlideShare is downloading. ×
Collaborative Cuisine's 1 Hour JNDI Cookbook
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Collaborative Cuisine's 1 Hour JNDI Cookbook

214
views

Published on

For programmers who are already familiar with JNDI and LDAP basics, but wonder how to mix all those ingredients together into collaborative directory-enabled JEE solutions. …

For programmers who are already familiar with JNDI and LDAP basics, but wonder how to mix all those ingredients together into collaborative directory-enabled JEE solutions.

http://kenlin.com

Published in: Technology, Business

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
214
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
4
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Lotus Software - Messaging & Collaboration Confidential | June 2, 2003 | LSM Seminar 2003 © 2002 IBM Corporation From Now To Next Ken Lin Senior Software Engineer klin@us.ibm.com Collaborative Cuisine's 1 Hour JNDI Cookbook
  • 2. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Goals Review common directory-related collaboration scenarios Examine solutions through algorithms and JNDI code Refine and improve solutions
  • 3. Lotus Software - Messaging & Collaboration Confidential | June 2, 2003 | LSM Seminar 2003 © 2002 IBM Corporation From Now To Next Starters Main Courses Desserts Tidy Up Today's Menu
  • 4. Lotus Software - Messaging & Collaboration Confidential | June 2, 2003 | LSM Seminar 2003 © 2002 IBM Corporation From Now To Next Locate a Directory Server Resolve and Authenticate a User Starters
  • 5. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Locate a Directory Server Properties File Configured by each application administrator Application-dependent solution Easy to code via java.util.Properties Manageable when few applications RFC 2782 - A DNS RR for specifying the location of services (DNS SRV) Configured centrally by DNS administrator Application-independent solution Easy to code via JNDI Manageable even when many applications Recognized by com.sun.jndi.ldap.LdapCtxFactory in JDK 1.4.1
  • 6. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DNS SRV (RFC 2782) w32 [C:] winntsystem32nslookup Default Server: ns1.iris.com Address: 9.95.aaa.bbb > set q=srv > _ldap._tcp.iris.com you type this 0=highest 65535=lowest Server: ns1.iris.com Address: 9.95.aaa.bbb _ldap._tcp.iris.com SRV service location: priority = 0 weight = 0 port = 389 svr hostname = clapton.iris.com _ldap._tcp.iris.com SRV service location: priority = 100 weight = 0 port = 389 svr hostname = little-village.iris.com clapton.iris.com internet address = 9.95.ccc.ddd little-village.iris.com internet address = 9.95.eee.fff >^Z
  • 7. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirServer.getServers returns host:port strings public static Vector getServers(String domain) throws NamingException { Vector servers = new Vector(); Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); DirContext ctx = new InitialDirContext(env); Attributes attrs = ctx.getAttributes("_ldap._tcp." + domain, new String[] {"SRV"}); Attribute srv = attrs.get("SRV"); if (srv != null) { NamingEnumeration results = srv.getAll(); if (results.hasMore()) { while (results.hasMore()) { String result = (String)results.next(); StringTokenizer tokens = new StringTokenizer(result, " "); String priority = tokens.nextToken(); String weight = tokens.nextToken(); String port = tokens.nextToken(); String target = tokens.nextToken(); servers.add(target + ":" + port); } } } return servers; } J2SE 1.4.1 or higher
  • 8. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Resolve and Authenticate Users How do we code applications to authenticate using "friendly" names? cn=ken lin,ou=westford,o=ibm is not very friendly!
  • 9. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Resolve and Authenticate Users Algorithm Does the supplied name look like an LDAP DN? Yes: ask the LDAP server if DN exists? Yes: go to Authenticated Bind No: go to Resolve DN No: go to Resolve LDAP DN Resolve supplied name to LDAP DN Unauthenticated search the name to obtain its DN (&(objectclass=person)(|(uid={0})(mail={0})(cn={0}))) Allow the filter to be customized to fit customer (&(objectclass=person)(telephonenumber={0})) If number of search hits is ... 0: name not found 1: go to Authenticated Bind otherwise: ambiguous DN Authenticated Bind Use LDAP DN and supplied password
  • 10. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirUser.authenticate to Authenticate and Resolve a Name boolean authenticate(String hostport, String anyname, String password) throws NamingException { boolean authenticated = false; DirContext ctx = null; try { String dn = resolve(anyname); if (dn != null) { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, m_ServiceProvider); env.put(Context.PROVIDER_URL, "ldap://" + hostport); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, dn); env.put(Context.SECURITY_CREDENTIALS, password); ctx = new InitialDirContext(env); authenticated = true; } } catch (AuthenticationException e) { authenticated = false; } finally { try { if (ctx != null) ctx.close(); } catch (Exception e) { } } return authenticated; } "com.sun.jndi.ldap.LdapCtxFactory" local DirContext for dn/password
  • 11. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirUser.resolve to Get a DN from anyname String resolve(String anyname) throws NamingException { // If anyname looks like it might be a DN, try a base search if (anyname.indexOf("=") != -1) { try { Attributes attrs = m_Ctx.getAttributes(anyname); return anyname; } catch (NameNotFoundException e) { // not a valid or known DN, try filtered search } } // anyname must not look like a DN, search for m_FilterPattern with anyname Object args[] = {anyname}; String filter = java.text.MessageFormat.format(m_FilterPattern, args); SearchControls ctls = new SearchControls(); ctls.setReturningAttributes(null); ctls.setCountLimit(1); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); NamingEnumeration results = m_Ctx.search(m_Base, filter, ctls); if (results.hasMore()) { SearchResult result = (SearchResult)results.next(); return result.getName(); } else { throw new NameNotFoundException("Neither DN nor filter hits"); } } "(&(objectclass=person) (|(uid={0})(mail={0})(cn={0})))" DirContext for this application some vendors require base so more than 1 result causes SizeLimitExceededException
  • 12. Lotus Software - Messaging & Collaboration Confidential | June 2, 2003 | LSM Seminar 2003 © 2002 IBM Corporation From Now To Next Find a Member's Group Find a Group's Members Main Courses
  • 13. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Directory Groups IETF, Defacto, and Vendor Group Definitions Definitions for Static Groups in IETF RFC 2782 groupOfNames / member groupOfUniqueNames / uniqueMember Group operations are coded by the application, not the LDAP server! Applications must understand schema Applications must code findMembers Applications must code findGroups
  • 14. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 dgservlet Demo
  • 15. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Two Common Uses for findMembers and findGroups findMembers can be used to expand and flatten out a buddy list findGroups can be used to create Notes-like NamesLists for authorization
  • 16. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirGroups Class public class DirGroups { protected DirContext m_Ctx = null; protected NameParser m_Parser = null; protected String m_GroupObjectClasses[] = {"groupOfNames"}; protected String m_MemberNames[] = {"member"}; protected String m_Base = ""; protected String m_MemberFilter = "(&(objectclass=groupOfNames)(member={0}))"; protected int m_FindMembersDepth = 10; protected String m_MemberAttrIds[] = {"objectclass", "member", "cn"}; public DirGroups(DirContext ctx) { m_Ctx = ctx; } public void findGroups(String memberDN, Hashtable groups) throws NamingException { described later... } public void findMembers(Name groupDN, Hashtable groups, Hashtable users, Hashtable unknown) throws NamingException { described later... } etc... }
  • 17. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 findMembers Algorithm get entry g from groupDN and verify it is a group foreach memberDN in g { if memberDN isn't in groups, users, or unknown { get entry m from memberDN if m is a group --> add m to groups and recurse... findMembers(memberDN, groups, users, unknown) if m is a non-group --> add m to users if m's objectclass is unknown --> add m to unknown } } findMembers(in String groupDN, inout Hashtable groups, inout Hashtable users, inout Hashtable unknown) Optimize!
  • 18. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirGroups.findMembers public void findMembers(Name groupDN, Hashtable groups, Hashtable users, Hashtable unknown) throws NamingException { // Verify arguments if (groupDN == null || groups == null || users == null || unknown == null) { return; } // Verify the groupDN is really a group Attributes attrs = m_Ctx.getAttributes(groupDN, m_MemberAttrIds); if (!isGroup(attrs)) { throw new NamingException("'objectclass' is not a group"); } findMembers(attrs, m_FindMembersDepth, groups, users, unknown); } DirContext for this DirGroups object 10 {"objectclass", "member", "cn"}
  • 19. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirGroups.findMembers private void findMembers(Attributes attrs, int depth, Hashtable groups, Hashtable users,Hashtable unknown) throws NamingException { if (depth <= 0) { return; } for (int i = 0; i < m_MemberNames.length; i++) { Attribute attr = attrs.get(m_MemberNames[i]); if (attr != null) { NamingEnumeration members = attr.getAll(); while (members.hasMore()) { Name memberDN = toName((String)members.nextElement()); // Process memberDN only if it hasn't yet been encounterred if (!users.containsKey(memberDN) && !groups.containsKey(memberDN) && !unknown.containsKey(memberDN)) { try { if (isGroup(memberDN)) { // memberDN is a group attrs = m_Ctx.getAttributes(memberDN, m_MemberAttrIds); if (groups.put(memberDN, attrs) == null) { findMembers(attrs, depth-1, groups, users, unknown); } } else { // memberDN is a non-group users.put(memberDN, memberDN/*null*/); } } catch (NamingException e) { // memberDN is unknown unknown.put(memberDN, memberDN/*null*/); } } } // while } } // for } {"objectclass", "member", "cn"} {"member"}
  • 20. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirGroups.isGroup private boolean isGroup(Name name) throws NamingException { if (m_GroupObjectClasses.length == 1) { return compare(name, "objectclass", m_GroupObjectClasses[0]); } else { Attributes attrs = m_Ctx.getAttributes(name, m_MemberAttrIds); return isGroup(attrs); } } private boolean isGroup(Attributes attrs) throws NamingException { Attribute attr = attrs.get("objectclass"); if (attr != null) { for (int i = 0; i < m_GroupObjectClasses.length; i++) { if (attr.contains(m_GroupObjectClasses[i])) { return true; } } return false; } else { throw new NamingException("'objectclass' attribute not found"); } } LDAP compare is faster than search {"groupOfNames"}
  • 21. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirGroups.compare private boolean compare(Name name, String attr, String value) throws NamingException { SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.OBJECT_SCOPE); ctls.setReturningAttributes(new String[0]); // no attributes // LDAP compare operation NamingEnumeration results = m_Ctx.search(name, "(" + attr + "=" + value + ")", ctls); return results.hasMore(); // if successful, results will contain a single item }
  • 22. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 findGroups Algorithm findGroups(in String memberDN, inout Hashtable groups) g = DNs of groups that memberDN is a direct member tovisit = g while tovisit is not empty { pop any groupDN from tovisit if groupDN is not in groups { groups += groupDN g = DNs of groups that groupDN is a direct member of tovisit += elements of g not in tovisit or groups } } 1. cn=bugs bunny,o=toons empty 2. cn=looney toons 3. cn=looney toons 4. cn=looney toons empty 5. cn=looney toons 6. cn=all toons 7. cn=all toons 8. cn=all toons 9. cn=all toons empty 10. cn=looney toons cn=all toons 11. empty 12. empty
  • 23. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirGroups.findGroups public void findGroups(Name memberDN, Hashtable groups) throws NamingException { Hashtable tovisit = new Hashtable(); // DNs of groups to visit // Initialize tovisit to groups that memberDN is a direct member of. putDirectGroups(memberDN, tovisit, groups); // groups = union(groups, tovisit) while (!tovisit.isEmpty()) { // Pop groupDN from tovisit Name groupDN = (Name)tovisit.keys().nextElement(); tovisit.remove(groupDN); // Add groupDN to groups if (groups.put(groupDN, groupDN) == null) { // Wasn't previously processed, search what groups it is a // member of. try { putDirectGroups(groupDN, tovisit, groups); } catch (NamingException e) { e.printStackTrace(); } } else { // Was processed previously, don't do anything } } }
  • 24. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirGroups.putDirectGroups private void putDirectGroups(Name memberDN, Hashtable tovisit, Hashtable groups) throws NamingException { // Find in results the groups that memberDN is a direct member of. NamingEnumeration results = findDirectGroups(memberDN); // Put each group in tovisit if it doesn't already exist in tovisit or // groups. while (results.hasMore()) { SearchResult result = (SearchResult)results.next(); Name groupDN = toName(result.getName()); if (!groups.containsKey(groupDN) && !tovisit.contains(groupDN)) { tovisit.put(groupDN, groupDN); } } }
  • 25. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirGroups.findDirectGroups private NamingEnumeration findDirectGroups(Name memberDN) throws NamingException { Object args[] = {memberDN}; String filter = java.text.MessageFormat.format(m_MemberFilter, args); SearchControls ctls = new SearchControls(); String[] attrIDs = {}; ctls.setReturningAttributes(attrIDs); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); NamingEnumeration results = m_Ctx.search(m_Base, filter, ctls); return results; } "(&(objectclass=groupOfNames) (member={0}))" some vendors require base DirContext for this DirGroups object
  • 26. Lotus Software - Messaging & Collaboration Confidential | June 2, 2003 | LSM Seminar 2003 © 2002 IBM Corporation From Now To Next Domino LDAP Server Tips Client-side LDAP Improvements Two and Three-Tier Architectures Desserts
  • 27. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 DirUser.m_FilterPattern = "(&(objectclass=person)(|(uid={0})(mail={0})(cn={0})))" More "|" terms increases search time FT Index Domino Directory if term cannot be serviced by view search DirGroups.m_GroupObjectClasses = {"groupOfNames"} Uses slightly more efficient LDAP compare instead LDAP search Use {"groupOfUniqueNames"} when running against Netscape only Use {"groupOfNames", "groupOfUniqueNames"} when running against LDAP servers from various vendors Domino 6 LDAP Query-Results Cache Domino 6.02 LDAP improves DirGroups.findMembers response for attributes with hundreds of values Use LDAPDEBUG=1 in Notes.ini to trace LDAP server Domino LDAP Server Tips
  • 28. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Client-side LDAP Improvements Eliminate trips to LDAP server for duplicated group queries findMembers("cn=Iris Directory Team", ...) findGroups("cn=ken lin,ou=westford,o=ibm", ...) Reduce trips to LDAP server for "similar" group queries findMembers("cn=Iris Directory Team", ...) vs. findMembers("cn=LDAP Server Dev', ...) findGroups("cn=ken lin,ou=westford,o=ibm") -> 104 groups vs. findGroups("cn=scott m davidson,ou=westford,o=ibm") -> 135 groups Eliminate trips to LDAP server for duplicated name resolution queries TBD - improve DirGroups.isGroup by consulting cached "objectclass=groupOfNames" results (FT Index) TBD - cache LDAP bind requests
  • 29. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 InitialDirContextCache Extends javax.naming.InitialDirContext Overrides and caches DirContext's getAttributes and search DirGroups or other JNDI calls Initial- DirContext- Cache Initial DirContext LDAP ServerApp Internally, query-results caches are implemented via Hashtables Name.compareTo() is important for Hashtable entry comparison Not a single line of DirGroups or your JNDI calls was changed to take advantage of caching!
  • 30. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 InitialDirContextCache.getAttributes public Attributes getAttributes(Name name, String[] attrIds) throws NamingException { String key = toKey(name, attrIds); Object cached = m_AttributesCache.get(key); Attributes attrs = null; if (cached == null) { try { attrs = super.getAttributes(name, attrIds); if (attrs != null) { Attributes value = (Attributes)attrs.clone(); m_AttributesCache.put(key, value); } } catch (NamingException e) { m_AttributesCache.put(key, e.toString()); throw e; } } else { if (cached instanceof String) { throw new NamingException(cached.toString()); } else { attrs = (Attributes)cached; } } return attrs; } cache implemented via Hashtable performs the real LDAP call makes a 2-tuple from name/attrIDs
  • 31. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Two and Three-Tier Architectures Two-Tier Architecture LDAP Server JNDI or DirGroups App JNDI or DirGroups App JNDI or DirGroups App JNDI or DirGroups App Back App Front App Front App Front LDAP Server Three-Tier Architecture e.g., Domino DA, Sametime, J2EE, dgservlet e.g., Mail clients
  • 32. Lotus Software - Messaging & Collaboration Confidential | June 2, 2003 | LSM Seminar 2003 © 2002 IBM Corporation From Now To Next Review Tomorrow Questions Tidy Up
  • 33. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Review Algorithms and Code Locate a Directory Server DirServer.getServers() Resolve and Authenticate a userDirUser.authenticate() Find a Group's Members DirGroups.findMembers() Find a Member's Groups DirGroups.findGroups() Cache Query Results InitialDirContextCache Improvements
  • 34. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 Tomorrow Run nslookup, look for SRVs Download seminar samples Run DirServer.main() Run DirUser.main() Install and run dgservlet Try "real" directories Experiment!
  • 35. Lotus Software - Messaging and Collaboration © 2002 IBM CorporationCollaborative Cuisine's 1 Hour JNDI Cookbook | LSM Seminar 2003 References Collaborative Cuisine's 1 Hour JNDI Cookbook - LSM 2003 https://www-914.ibm.com/events/lsm/03lsm.nsf Building Directory Friendly Applications - LSM 2002 https://www-914.ibm.com/events/lsm/02lsm.nsf/lookupwebpage/AbsPresAppDev JNDI Tutorial - Tips for LDAP Users http://java.sun.com/products/jndi/tutorial/ldap/index.html Java Servlet Technology http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Servlets.html Eclipse - an open extensible IDE http://eclipse.org Directory Services Markup Language http://www.oasis-open.org/cover/dsml.html The String Representation of LDAP Search Filters http://www.ietf.org/rfc/rfc2254.txt A DNS RR for specifying the location of services (DNS SRV) http://www.ietf.org/rfc/rfc2782.txt http://www.ietf.org/internet-drafts/draft-ietf-ldapext-locate-08.txt A Summary of the X.500(96) User Schema for use with LDAPv3 http://www.ietf.org/rfc/rfc2256.txt Misc. LDAP JNDI
  • 36. Lotus Software - Messaging & Collaboration Confidential | June 2, 2003 | LSM Seminar 2003 © 2002 IBM Corporation From Now To Next Questions?