001: /**
002: * Copyright 2002 Sun Microsystems, Inc. All
003: * rights reserved. Use of this product is subject
004: * to license terms. Federal Acquisitions:
005: * Commercial Software -- Government Users
006: * Subject to Standard License Terms and
007: * Conditions.
008: *
009: * Sun, Sun Microsystems, the Sun logo, and iPlanet
010: * are trademarks or registered trademarks of Sun Microsystems,
011: * Inc. in the United States and other countries.
012: */package com.sun.portal.app.calendarcommon.calendar;
013:
014: import com.sun.comm.jdapi.DAAttribute;
015: import com.sun.comm.jdapi.DABusinessOrganization;
016: import com.sun.comm.jdapi.DAConnection;
017: import com.sun.comm.jdapi.DAConstants;
018: import com.sun.comm.jdapi.DAException;
019: import com.sun.comm.jdapi.DASearchConstraint;
020: import com.sun.comm.jdapi.DASearchResults;
021: import com.sun.comm.jdapi.DAUser;
022: import com.sun.portal.app.calendarcommon.common.SharedServicesException;
023: import com.sun.portal.log.common.PortalLogger;
024: import java.util.Arrays;
025: import java.util.HashMap;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Properties;
029: import java.util.Vector;
030: import java.util.logging.Level;
031: import java.util.logging.Logger;
032:
033: /**
034: * Handles access to a single Delegated Administrator server for creation, deletion and update of
035: * calendar proxy users and community member users, on behalf of a particular Community.
036: *
037: * @author Nigel Jacobs
038: * @created May 18, 2005
039: */
040:
041: public class DelegatedAdministratorHandler {
042:
043: private static Logger logger = PortalLogger
044: .getLogger(SharedCalendarUtilsImpl.class);
045:
046: // The SSO adapter config properties that define the DA host/port, proxy uid/pwd, domain etc.
047: private Properties _configProps = null;
048:
049: // The community ID of this handler.
050:
051: private String _communityID = null;
052:
053: private SharedCalendarUtils _calUtils = null;
054:
055: // maps da user dns (mbr ids) to sunPreferredDomain value of parent business org
056: private Map _usersDomain = new HashMap();
057:
058: /**
059: * Creates a new instance of DelegatedAdministratorHandler
060: */
061: public DelegatedAdministratorHandler(String communityID,
062: Properties configProps, SharedCalendarUtils calUtils) {
063: _configProps = configProps;
064: _communityID = communityID;
065: _calUtils = calUtils;
066: }
067:
068: /**
069: * Create a the proxy calendar user for the community. Use JDAPI to connect to DA, using the params defined
070: * in the SSO adapter config properties.
071: */
072: public void createCalProxyUser() throws SharedServicesException {
073:
074: try {
075:
076: DAConnection con = getConnection();
077: DABusinessOrganization org = getBusinessOrgForConfiguredDomain(con);
078: String domain = _configProps
079: .getProperty(SharedCalendarUtils.CONFIG_PROP_daDomain);
080: String userUid = _calUtils.getProxyUser(_communityID);
081:
082: // Create the proxy user, if it does not exist
083: DAUser user = findUserInOrgByUID(org, userUid);
084: if (user == null) {
085:
086: user = new DAUser();
087: String[] aValues = new String[1];
088: user.setAttributeValues(DAConstants.UID, userUid);
089: user.setAttributeValues(DAConstants.LAST_NAME, "");
090: user
091: .setAttributeValues(DAConstants.FIRST_NAME,
092: userUid);
093: user.setAttributeValues(DAConstants.FULL_NAME, userUid);
094: // as this user is a proxy user, solely for shared cal use, we can use the DA proxy password
095: user
096: .setAttributeValues(
097: DAConstants.PASSWORD,
098: _configProps
099: .getProperty(SharedCalendarUtils.CONFIG_PROP_daProxyPassword));
100: // Add the calendarService specific Attributes (Hack until we can use JES4 JDAPI)
101: aValues[0] = "icsCalendarUser";
102: user.addAttribute("objectclass", aValues);
103: String mailDomain = org
104: .getFirstValue(DAConstants.DOMAIN_NAME);
105: if (mailDomain == null) {
106: mailDomain = "DUMMY.COM"; // shouldn't happen
107: }
108: // This LDAP attr is required by cal server
109: user.setAttributeValues(DAConstants.MAIL_ATTR, userUid
110: + "@" + mailDomain);
111:
112: org.createUser(user);
113:
114: if (logger.isLoggable(Level.FINE)) {
115: logger.fine("Created Proxy User: " + userUid);
116: }
117:
118: }
119:
120: } catch (Exception e) {
121: throw new SharedServicesException(
122: "Couldn't create proxy user for cty: "
123: + _communityID, e);
124: }
125:
126: }
127:
128: /**
129: * Delete the proxy calendar user for the community. Use JDAPI to connect to DA, using the params defined
130: * in the SSO adapter config with provided config name.
131: */
132: public void deleteCalProxyUser() throws SharedServicesException {
133:
134: String userUid = _calUtils.getProxyUser(_communityID);
135: try {
136:
137: DAConnection con = getConnection();
138: DABusinessOrganization org = getBusinessOrgForConfiguredDomain(con);
139: DAUser user = findUserInOrgByUID(org, userUid);
140: if (user != null) {
141: org.deleteUser(user);
142: if (logger.isLoggable(Level.FINE)) {
143: logger.fine("Deleted Proxy User: " + userUid);
144: }
145: } else {
146: logger.info("Proxy user: " + userUid
147: + " already deleted");
148: }
149:
150: } catch (Exception e) {
151: throw new SharedServicesException(
152: "Couldn't delete proxy user for cty: "
153: + _communityID, e);
154: }
155:
156: }
157:
158: /**
159: * Get the domain of the member.
160: *
161: * Check if already in cache, and if not,
162: * iterate over all business orgs, and sunPreferredDomain of the one
163: * that is the longest suffix of the mbr id.
164: *
165: * @param The community member id (user dn).
166: */
167: public String getDomainOfMember(String memberID)
168: throws SharedServicesException {
169:
170: String domain = (String) _usersDomain.get(memberID);
171:
172: if (domain == null) {
173:
174: try {
175:
176: if (logger.isLoggable(Level.FINE)) {
177: logger.fine("Domain not in cache -- Mbr: "
178: + memberID);
179: }
180:
181: DAConnection con = getConnection();
182: DABusinessOrganization org = getMembersOrganization(
183: con, memberID);
184: domain = org.getAttribute(DAConstants.DOMAIN_NAME)
185: .getFirstValue();
186: _usersDomain.put(memberID, domain);
187:
188: } catch (DAException e) {
189: throw new SharedServicesException(
190: "Couldn't get domain of mbr: " + memberID, e);
191: }
192:
193: }
194:
195: if (logger.isLoggable(Level.FINE)) {
196: logger.fine("Found domain -- Mbr: " + memberID
197: + ", domain: " + domain);
198: }
199:
200: return domain;
201: }
202:
203: /**
204: * Sets the mail attribute for a user entry, if not already set.
205: *
206: * To get around JDAPI's checks throwing exceptions, it is necessary to set the correct
207: * objectclass values first.
208: */
209: public void setMailAttributeForMember(String memberID) {
210:
211: try {
212:
213: DAConnection con = getConnection();
214: DABusinessOrganization org = getMembersOrganization(con,
215: memberID);
216:
217: // Get the user (clean set of atts)
218: DAUser user = con.getUser(memberID);
219:
220: String mail = user.getFirstValue(DAConstants.MAIL_ATTR);
221: if (mail == null) {
222:
223: // First set the correct values for objectclass (only if not present)
224: Vector newOCValues = new Vector();
225: List oldOCValues = Arrays.asList(user
226: .getAttributeValues("objectclass"));
227:
228: addValueIfNotAlreadyPresent("inetlocalmailrecipient",
229: oldOCValues, newOCValues);
230: addValueIfNotAlreadyPresent("ipuser", oldOCValues,
231: newOCValues);
232: addValueIfNotAlreadyPresent("inetsubscriber",
233: oldOCValues, newOCValues);
234: addValueIfNotAlreadyPresent("inetmailuser",
235: oldOCValues, newOCValues);
236: addValueIfNotAlreadyPresent("userpresenceprofile",
237: oldOCValues, newOCValues);
238:
239: if (newOCValues.size() > 0) {
240: String[] values = new String[newOCValues.size()];
241: for (int i = 0; i < newOCValues.size(); i++) {
242: values[i] = (String) newOCValues.elementAt(i);
243: }
244: user.addValuesToAttribute("objectclass", values);
245: org.modifyUser(user);
246: }
247:
248: // Get the user (clean set of atts)
249: user = con.getUser(memberID);
250:
251: String domain = org
252: .getFirstValue(DAConstants.DOMAIN_NAME);
253: if (domain == null) {
254: domain = "DUMMY.COM"; // shouldn't happen
255: }
256: String uid = user.getFirstValue(DAConstants.UID);
257: if (uid == null) {
258: uid = "foo"; // shouldn't happen
259: }
260: mail = uid + "@" + domain;
261: user.setAttributeValues(DAConstants.MAIL_ATTR, mail);
262: user.setAttributeValues(
263: DAConstants.MAIL_DELIVERY_OPTION, "mailbox");
264: user.setAttributeValues(DAConstants.MAIL_USER_STATUS,
265: "active");
266: org.modifyUser(user);
267:
268: if (logger.isLoggable(Level.FINE)) {
269: logger.fine("Set mail for mbr: " + memberID
270: + " to " + mail);
271: }
272:
273: }
274:
275: } catch (Exception e) {
276: // Log the error, but don't abandon mbr provisioning
277: logger.warning("Couldn't set mail attribute for mbr: "
278: + memberID + " ex: " + e.getMessage());
279: }
280:
281: };
282:
283: // Convenience method: does a end with b, ignoring case ?
284: private static boolean endsWithIgnoreCase(String a, String b) {
285: if ((a.length() >= b.length()) && a.regionMatches(true, // ignore case
286: a.length() - b.length(), // offset of region to compare, in a
287: b, 0, // from beginning of b
288: b.length())) {
289: return true;
290: } else {
291: return false;
292: }
293: }
294:
295: // add the value to the new values list, if not present in the old values list
296: private static void addValueIfNotAlreadyPresent(String value,
297: List existingValues, List newValues) {
298: if (!existingValues.contains(value)) {
299: newValues.add(value);
300: }
301: }
302:
303: // get a connection based upon the cached config props
304: private DAConnection getConnection() throws DAException {
305: return DAConnection
306: .authenticate(
307: _configProps
308: .getProperty(SharedCalendarUtils.CONFIG_PROP_daHost),
309: Integer
310: .parseInt(_configProps
311: .getProperty(SharedCalendarUtils.CONFIG_PROP_daPort)),
312: _configProps
313: .getProperty(SharedCalendarUtils.CONFIG_PROP_daProxyUid),
314: _configProps
315: .getProperty(SharedCalendarUtils.CONFIG_PROP_daProxyPassword),
316: false);
317: }
318:
319: // Find the business org whose DN is the immediate container of the member
320: private DABusinessOrganization getMembersOrganization(
321: DAConnection con, String memberID) throws DAException,
322: SharedServicesException {
323:
324: // Get all business orgs, and select the org whose dn is the largest suffix of the mbr id
325: DABusinessOrganization[] orgs = con.getBusinessOrganization();
326:
327: DABusinessOrganization targetOrg = null;
328: for (int i = 0; i < orgs.length; i++) {
329: DABusinessOrganization org = orgs[i];
330: if (logger.isLoggable(Level.FINER)) {
331: logger.fine("Bis Org: " + org.getDN());
332: }
333:
334: if (endsWithIgnoreCase(memberID, org.getDN())) {
335: if (targetOrg == null) {
336: targetOrg = org;
337: } else {
338: if (endsWithIgnoreCase(org.getDN(), targetOrg
339: .getDN())) {
340: // org is more specific (a child), so it is new target
341: targetOrg = org;
342: }
343: }
344: }
345: }
346:
347: if (targetOrg == null) {
348: throw new SharedServicesException(
349: "Couldn't find a matching org for mbr: " + memberID);
350: }
351:
352: return targetOrg;
353:
354: }
355:
356: // Get all business orgs, and select the one whose 'sunPreferredDomain' (canonical domain name)
357: // attr value corresponds to the configured domain
358: // (sunPreferredDomain will always be set to the cal domain, for cal hosted domains)
359: private DABusinessOrganization getBusinessOrgForConfiguredDomain(
360: DAConnection con) throws DAException,
361: SharedServicesException {
362:
363: DABusinessOrganization[] orgs = con.getBusinessOrganization();
364: DABusinessOrganization targetOrg = null;
365: String domain = _configProps
366: .getProperty(SharedCalendarUtils.CONFIG_PROP_daDomain);
367: for (int i = 0; i < orgs.length; i++) {
368: DABusinessOrganization org = orgs[i];
369: DAAttribute domainAttr = org
370: .getAttribute(DAConstants.DOMAIN_NAME);
371: String orgDomain = null;
372: if (domainAttr != null) {
373: orgDomain = domainAttr.getFirstValue();
374: }
375: if (logger.isLoggable(Level.FINER)) {
376: logger.finer("DABizOrg: " + org.getName() + " domain: "
377: + orgDomain);
378: }
379: if (orgDomain != null
380: && (orgDomain.equalsIgnoreCase(domain))) {
381: targetOrg = org;
382: }
383: }
384: if (targetOrg == null) {
385: throw new SharedServicesException(
386: "Couldn't find a matching org for cty: "
387: + _communityID + ", domain: " + domain);
388: }
389: return targetOrg;
390:
391: }
392:
393: // Retrieve the user within the org by uid
394: private DAUser findUserInOrgByUID(DABusinessOrganization org,
395: String uid) throws DAException {
396:
397: DAUser user = null;
398: Map filter = new HashMap();
399: filter.put(DAConstants.UID, uid);
400: DASearchResults rslts = org.searchUsers(new DASearchConstraint(
401: org.getDN(), DASearchConstraint.SUBTREE_SCOPE, filter));
402: if (rslts.hasMoreElements()) {
403: // assume that there is only one user with the uid
404: user = (DAUser) rslts.nextElement();
405: }
406: return user;
407:
408: }
409:
410: }
|