/* * Copyright (C) 2005-2008 Jive Software. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.admin; import org.jivesoftware.util.Base64; import org.jivesoftware.openfire.ldap.LdapManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xmpp.packet.JID; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.*; import javax.naming.ldap.Control; import javax.naming.ldap.LdapContext; import javax.naming.ldap.SortControl; import java.io.IOException; import java.text.MessageFormat; import java.util.*; /** * Class that assists during the testing of the user-ldap mapping. * * @author Gaston Dombiak */ public class LdapUserTester { private static final Logger Log = LoggerFactory.getLogger(LdapUserTester.class); /** * Constants to access user properties */ public static final String NAME = "Name"; public static final String EMAIL = "Email"; public static final String FULL_NAME = "FullName"; public static final String NICKNAME = "Nickname"; public static final String BIRTHDAY = "Birthday"; public static final String PHOTO = "Photo"; public static final String HOME_STREET = "HomeStreet"; public static final String HOME_CITY = "HomeCity"; public static final String HOME_STATE = "HomeState"; public static final String HOME_ZIP = "HomeZip"; public static final String HOME_COUNTRY = "HomeCountry"; public static final String HOME_PHONE = "HomePhone"; public static final String HOME_MOBILE = "HomeMobile"; public static final String HOME_FAX = "HomeFax"; public static final String HOME_PAGER = "HomePager"; public static final String BUSINESS_STREET = "BusinessStreet"; public static final String BUSINESS_CITY = "BusinessCity"; public static final String BUSINESS_STATE = "BusinessState"; public static final String BUSINESS_ZIP = "BusinessZip"; public static final String BUSINESS_COUNTRY = "BusinessCountry"; public static final String BUSINESS_JOB_TITLE = "BusinessJobTitle"; public static final String BUSINESS_DEPARTMENT = "BusinessDepartment"; public static final String BUSINESS_PHONE = "BusinessPhone"; public static final String BUSINESS_MOBILE = "BusinessMobile"; public static final String BUSINESS_FAX = "BusinessFax"; public static final String BUSINESS_PAGER = "BusinessPager"; private LdapManager manager; private LdapUserProfile profile; public LdapUserTester(LdapManager manager, LdapUserProfile profile) { this.manager = manager; this.profile = profile; } /** * Returns a list of usernames with a sample of the users found in LDAP. * * @param maxSample the max size of the sample to return. * @return a list of usernames with a sample of the users found in LDAP. * @throws NamingException if something goes wrong.... */ public List<String> getSample(int maxSample) throws NamingException { List<String> usernames = new ArrayList<>(); LdapContext ctx = null; try { ctx = manager.getContext(); // Sort on username field. Control[] searchControl; try { searchControl = new Control[]{ new SortControl(new String[]{manager.getUsernameField()}, Control.NONCRITICAL) }; } catch (IOException e) { Log.error(e.getMessage(), e); return Collections.emptyList(); } ctx.setRequestControls(searchControl); // Search for the dn based on the username. SearchControls searchControls = new SearchControls(); // See if recursive searching is enabled. Otherwise, only search one level. if (manager.isSubTreeSearch()) { searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); } else { searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE); } searchControls.setReturningAttributes(new String[]{manager.getUsernameField()}); // Limit results to those we'll need to process searchControls.setCountLimit(maxSample); String filter = MessageFormat.format(manager.getSearchFilter(), "*"); NamingEnumeration answer = ctx.search("", filter, searchControls); while (answer.hasMoreElements()) { // Get the next userID. String username = (String) ((SearchResult) answer.next()).getAttributes().get( manager.getUsernameField()).get(); // Escape username and add to results. usernames.add(JID.escapeNode(username)); } // Close the enumeration. answer.close(); } finally { try { if (ctx != null) { ctx.setRequestControls(null); ctx.close(); } } catch (Exception ignored) { // Ignore. } } return usernames; } /** * Returns a list of attributes and their LDAP values found in LDAP for the specified username. * * @param username the username of the user to get his attributes from LDAP. * @return a list of attributes and their LDAP values found in LDAP for the specified username. */ public Map<String, String> getAttributes(String username) { Map<String, String> userAttributes = new HashMap<>(); // Un-escape username. username = JID.unescapeNode(username); DirContext ctx = null; try { String userDN = manager.findUserDN(username); // Build list of attributes to load from LDAP Map<String, PropertyMapping> ldapMappings = getLdapAttributes(); Set<String> fields = new HashSet<>(); for (PropertyMapping mapping : ldapMappings.values()) { fields.addAll(mapping.getFields()); } fields.add(manager.getUsernameField()); // Load records ctx = manager.getContext(manager.getUsersBaseDN(username)); Attributes attrs = ctx.getAttributes(userDN, fields.toArray(new String[]{})); // Build answer for (Map.Entry<String, PropertyMapping> entry : ldapMappings.entrySet()) { String attribute = entry.getKey(); PropertyMapping mapping = entry.getValue(); String value = mapping.getDisplayFormat(); for (String field : mapping.getFields()) { Attribute ldapField = attrs.get(field); if (ldapField != null) { String answer; Object ob = ldapField.get(); if (ob instanceof String) { answer = (String) ob; } else { answer = Base64.encodeBytes((byte[]) ob); } value = value.replace("{" + field + "}", answer); } } userAttributes.put(attribute, value); } } catch (Exception e) { Log.error(e.getMessage(), e); // TODO something else? } finally { try { if (ctx != null) { ctx.close(); } } catch (Exception ignored) { // Ignore. } } return userAttributes; } private Map<String, PropertyMapping> getLdapAttributes() { Map<String, PropertyMapping> map = new HashMap<>(); if (profile.getName() != null && profile.getName().trim().length() > 0) { map.put(NAME, new PropertyMapping(profile.getName())); } if (profile.getEmail() != null && profile.getEmail().trim().length() > 0) { map.put(EMAIL, new PropertyMapping(profile.getEmail())); } if (profile.getFullName() != null && profile.getFullName().trim().length() > 0) { map.put(FULL_NAME, new PropertyMapping(profile.getFullName())); } if (profile.getNickname() != null && profile.getNickname().trim().length() > 0) { map.put(NICKNAME, new PropertyMapping(profile.getNickname())); } if (profile.getBirthday() != null && profile.getBirthday().trim().length() > 0) { map.put(BIRTHDAY, new PropertyMapping(profile.getBirthday())); } if (profile.getPhoto() != null && profile.getPhoto().trim().length() > 0) { map.put(PHOTO, new PropertyMapping(profile.getPhoto())); } if (profile.getHomeStreet() != null && profile.getHomeStreet().trim().length() > 0) { map.put(HOME_STREET, new PropertyMapping(profile.getHomeStreet())); } if (profile.getHomeCity() != null && profile.getHomeCity().trim().length() > 0) { map.put(HOME_CITY, new PropertyMapping(profile.getHomeCity())); } if (profile.getHomeState() != null && profile.getHomeState().trim().length() > 0) { map.put(HOME_STATE, new PropertyMapping(profile.getHomeState())); } if (profile.getHomeZip() != null && profile.getHomeZip().trim().length() > 0) { map.put(HOME_ZIP, new PropertyMapping(profile.getHomeZip())); } if (profile.getHomeCountry() != null && profile.getHomeCountry().trim().length() > 0) { map.put(HOME_COUNTRY, new PropertyMapping(profile.getHomeCountry())); } if (profile.getHomePhone() != null && profile.getHomePhone().trim().length() > 0) { map.put(HOME_PHONE, new PropertyMapping(profile.getHomePhone())); } if (profile.getHomeMobile() != null && profile.getHomeMobile().trim().length() > 0) { map.put(HOME_MOBILE, new PropertyMapping(profile.getHomeMobile())); } if (profile.getHomeFax() != null && profile.getHomeFax().trim().length() > 0) { map.put(HOME_FAX, new PropertyMapping(profile.getHomeFax())); } if (profile.getHomePager() != null && profile.getHomePager().trim().length() > 0) { map.put(HOME_PAGER, new PropertyMapping(profile.getHomePager())); } if (profile.getBusinessStreet() != null && profile.getBusinessStreet().trim().length() > 0) { map.put(BUSINESS_STREET, new PropertyMapping(profile.getBusinessStreet())); } if (profile.getBusinessCity() != null && profile.getBusinessCity().trim().length() > 0) { map.put(BUSINESS_CITY, new PropertyMapping(profile.getBusinessCity())); } if (profile.getBusinessState() != null && profile.getBusinessState().trim().length() > 0) { map.put(BUSINESS_STATE, new PropertyMapping(profile.getBusinessState())); } if (profile.getBusinessZip() != null && profile.getBusinessZip().trim().length() > 0) { map.put(BUSINESS_ZIP, new PropertyMapping(profile.getBusinessZip())); } if (profile.getBusinessCountry() != null && profile.getBusinessCountry().trim().length() > 0) { map.put(BUSINESS_COUNTRY, new PropertyMapping(profile.getBusinessCountry())); } if (profile.getBusinessJobTitle() != null && profile.getBusinessJobTitle().trim().length() > 0) { map.put(BUSINESS_JOB_TITLE, new PropertyMapping(profile.getBusinessJobTitle())); } if (profile.getBusinessDepartment() != null && profile.getBusinessDepartment().trim().length() > 0) { map.put(BUSINESS_DEPARTMENT, new PropertyMapping(profile.getBusinessDepartment())); } if (profile.getBusinessPhone() != null && profile.getBusinessPhone().trim().length() > 0) { map.put(BUSINESS_PHONE, new PropertyMapping(profile.getBusinessPhone())); } if (profile.getBusinessMobile() != null && profile.getBusinessMobile().trim().length() > 0) { map.put(BUSINESS_MOBILE, new PropertyMapping(profile.getBusinessMobile())); } if (profile.getBusinessFax() != null && profile.getBusinessFax().trim().length() > 0) { map.put(BUSINESS_FAX, new PropertyMapping(profile.getBusinessFax())); } if (profile.getBusinessPager() != null && profile.getBusinessPager().trim().length() > 0) { map.put(BUSINESS_PAGER, new PropertyMapping(profile.getBusinessPager())); } return map; } private static class PropertyMapping { /** * Format how user property is going to appear (e.g. {firstname}, {lastname} */ private String displayFormat; /** * LDAP fields that compose the user property */ private Collection<String> fields = new ArrayList<>(); public PropertyMapping(String displayFormat) { this.displayFormat = displayFormat; StringTokenizer st = new StringTokenizer(displayFormat.trim(), ", //{}"); while (st.hasMoreTokens()) { fields.add(st.nextToken().replaceFirst("(\\{)([\\d\\D&&[^}]]+)(})", "$2")); } } public String getDisplayFormat() { return displayFormat; } public Collection<String> getFields() { return fields; } } }