001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2005 Danet GmbH (www.danet.de), BU BTS.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: LdapRmsManagedConnection.java,v 1.4.4.2 2007/11/06 13:57:41 drmlipp Exp $
021: *
022: * $Log: LdapRmsManagedConnection.java,v $
023: * Revision 1.4.4.2 2007/11/06 13:57:41 drmlipp
024: * Removed dependency on spis.
025: *
026: * Revision 1.4.4.1 2007/11/05 20:14:12 mlipp
027: * Added authentication properties.
028: *
029: * Revision 1.4 2007/09/02 22:19:53 mlipp
030: * Made LDAP EIS RA realy work.
031: *
032: * Revision 1.3 2007/05/17 21:52:59 mlipp
033: * Refactored resource adaptors.
034: *
035: * Revision 1.2 2006/09/29 12:32:07 drmlipp
036: * Consistently using WfMOpen as projct name now.
037: *
038: * Revision 1.1 2006/09/24 20:57:16 mlipp
039: * Moved RMS implementations in own sub-package.
040: *
041: * Revision 1.1 2006/07/11 08:59:55 drmlipp
042: * Started LDAP RMS RA.
043: *
044: */
045: package de.danet.an.workflow.rmsimpls.ldaprmsra;
046:
047: import java.util.ArrayList;
048: import java.util.Collection;
049: import java.util.Hashtable;
050: import java.util.List;
051:
052: import javax.naming.Binding;
053: import javax.naming.InvalidNameException;
054: import javax.naming.NameNotFoundException;
055: import javax.naming.NamingEnumeration;
056: import javax.naming.NamingException;
057: import javax.naming.NotContextException;
058: import javax.naming.directory.Attribute;
059: import javax.naming.directory.Attributes;
060: import javax.naming.directory.DirContext;
061: import javax.naming.directory.SearchControls;
062: import javax.naming.directory.SearchResult;
063: import javax.naming.ldap.InitialLdapContext;
064: import javax.resource.ResourceException;
065: import javax.resource.spi.CommException;
066: import javax.resource.spi.ConnectionRequestInfo;
067: import javax.security.auth.Subject;
068:
069: import de.danet.an.util.ra.ConnectionSupport;
070: import de.danet.an.util.ra.FactoryConfigurationError;
071: import de.danet.an.util.ra.ManagedConnectionFactorySupport;
072: import de.danet.an.util.ra.ManagedConnectionSupport;
073: import de.danet.an.workflow.rmsimpls.eisrms.aci.RmsEntry;
074:
075: /**
076: * This class provides the managed connection used by the resource adapter
077: * for the properties files based RMS.
078: * @author Michael Lipp
079: */
080: public class LdapRmsManagedConnection extends ManagedConnectionSupport {
081:
082: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
083: .getLog(LdapRmsManagedConnection.class);
084:
085: private LdapRmsManagedConnectionFactory factory = null;
086: private InitialLdapContext ctx = null;
087:
088: /**
089: * Create a new instance.
090: * @param mcf the managed connection factory
091: * @param subject the subject
092: */
093: public LdapRmsManagedConnection(
094: ManagedConnectionFactorySupport mcf, Subject subject) {
095: super (mcf, subject);
096: factory = (LdapRmsManagedConnectionFactory) mcf;
097: Hashtable env = new Hashtable();
098: env.put("java.naming.factory.initial", factory
099: .getJavaNamingFactoryInitial());
100: env.put("java.naming.provider.url", factory
101: .getJavaNamingProviderUrl());
102: env.put("java.naming.security.authentication", factory
103: .getJavaNamingSecurityAuthentication());
104: if (factory.getJavaNamingSecurityPrincipal() != null
105: && factory.getJavaNamingSecurityPrincipal().length() > 0) {
106: env.put("java.naming.security.principal", factory
107: .getJavaNamingSecurityPrincipal());
108: env.put("java.naming.security.credentials", factory
109: .getJavaNamingSecurityCredentials());
110: }
111: if (logger.isDebugEnabled()) {
112: logger.debug("Logging into LDAP server, env=" + env);
113: }
114: try {
115: ctx = new InitialLdapContext(env, null);
116: } catch (NamingException e) {
117: throw new FactoryConfigurationError(
118: "Cannot create LDAP connection: " + e.getMessage(),
119: e);
120: }
121: }
122:
123: /* (non-Javadoc)
124: * Comment copied from interface or superclass.
125: */
126: protected void doDestroy() {
127: try {
128: ctx.close();
129: } catch (NamingException e) {
130: logger.debug("Problem closing ldap context (ignored): "
131: + e.getMessage());
132: }
133: ctx = null;
134: }
135:
136: /* (non-Javadoc)
137: * Comment copied from interface or superclass.
138: */
139: protected ConnectionSupport createConnection(Subject subject,
140: ConnectionRequestInfo cxRequestInfo) {
141: return new LdapRmsConnection();
142: }
143:
144: /* (non-Javadoc)
145: * @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#findResource
146: */
147: public RmsEntry lookupUserByAccountName(String name)
148: throws ResourceException, NameNotFoundException {
149: return searchResource(RmsEntry.RESOURCE_TYPE_USER, name);
150: }
151:
152: /* (non-Javadoc)
153: * @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#lookupResource
154: */
155: public RmsEntry lookupResource(String key)
156: throws ResourceException, NameNotFoundException {
157: String dn = key.substring(2);
158: int resType = 0;
159: if (key.startsWith(RmsEntry.RESOURCE_TYPE_USER + "/")) {
160: resType = RmsEntry.RESOURCE_TYPE_USER;
161: } else if (key.startsWith(RmsEntry.RESOURCE_TYPE_GROUP + "/")) {
162: resType = RmsEntry.RESOURCE_TYPE_GROUP;
163: } else if (key.startsWith(RmsEntry.RESOURCE_TYPE_ROLE + "/")) {
164: resType = RmsEntry.RESOURCE_TYPE_ROLE;
165: } else {
166: throw new IllegalArgumentException(
167: "Resource with invalid key " + key);
168: }
169: String rna = factory.getQueryInfos(resType)
170: .getResourceNameAttribute();
171: try {
172: Attributes pd = ctx.getAttributes(dn);
173: String name = dn;
174: if (pd.get(rna) != null) {
175: name = (String) pd.get(rna).get();
176: }
177: return new RmsEntry(resType, key, name);
178: } catch (InvalidNameException e) {
179: throw (NameNotFoundException) (new NameNotFoundException(
180: "Unknown LDAP resource \"" + dn + "\": "
181: + e.getMessage())).initCause(e);
182: } catch (NotContextException e) {
183: throw (NameNotFoundException) (new NameNotFoundException(
184: "Unknown LDAP resource \"" + dn + "\": "
185: + e.getMessage())).initCause(e);
186: } catch (NamingException e) {
187: throw (ResourceException) (new ResourceException(
188: "Problem accessing LDAP: " + e.getMessage()))
189: .initCause(e);
190: }
191: }
192:
193: /* (non-Javadoc)
194: * @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#listResources()
195: */
196: public Collection listResources() throws ResourceException {
197: List result = new ArrayList();
198: listResourceType(result, factory
199: .getQueryInfos(RmsEntry.RESOURCE_TYPE_USER));
200: listResourceType(result, factory
201: .getQueryInfos(RmsEntry.RESOURCE_TYPE_GROUP));
202: listResourceType(result, factory
203: .getQueryInfos(RmsEntry.RESOURCE_TYPE_ROLE));
204: return result;
205: }
206:
207: private void listResourceType(List result, QueryInfos qi)
208: throws ResourceException {
209: if (qi.getCtxDN() == null) {
210: return;
211: }
212: try {
213: NamingEnumeration resources = null;
214: if (qi.getFilter() == null) {
215: resources = ctx.listBindings(qi.getCtxDN());
216: } else {
217: SearchControls ctrls = new SearchControls();
218: ctrls.setReturningObjFlag(true);
219: ctrls.setReturningAttributes(new String[] {
220: qi.getSearchAttribute(),
221: qi.getResourceNameAttribute() });
222: resources = ctx.search(qi.getCtxDN(), qi.getFilter(),
223: ctrls);
224: }
225: while (resources.hasMore()) {
226: Binding b = (Binding) resources.next();
227: result.add(resourceFromBinding(b, qi));
228: }
229: } catch (NameNotFoundException e) {
230: logger.warn("Cannot access configured context \""
231: + qi.getCtxDN() + "\"");
232: } catch (InvalidNameException e) {
233: logger.warn("Cannot access configured context \""
234: + qi.getCtxDN() + "\"");
235: } catch (NotContextException e) {
236: logger.warn("Cannot access configured context \""
237: + qi.getCtxDN() + "\"");
238: } catch (NamingException e) {
239: throw (CommException) (new CommException(
240: "Problem accessing LDAP: " + e.getMessage()))
241: .initCause(e);
242: }
243: }
244:
245: /* (non-Javadoc)
246: * @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#authorizers
247: */
248: public Collection authorizers(String key) throws ResourceException {
249: List result = new ArrayList();
250: if (!key.startsWith(RmsEntry.RESOURCE_TYPE_USER + "/")) {
251: return result;
252: }
253: String dn = key.substring(2);
254: String mka = factory.getQueryInfos(RmsEntry.RESOURCE_TYPE_USER)
255: .getMemberAttribute();
256: if (mka != null) {
257: try {
258: Attributes attrs = ctx.getAttributes(dn,
259: new String[] { mka });
260: Attribute attr = attrs.get(mka);
261: if (attr == null) {
262: throw new IllegalStateException(
263: "Configuration or data problem: " + dn
264: + " should have attribute \"" + mka
265: + "\"" + " for use as member key.");
266: }
267: dn = (String) attr.get();
268: } catch (NameNotFoundException e) {
269: throw (IllegalArgumentException) (new IllegalArgumentException(
270: "Unknown LDAP resource \"" + dn + "\": "
271: + e.getMessage())).initCause(e);
272: } catch (InvalidNameException e) {
273: throw (IllegalArgumentException) (new IllegalArgumentException(
274: "Unknown LDAP resource \"" + dn + "\": "
275: + e.getMessage())).initCause(e);
276: } catch (NotContextException e) {
277: throw (IllegalArgumentException) (new IllegalArgumentException(
278: "Unknown LDAP resource \"" + dn + "\": "
279: + e.getMessage())).initCause(e);
280: } catch (NamingException e) {
281: throw (CommException) (new CommException(
282: "Problem accessing LDAP: " + e.getMessage()))
283: .initCause(e);
284: }
285: }
286: appendAuthorizers(result, factory
287: .getQueryInfos(RmsEntry.RESOURCE_TYPE_GROUP), dn);
288: appendAuthorizers(result, factory
289: .getQueryInfos(RmsEntry.RESOURCE_TYPE_ROLE), dn);
290: return result;
291: }
292:
293: private void appendAuthorizers(List result, QueryInfos qi,
294: String crit) throws ResourceException {
295: if (qi.getCtxDN() == null) {
296: return;
297: }
298: try {
299: String filter = "(" + qi.getMemberAttribute() + "=" + crit
300: + ")";
301: SearchControls ctrls = new SearchControls();
302: ctrls.setReturningObjFlag(true);
303: ctrls.setReturningAttributes(new String[] {
304: qi.getSearchAttribute(),
305: qi.getResourceNameAttribute() });
306: NamingEnumeration resources = ctx.search(qi.getCtxDN(),
307: filter, ctrls);
308: while (resources.hasMore()) {
309: Binding b = (Binding) resources.next();
310: result.add(resourceFromBinding(b, qi));
311: }
312: } catch (NameNotFoundException e) {
313: logger.warn("Cannot access configured context \""
314: + qi.getCtxDN() + "\"");
315: } catch (InvalidNameException e) {
316: logger.warn("Cannot access configured context \""
317: + qi.getCtxDN() + "\"");
318: } catch (NotContextException e) {
319: logger.warn("Cannot access configured context \""
320: + qi.getCtxDN() + "\"");
321: } catch (NamingException e) {
322: throw (CommException) (new CommException(
323: "Problem accessing LDAP: " + e.getMessage()))
324: .initCause(e);
325: }
326: }
327:
328: /* (non-Javadoc)
329: * @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#selectResources
330: */
331: public Collection selectResources(Object resSel)
332: throws ResourceException {
333: Collection res = new ArrayList();
334: if (resSel == null || !(resSel instanceof String)) {
335: return res;
336: }
337: String crit = (String) resSel;
338: String selType = crit.substring(0, 1);
339: int resType = 0;
340: if (selType.equals("M") || selType.equals("U")) {
341: resType = RmsEntry.RESOURCE_TYPE_USER;
342: } else if (selType.equals("G")) {
343: resType = RmsEntry.RESOURCE_TYPE_GROUP;
344: } else if (selType.equals("R")) {
345: resType = RmsEntry.RESOURCE_TYPE_ROLE;
346: } else {
347: return null;
348: }
349: try {
350: res.add(searchResource(resType, crit.substring(2)));
351: } catch (NameNotFoundException e) {
352: }
353: return res;
354: }
355:
356: private RmsEntry searchResource(int resType, String crit)
357: throws ResourceException, NameNotFoundException {
358: QueryInfos qi = factory.getQueryInfos(resType);
359: if (qi.getCtxDN() == null) {
360: throw new IllegalArgumentException(
361: "No context configured for searching \"" + crit
362: + "\"");
363: }
364: try {
365: String filter = "(" + qi.getSearchAttribute() + "=" + crit
366: + ")";
367: if (qi.getFilter() != null) {
368: filter = "(&" + qi.getFilter() + filter + ")";
369: }
370: SearchControls ctrls = new SearchControls();
371: ctrls.setReturningObjFlag(true);
372: ctrls.setReturningAttributes(new String[] {
373: qi.getSearchAttribute(),
374: qi.getResourceNameAttribute() });
375: NamingEnumeration resources = ctx.search(qi.getCtxDN(),
376: filter, ctrls);
377: if (!resources.hasMore()) {
378: throw (NameNotFoundException) (new NameNotFoundException(
379: "No LDAP resource in context \""
380: + qi.getCtxDN() + "\" with \""
381: + qi.getSearchAttribute() + "=" + crit
382: + "\""));
383: }
384: Binding b = (Binding) resources.next();
385: return resourceFromBinding(b, qi);
386: } catch (NameNotFoundException e) {
387: throw (NameNotFoundException) (new NameNotFoundException(
388: "Unknown LDAP context \"" + qi.getCtxDN() + "\": "
389: + e.getMessage())).initCause(e);
390: } catch (InvalidNameException e) {
391: throw (NameNotFoundException) (new NameNotFoundException(
392: "Unknown LDAP context \"" + qi.getCtxDN() + "\": "
393: + e.getMessage())).initCause(e);
394: } catch (NotContextException e) {
395: throw (NameNotFoundException) (new NameNotFoundException(
396: "Unknown LDAP context \"" + qi.getCtxDN() + "\": "
397: + e.getMessage())).initCause(e);
398: } catch (NamingException e) {
399: throw (CommException) (new CommException(
400: "Problem accessing LDAP: " + e.getMessage()))
401: .initCause(e);
402: }
403: }
404:
405: private RmsEntry resourceFromBinding(Binding binding, QueryInfos qi)
406: throws NamingException {
407: DirContext resource = (DirContext) binding.getObject();
408: String resDN = resource.getNameInNamespace();
409: String resKey = qi.getResType() + "/" + resDN;
410: Attributes attrs = null;
411: if (binding instanceof SearchResult) {
412: attrs = ((SearchResult) binding).getAttributes();
413: } else {
414: attrs = resource.getAttributes("", new String[] {
415: qi.getResourceNameAttribute(),
416: qi.getSearchAttribute() });
417: }
418: String resName = null;
419: if (attrs.get(qi.getResourceNameAttribute()) != null) {
420: resName = (String) attrs.get(qi.getResourceNameAttribute())
421: .get();
422: } else if (qi.getSearchAttribute() != null
423: && attrs.get(qi.getSearchAttribute()) != null) {
424: resName = (String) attrs.get(qi.getSearchAttribute()).get();
425: }
426: return new RmsEntry(qi.getResType(), resKey, resName);
427: }
428:
429: }
|