shibboleth-dev - JNDI data connector and DN-based searches (was: 2 interesting questions)
Subject: Shibboleth Developers
List archive
- From: Brent Putman <>
- To:
- Subject: JNDI data connector and DN-based searches (was: 2 interesting questions)
- Date: Fri, 23 Sep 2005 17:38:43 -0400
This question over on shib-users brought up again something that I have
encountered in the past: the general need within the resolver to use
the value of a user's DN (obtained in an initial LDAP search) in a
second search that has the first as a dependency. I saw that in 1.3 in
the JNDIDirectoryDataConnector, the DN value is now nicely being placed
in the resolved attribute set (when using Sun's LDAP provider), but it
still seems like you would have to write a custom connector to actually
make use of it. If I'm missing something there let me know... What I want to be able to do is something more declarative in the resolver config example below - a %DN% macro that gets expanded using the dn value available from a previous search (via a DataConnectorDependency). And ideally, I want to be able to use it in either the search filter, *or* in the provider URL as the LDAP search base. <JNDIDirectoryDataConnector id="directory"> <Search filter="uid=%PRINCIPAL%"> <Controls searchScope="SUBTREE_SCOPE" returningObjects="false" /> </Search> <Property name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory" /> <Property name="java.naming.provider.url" value="ldap://directory.georgetown.edu/dc=georgetown,dc=edu" /> </JNDIDirectoryDataConnector> <JNDIDirectoryDataConnector id="directory_groups" mergeMultipleResults="true"> <DataConnectorDependency requires="directory"/> <Search filter="uniquemember=%DN%"> <Controls searchScope="SUBTREE_SCOPE" returningObjects="false" /> </Search> <Property name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory" /> <Property name="java.naming.provider.url" value="ldap://directory.georgetown.edu/dc=georgetown,dc=edu" /> </JNDIDirectoryDataConnector> <JNDIDirectoryDataConnector id="directory_roles" mergeMultipleResults="true"> <DataConnectorDependency requires="directory"/> <Search filter="objectclass=organizationalRole"> <Controls searchScope="SUBTREE_SCOPE" returningObjects="false" /> </Search> <Property name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory" /> <Property name="java.naming.provider.url" value="ldap://directory.georgetown.edu/%DN%" /> </JNDIDirectoryDataConnector> The "directory" connector is the traditional basic search using the user's authenticated principal name, and returns the user's "dn" attribute, among others. The "directory_groups" example shows the typical case where the user's DN needs to be used as the input to the search filter, for example when the directory contains GroupofNames or GroupofUniqueNames objects, containing member or uniqueMember attributes with DN values. I think this is a very common use case. The "directory_roles" example is the less common (but nonetheless extant and valid) case where the user's DN is not a leaf, but is a container holding subordinate objects specific to that user (ala Roman's example). Here you need to be able to insert the user's DN into the LDAP search base. So, with that in mind, I have written the attached patch for JNDIDirectoryDataConnector which implements the above basic functionality. The search filter case is pretty easy. The provider url case is a little more complicated, and means having to skip the fail-fast test on connector initialization (or maybe using a known fixed search base to test with, but that might not be portable across directory servers). In order for the %DN% macro expansion to work, you must have a DataConnectorDependency declared which has resolved a "dn" attribute. I have tested it and it does work for both of the above configs, but would consider it a work-in-progress... I'm sure I've missed some edge cases, etc. So I throw this out there for consideration, or at least for discussion. Perhaps others won't consider the use cases to be common enough to warrant adding this functionality to the base connector. If that is the case, then I could perhaps rework this into a custom connector that extends the base JNDI connector. Mainly I just wanted to see what others think. Thanks, Brent Roman Sozinov wrote: The inner structure of my ldap server is: dn: ou=People,c=LT objectClass: organizationalUnit ou: People dn: uid=user3,ou=People,c=lt objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson uid: user3 cn: Sam telephoneNumber: 55544 dn: ou=sites,uid=user3,ou=People,c=lt ou: sites objectClass: top objectClass: organizationalUnit dn: ou=www.site1.lt,ou=sites,uid=user3,ou=People,c=lt cn: admin ou: cnt.e-space.lt objectClass: organizationalRole objectClass: top dn: ou=www.site2.lt,ou=sites,uid=user3,ou=People,c=lt cn: manager ou: cnt.e-space.lt objectClass: organizationalRole objectClass: top As you can see, my user uid=user3,ou=People,c=lt has different roles for different sites(www.site1.lt, www.site2.lt). But i don't know how to say to IdP to get roles(admin, manager) from my ldap server, because the user is authenticated on IdP using JNDI-Connector: <JNDIDirectoryDataConnector id="directory"> <Search filter="uid=%PRINCIPAL%"> <Controls searchScope="SUBTREE_SCOPE" returningObjects="false" /> </Search> <Property name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory" /> <Property name="java.naming.provider.url" value="ldap://myldap/ou=People,c=lt <Property name="java.naming.security.principal" value="cn=admin,c=lt" /> <Property name="java.naming.security.credentials" value="password" /> </JNDIDirectoryDataConnector> and i don't know how to get attributes ...ou=sites,uid=user3,ou=People,c=lt with a help of arps-files. If i need to use the second JNDI-connector, what the sintax should be? -- Roman Sozinov ----- Original Message ----- From: "Walter Hoehn" To: Sent: Thursday, September 22, 2005 10:45 PM Subject: Re: 2 interesting questions I'm not certain that I understand your DIT layout, but I'm pretty sure you can accomplish what you want by having two JNDI connectors in your configuration. -Walter On Sep 22, 2005, at 4:14 AM, Roman Sozinov wrote:and there is another question about accessing LDAP-atributes from our IdP: When we give access with JNDIDirectoryDataConnector to the user, we can operate only with that his attributes, which are in the same level of directory as his uid(cn). But how can we get access to attributes which are inside user's tree. For example, 1st level: (key attribute) uid uid=user1 cn=bob sn=smith ou=roles 2nd level (key attribute) ou ou=roles cn=manager We have access to attributes: uid, cn,sn,ou in the first level of user's tree, but can we have access to attribute cn at the 2-nd level? If "yes" - how?__________ http://www.newhost.ru - ÃîâÝëÙ ÔÞÜ ÔÛï ²ÐèÕÓÞ áÐÙâÐ! |
===================================================================
RCS file:
/home/cvs/shibboleth/shibboleth/java/src/edu/internet2/middleware/shibboleth/aa/attrresolv/provider/JNDIDirectoryDataConnector.java,v
retrieving revision 1.18
diff -u -r1.18 JNDIDirectoryDataConnector.java
--- JNDIDirectoryDataConnector.java 21 Aug 2005 11:42:03 -0000 1.18
+++ JNDIDirectoryDataConnector.java 23 Sep 2005 20:53:21 -0000
@@ -148,8 +148,12 @@
try {
if (!startTls) {
try {
- log.debug("Attempting to connect to
JNDI directory source as a sanity check.");
- context = initConnection();
+ if ( !
properties.getProperty("java.naming.provider.url").contains("%DN%") ) {
+ log.debug("Attempting to
connect to JNDI directory source as a sanity check.");
+ context = initConnection();
+ } else {
+ log.debug("Bypassing JNDI
fail-fast test because provider URL contains '%DN%'");
+ }
} catch (IOException ioe) {
log.error("Failed to startup
directory context: " + ioe);
throw new
ResolutionPlugInException("Failed to startup directory context.");
@@ -185,8 +189,12 @@
sslc.init(new
KeyManager[]{keyManager}, null, new SecureRandom());
sslsf = sslc.getSocketFactory();
- log.debug("Attempting to connect to
JNDI directory source as a sanity check.");
- initConnection();
+ if (!
properties.getProperty("java.naming.provider.url").contains("%DN%") ) {
+ log.debug("Attempting to
connect to JNDI directory source as a sanity check.");
+ initConnection();
+ } else {
+ log.debug("Bypassing JNDI
fail-fast test because provider URL contains '%DN%'");
+ }
} catch (GeneralSecurityException gse) {
log.error("Failed to startup
directory context. Error creating SSL socket: " + gse);
throw new
ResolutionPlugInException("Failed to startup directory context.");
@@ -299,6 +307,54 @@
InitialDirContext context = null;
NamingEnumeration nEnumeration = null;
String populatedSearch =
searchFilter.replaceAll("%PRINCIPAL%", principal.getName());
+
+ if (populatedSearch.contains("%DN%")
+ ||
properties.getProperty("java.naming.provider.url").contains("%DN%") ) {
+ Iterator connectorDependIt =
connectorDependencyIds.iterator();
+ Attribute attr = null;
+ while (connectorDependIt.hasNext()) {
+ Attributes attrs =
depends.getConnectorResolution((String) connectorDependIt.next());
+ if (attrs != null) {
+ attr = attrs.get("dn");
+ // TODO: Break out when find the
first dn attribute - there can be only one...
+ // or maybe should loop over
them all.. or throw an error if multi ???
+ if (attr != null)
+ break;
+ }
+ }
+ try {
+ if (attr != null) {
+ // There should only be one value for
dn
+ String dn = (String) attr.get();
+ if (!dn.equals("")) {
+ populatedSearch =
populatedSearch.replaceAll("%DN%", dn);
+ // Also allow interpolation
into the LDAP search base
+ String providerURL =
properties.getProperty("java.naming.provider.url");
+ if
(providerURL.contains("%DN%")) {
+ providerURL =
providerURL.replaceAll("%DN%", dn);
+ // TODO may need to
encode/escape this string further, if it has spaces, etc
+
properties.setProperty("java.naming.provider.url",
+
providerURL);
+ }
+ } else {
+ log.error("Found an empty
'dn' value for '%DN%' for principal ("
+ +
principal.getName() + ")");
+ throw new
ResolutionPlugInException("Found an empty 'dn' value for '%DN%'");
+ }
+ } else {
+ log.error("Search filter contained
%DN% macro, but was unable to resolve a 'dn' attribute value for principal ("
+ + principal.getName()
+ ")" );
+ throw new
ResolutionPlugInException("Unable to resolve 'dn' value for %DN%.");
+ }
+ }
+ catch (NamingException e) {
+ log.error("An error occurred while obtaining
DN attribute dependency data for principal (" + principal.getName() + ") :"
+ + e.getMessage());
+ throw new ResolutionPlugInException("Problem
obtaining 'dn' attribute value from resolved data connector dependency");
+ }
+ }
+
+
try {
try {
context = initConnection();
- JNDI data connector and DN-based searches (was: 2 interesting questions), Brent Putman, 09/23/2005
- Re: JNDI data connector and DN-based searches, Brent Putman, 09/26/2005
Archive powered by MHonArc 2.6.16.