Más contenido relacionado La actualidad más candente (9) Similar a Collaborative Cuisine's 1 Hour JNDI Cookbook (20) Collaborative Cuisine's 1 Hour JNDI Cookbook1. 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?