001: /**
002: * $RCSfile$
003: * $Revision: $
004: * $Date: $
005: *
006: * Copyright (C) 2006 Jive Software. All rights reserved.
007: *
008: * This software is published under the terms of the GNU Public License (GPL),
009: * a copy of which is included in this distribution.
010: */package org.jivesoftware.admin;
011:
012: import org.jivesoftware.util.Log;
013: import org.jivesoftware.util.Base64;
014: import org.jivesoftware.openfire.ldap.LdapManager;
015: import org.xmpp.packet.JID;
016:
017: import javax.naming.NamingEnumeration;
018: import javax.naming.NamingException;
019: import javax.naming.directory.*;
020: import javax.naming.ldap.Control;
021: import javax.naming.ldap.LdapContext;
022: import javax.naming.ldap.SortControl;
023: import java.io.IOException;
024: import java.text.MessageFormat;
025: import java.util.*;
026:
027: /**
028: * Class that assists during the testing of the user-ldap mapping.
029: *
030: * @author Gaston Dombiak
031: */
032: public class LdapUserTester {
033:
034: /**
035: * Constants to access user properties
036: */
037: public static final String NAME = "Name";
038: public static final String EMAIL = "Email";
039: public static final String FULL_NAME = "FullName";
040: public static final String NICKNAME = "Nickname";
041: public static final String BIRTHDAY = "Birthday";
042: public static final String PHOTO = "Photo";
043: public static final String HOME_STREET = "HomeStreet";
044: public static final String HOME_CITY = "HomeCity";
045: public static final String HOME_STATE = "HomeState";
046: public static final String HOME_ZIP = "HomeZip";
047: public static final String HOME_COUNTRY = "HomeCountry";
048: public static final String HOME_PHONE = "HomePhone";
049: public static final String HOME_MOBILE = "HomeMobile";
050: public static final String HOME_FAX = "HomeFax";
051: public static final String HOME_PAGER = "HomePager";
052: public static final String BUSINESS_STREET = "BusinessStreet";
053: public static final String BUSINESS_CITY = "BusinessCity";
054: public static final String BUSINESS_STATE = "BusinessState";
055: public static final String BUSINESS_ZIP = "BusinessZip";
056: public static final String BUSINESS_COUNTRY = "BusinessCountry";
057: public static final String BUSINESS_JOB_TITLE = "BusinessJobTitle";
058: public static final String BUSINESS_DEPARTMENT = "BusinessDepartment";
059: public static final String BUSINESS_PHONE = "BusinessPhone";
060: public static final String BUSINESS_MOBILE = "BusinessMobile";
061: public static final String BUSINESS_FAX = "BusinessFax";
062: public static final String BUSINESS_PAGER = "BusinessPager";
063:
064: private LdapManager manager;
065: private LdapUserProfile profile;
066:
067: public LdapUserTester(LdapManager manager, LdapUserProfile profile) {
068: this .manager = manager;
069: this .profile = profile;
070: }
071:
072: /**
073: * Returns a list of usernames with a sample of the users found in LDAP.
074: *
075: * @param maxSample the max size of the sample to return.
076: * @return a list of usernames with a sample of the users found in LDAP.
077: * @throws NamingException if something goes wrong....
078: */
079: public List<String> getSample(int maxSample) throws NamingException {
080: List<String> usernames = new ArrayList<String>();
081: LdapContext ctx = null;
082:
083: try {
084: ctx = manager.getContext();
085:
086: // Sort on username field.
087: Control[] searchControl;
088: try {
089: searchControl = new Control[] { new SortControl(
090: new String[] { manager.getUsernameField() },
091: Control.NONCRITICAL) };
092: } catch (IOException e) {
093: Log.error(e);
094: return Collections.emptyList();
095: }
096: ctx.setRequestControls(searchControl);
097:
098: // Search for the dn based on the username.
099: SearchControls searchControls = new SearchControls();
100: // See if recursive searching is enabled. Otherwise, only search one level.
101: if (manager.isSubTreeSearch()) {
102: searchControls
103: .setSearchScope(SearchControls.SUBTREE_SCOPE);
104: } else {
105: searchControls
106: .setSearchScope(SearchControls.ONELEVEL_SCOPE);
107: }
108: searchControls
109: .setReturningAttributes(new String[] { manager
110: .getUsernameField() });
111: // Limit results to those we'll need to process
112: searchControls.setCountLimit(maxSample);
113: String filter = MessageFormat.format(manager
114: .getSearchFilter(), "*");
115: NamingEnumeration answer = ctx.search("", filter,
116: searchControls);
117:
118: while (answer.hasMoreElements()) {
119: // Get the next userID.
120: String username = (String) ((SearchResult) answer
121: .next()).getAttributes().get(
122: manager.getUsernameField()).get();
123: // Escape username and add to results.
124: usernames.add(JID.escapeNode(username));
125: }
126: // Close the enumeration.
127: answer.close();
128: } finally {
129: try {
130: if (ctx != null) {
131: ctx.setRequestControls(null);
132: ctx.close();
133: }
134: } catch (Exception ignored) {
135: // Ignore.
136: }
137: }
138: return usernames;
139: }
140:
141: /**
142: * Returns a list of attributes and their LDAP values found in LDAP for the specified username.
143: *
144: * @param username the username of the user to get his attributes from LDAP.
145: * @return a list of attributes and their LDAP values found in LDAP for the specified username.
146: */
147: public Map<String, String> getAttributes(String username) {
148: Map<String, String> userAttributes = new HashMap<String, String>();
149: // Un-escape username.
150: username = JID.unescapeNode(username);
151: DirContext ctx = null;
152: try {
153: String userDN = manager.findUserDN(username);
154: // Build list of attributes to load from LDAP
155: Map<String, PropertyMapping> ldapMappings = getLdapAttributes();
156: Set<String> fields = new HashSet<String>();
157: for (PropertyMapping mapping : ldapMappings.values()) {
158: fields.addAll(mapping.getFields());
159: }
160: fields.add(manager.getUsernameField());
161: // Load records
162: ctx = manager.getContext(manager.getUsersBaseDN(username));
163: Attributes attrs = ctx.getAttributes(userDN, fields
164: .toArray(new String[] {}));
165: // Build answer
166: for (Map.Entry<String, PropertyMapping> entry : ldapMappings
167: .entrySet()) {
168: String attribute = entry.getKey();
169: PropertyMapping mapping = entry.getValue();
170: String value = mapping.getDisplayFormat();
171: for (String field : mapping.getFields()) {
172: Attribute ldapField = attrs.get(field);
173: if (ldapField != null) {
174: String answer;
175: Object ob = ldapField.get();
176: if (ob instanceof String) {
177: answer = (String) ob;
178: } else {
179: answer = Base64.encodeBytes((byte[]) ob);
180: }
181: value = value
182: .replace("{" + field + "}", answer);
183: }
184: }
185: userAttributes.put(attribute, value);
186: }
187: } catch (Exception e) {
188: Log.error(e);
189: // TODO something else?
190: } finally {
191: try {
192: if (ctx != null) {
193: ctx.close();
194: }
195: } catch (Exception ignored) {
196: // Ignore.
197: }
198: }
199: return userAttributes;
200: }
201:
202: private Map<String, PropertyMapping> getLdapAttributes() {
203: Map<String, PropertyMapping> map = new HashMap<String, PropertyMapping>();
204:
205: if (profile.getName() != null
206: && profile.getName().trim().length() > 0) {
207: map.put(NAME, new PropertyMapping(profile.getName()));
208: }
209: if (profile.getEmail() != null
210: && profile.getEmail().trim().length() > 0) {
211: map.put(EMAIL, new PropertyMapping(profile.getEmail()));
212: }
213: if (profile.getFullName() != null
214: && profile.getFullName().trim().length() > 0) {
215: map.put(FULL_NAME, new PropertyMapping(profile
216: .getFullName()));
217: }
218: if (profile.getNickname() != null
219: && profile.getNickname().trim().length() > 0) {
220: map.put(NICKNAME,
221: new PropertyMapping(profile.getNickname()));
222: }
223: if (profile.getBirthday() != null
224: && profile.getBirthday().trim().length() > 0) {
225: map.put(BIRTHDAY,
226: new PropertyMapping(profile.getBirthday()));
227: }
228: if (profile.getPhoto() != null
229: && profile.getPhoto().trim().length() > 0) {
230: map.put(PHOTO, new PropertyMapping(profile.getPhoto()));
231: }
232: if (profile.getHomeStreet() != null
233: && profile.getHomeStreet().trim().length() > 0) {
234: map.put(HOME_STREET, new PropertyMapping(profile
235: .getHomeStreet()));
236: }
237: if (profile.getHomeCity() != null
238: && profile.getHomeCity().trim().length() > 0) {
239: map.put(HOME_CITY, new PropertyMapping(profile
240: .getHomeCity()));
241: }
242: if (profile.getHomeState() != null
243: && profile.getHomeState().trim().length() > 0) {
244: map.put(HOME_STATE, new PropertyMapping(profile
245: .getHomeState()));
246: }
247: if (profile.getHomeZip() != null
248: && profile.getHomeZip().trim().length() > 0) {
249: map
250: .put(HOME_ZIP, new PropertyMapping(profile
251: .getHomeZip()));
252: }
253: if (profile.getHomeCountry() != null
254: && profile.getHomeCountry().trim().length() > 0) {
255: map.put(HOME_COUNTRY, new PropertyMapping(profile
256: .getHomeCountry()));
257: }
258: if (profile.getHomePhone() != null
259: && profile.getHomePhone().trim().length() > 0) {
260: map.put(HOME_PHONE, new PropertyMapping(profile
261: .getHomePhone()));
262: }
263: if (profile.getHomeMobile() != null
264: && profile.getHomeMobile().trim().length() > 0) {
265: map.put(HOME_MOBILE, new PropertyMapping(profile
266: .getHomeMobile()));
267: }
268: if (profile.getHomeFax() != null
269: && profile.getHomeFax().trim().length() > 0) {
270: map
271: .put(HOME_FAX, new PropertyMapping(profile
272: .getHomeFax()));
273: }
274: if (profile.getHomePager() != null
275: && profile.getHomePager().trim().length() > 0) {
276: map.put(HOME_PAGER, new PropertyMapping(profile
277: .getHomePager()));
278: }
279: if (profile.getBusinessStreet() != null
280: && profile.getBusinessStreet().trim().length() > 0) {
281: map.put(BUSINESS_STREET, new PropertyMapping(profile
282: .getBusinessStreet()));
283: }
284: if (profile.getBusinessCity() != null
285: && profile.getBusinessCity().trim().length() > 0) {
286: map.put(BUSINESS_CITY, new PropertyMapping(profile
287: .getBusinessCity()));
288: }
289: if (profile.getBusinessState() != null
290: && profile.getBusinessState().trim().length() > 0) {
291: map.put(BUSINESS_STATE, new PropertyMapping(profile
292: .getBusinessState()));
293: }
294: if (profile.getBusinessZip() != null
295: && profile.getBusinessZip().trim().length() > 0) {
296: map.put(BUSINESS_ZIP, new PropertyMapping(profile
297: .getBusinessZip()));
298: }
299: if (profile.getBusinessCountry() != null
300: && profile.getBusinessCountry().trim().length() > 0) {
301: map.put(BUSINESS_COUNTRY, new PropertyMapping(profile
302: .getBusinessCountry()));
303: }
304: if (profile.getBusinessJobTitle() != null
305: && profile.getBusinessJobTitle().trim().length() > 0) {
306: map.put(BUSINESS_JOB_TITLE, new PropertyMapping(profile
307: .getBusinessJobTitle()));
308: }
309: if (profile.getBusinessDepartment() != null
310: && profile.getBusinessDepartment().trim().length() > 0) {
311: map.put(BUSINESS_DEPARTMENT, new PropertyMapping(profile
312: .getBusinessDepartment()));
313: }
314: if (profile.getBusinessPhone() != null
315: && profile.getBusinessPhone().trim().length() > 0) {
316: map.put(BUSINESS_PHONE, new PropertyMapping(profile
317: .getBusinessPhone()));
318: }
319: if (profile.getBusinessMobile() != null
320: && profile.getBusinessMobile().trim().length() > 0) {
321: map.put(BUSINESS_MOBILE, new PropertyMapping(profile
322: .getBusinessMobile()));
323: }
324: if (profile.getBusinessFax() != null
325: && profile.getBusinessFax().trim().length() > 0) {
326: map.put(BUSINESS_FAX, new PropertyMapping(profile
327: .getBusinessFax()));
328: }
329: if (profile.getBusinessPager() != null
330: && profile.getBusinessPager().trim().length() > 0) {
331: map.put(BUSINESS_PAGER, new PropertyMapping(profile
332: .getBusinessPager()));
333: }
334:
335: return map;
336: }
337:
338: private static class PropertyMapping {
339: /**
340: * Format how user property is going to appear (e.g. {firstname}, {lastname}
341: */
342: private String displayFormat;
343: /**
344: * LDAP fields that compose the user property
345: */
346: private Collection<String> fields = new ArrayList<String>();
347:
348: public PropertyMapping(String displayFormat) {
349: this .displayFormat = displayFormat;
350:
351: StringTokenizer st = new StringTokenizer(displayFormat
352: .trim(), ", //{}");
353: while (st.hasMoreTokens()) {
354: fields.add(st.nextToken().replaceFirst(
355: "(\\{)([\\d\\D&&[^}]]+)(})", "$2"));
356: }
357: }
358:
359: public String getDisplayFormat() {
360: return displayFormat;
361: }
362:
363: public Collection<String> getFields() {
364: return fields;
365: }
366: }
367: }
|