001/* 002 * Copyright 2016 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.contentio.synchronize.impl; 017 018import java.util.Arrays; 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025import java.util.stream.Collectors; 026 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.commons.lang.StringUtils; 030import org.slf4j.Logger; 031 032import org.ametys.core.user.directory.UserDirectory; 033import org.ametys.core.user.population.UserPopulation; 034import org.ametys.core.user.population.UserPopulationDAO; 035import org.ametys.core.util.JSONUtils; 036import org.ametys.plugins.contentio.synchronize.AbstractSynchronizableContentsCollection; 037import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollection; 038import org.ametys.plugins.core.impl.user.directory.JdbcUserDirectory; 039import org.ametys.plugins.core.impl.user.directory.LdapUserDirectory; 040 041/** 042 * Implementation of {@link SynchronizableContentsCollection} to be synchronized with a {@link UserPopulation} of the CMS. 043 */ 044public class UserPopulationSynchronizableContentsCollection extends AbstractSynchronizableContentsCollection 045{ 046 /** Name of parameter holding the id of population */ 047 protected static final String __PARAM_POPULATION_ID = "populationId"; 048 /** Name of parameter for the login metadata */ 049 protected static final String __PARAM_LOGIN_METADATA_NAME = "login"; 050 /** Name of parameter for the firstname metadata */ 051 protected static final String __PARAM_FIRSTNAME_METADATA_NAME = "firstname"; 052 /** Name of parameter for the lastname metadata */ 053 protected static final String __PARAM_LASTNAME_METADATA_NAME = "lastname"; 054 /** Name of parameter for the email metadata */ 055 protected static final String __PARAM_EMAIL_METADATA_NAME = "email"; 056 /** Name of parameter holding the fields mapping */ 057 protected static final String __PARAM_MAPPING = "mapping"; 058 /** Name of parameter into mapping holding the synchronized property */ 059 protected static final String __PARAM_MAPPING_SYNCHRO = "synchro"; 060 /** Name of parameter into mapping holding the path of metadata */ 061 protected static final String __PARAM_MAPPING_METADATA_REF = "metadata-ref"; 062 /** Name of parameter into mapping holding the remote attribute */ 063 protected static final String __PARAM_MAPPING_ATTRIBUTE_PREFIX = "attribute-"; 064 065 private static final int __LDAP_DEFAULT_PAGE_SIZE = 1000; 066 067 /** The DAO for user populations */ 068 protected UserPopulationDAO _userPopulationDAO; 069 /** The service manager */ 070 protected ServiceManager _manager; 071 /** The JSON utils */ 072 protected JSONUtils _jsonUtils; 073 074 @Override 075 public void service(ServiceManager manager) throws ServiceException 076 { 077 super.service(manager); 078 _userPopulationDAO = (UserPopulationDAO) manager.lookup(UserPopulationDAO.ROLE); 079 _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE); 080 _manager = manager; 081 } 082 083 @Override 084 protected void _internalPopulate(Logger logger) 085 { 086 UserPopulation population = _userPopulationDAO.getUserPopulation(getPopulationId()); 087 088 for (UserDirectory userDirectory : population.getUserDirectories()) 089 { 090 if (userDirectory instanceof LdapUserDirectory) 091 { 092 importContentFromLdap((LdapUserDirectory) userDirectory, logger); 093 } 094 else if (userDirectory instanceof JdbcUserDirectory) 095 { 096 // TODO handle SQL case 097// _importFromSql((JdbcUserDirectory) userDirectory, logger); 098 } 099 } 100 } 101 102 /** 103 * Populate contents from a LDAP user directory of the population 104 * @param userDirectory The LDAP user directory 105 * @param logger The logger 106 */ 107 protected void importContentFromLdap(LdapUserDirectory userDirectory, Logger logger) 108 { 109 Map<String, Object> ldapParameterValues = userDirectory.getParameterValues(); 110 String dataSourceId = (String) ldapParameterValues.get(LdapUserDirectory.PARAM_DATASOURCE_ID); 111 String relativeDN = (String) ldapParameterValues.get(LdapUserDirectory.PARAM_USERS_RELATIVE_DN); 112 String filter = (String) ldapParameterValues.get(LdapUserDirectory.PARAM_USERS_OBJECT_FILTER); 113 String searchScope = (String) ldapParameterValues.get(LdapUserDirectory.PARAM_USERS_SEARCH_SCOPE); 114 String loginAttr = (String) ldapParameterValues.get(LdapUserDirectory.PARAM_USERS_LOGIN_ATTRIBUTE); 115 String firstNameAttr = (String) ldapParameterValues.get(LdapUserDirectory.PARAM_USERS_FIRSTNAME_ATTRIBUTE); 116 String lastNameAttr = (String) ldapParameterValues.get(LdapUserDirectory.PARAM_USERS_LASTNAME_ATTRIBUTE); 117 String emailAttr = (String) ldapParameterValues.get(LdapUserDirectory.PARAM_USERS_EMAIL_ATTRIBUTE); 118 119 Map<String, List<String>> udMapping = getMapping().get(userDirectory.getId()); 120 if (udMapping == null) 121 { 122 udMapping = new HashMap<>(); 123 } 124 udMapping.put(getLoginMetadata(), Collections.singletonList(loginAttr)); 125 udMapping.put(getFirstNameMetadata(), Collections.singletonList(firstNameAttr)); 126 udMapping.put(getLastNameMetadata(), Collections.singletonList(lastNameAttr)); 127 udMapping.put(getEmailMetadata(), Collections.singletonList(emailAttr)); 128 129 try 130 { 131 LDAPCollectionHelper ldapHelper = (LDAPCollectionHelper) _manager.lookup(LDAPCollectionHelper.ROLE); 132 ldapHelper._delayedInitialize(dataSourceId); 133 134 Map<String, Map<String, List<Object>>> remoteValuesByContent = ldapHelper.search(getId(), __LDAP_DEFAULT_PAGE_SIZE, relativeDN, filter, searchScope, udMapping, loginAttr, logger); 135 _nbError = ldapHelper.getNbErrors(); 136 _hasGlobalError = ldapHelper.hasGlobalError(); 137 138 for (String idValue : remoteValuesByContent.keySet()) 139 { 140 Map<String, List<Object>> remoteValues = remoteValuesByContent.get(idValue); 141 importContent(idValue, remoteValues, logger); 142 } 143 } 144 catch (Exception e) 145 { 146 logger.error("An error occured when importing from LDAP UserDirectory", e); 147 } 148 } 149 150 /** 151 * Get the id of the user population 152 * @return The id of user population 153 */ 154 public String getPopulationId() 155 { 156 return (String) _modelParamValues.get(__PARAM_POPULATION_ID); 157 } 158 159 @Override 160 public String getIdField() 161 { 162 return getLoginMetadata(); 163 } 164 165 /** 166 * Get the metadata name for the login 167 * @return The the metadata name for the login 168 */ 169 public String getLoginMetadata() 170 { 171 return (String) _modelParamValues.get(__PARAM_LOGIN_METADATA_NAME); 172 } 173 174 /** 175 * Get the metadata name for the first name 176 * @return The the metadata name for the first name 177 */ 178 public String getFirstNameMetadata() 179 { 180 return (String) _modelParamValues.get(__PARAM_FIRSTNAME_METADATA_NAME); 181 } 182 183 /** 184 * Get the metadata name for the last name 185 * @return The the metadata name for the last name 186 */ 187 public String getLastNameMetadata() 188 { 189 return (String) _modelParamValues.get(__PARAM_LASTNAME_METADATA_NAME); 190 } 191 192 /** 193 * Get the metadata name for the email 194 * @return The the metadata name for the email 195 */ 196 public String getEmailMetadata() 197 { 198 return (String) _modelParamValues.get(__PARAM_EMAIL_METADATA_NAME); 199 } 200 201 @Override 202 public Set<String> getExternalOnlyFields() 203 { 204 Set<String> extFields = new HashSet<>(); 205 206 String mappingAsString = (String) getParameterValues().get(__PARAM_MAPPING); 207 if (StringUtils.isNotEmpty(mappingAsString)) 208 { 209 List<Object> mappingAsList = _jsonUtils.convertJsonToList(mappingAsString); 210 for (Object object : mappingAsList) 211 { 212 @SuppressWarnings("unchecked") 213 Map<String, Object> field = (Map<String, Object>) object; 214 boolean isSynchronized = field.containsKey(__PARAM_MAPPING_SYNCHRO) ? (Boolean) field.get(__PARAM_MAPPING_SYNCHRO) : false; 215 if (!isSynchronized) 216 { 217 extFields.add((String) field.get(__PARAM_MAPPING_METADATA_REF)); 218 } 219 } 220 } 221 222 return extFields; 223 } 224 225 @Override 226 public Set<String> getLocalAndExternalFields() 227 { 228 Set<String> syncFields = new HashSet<>(); 229 230 String mappingAsString = (String) getParameterValues().get(__PARAM_MAPPING); 231 if (StringUtils.isNotEmpty(mappingAsString)) 232 { 233 List<Object> mappingAsList = _jsonUtils.convertJsonToList(mappingAsString); 234 for (Object object : mappingAsList) 235 { 236 @SuppressWarnings("unchecked") 237 Map<String, Object> field = (Map<String, Object>) object; 238 boolean isSynchronized = field.containsKey(__PARAM_MAPPING_SYNCHRO) ? (Boolean) field.get(__PARAM_MAPPING_SYNCHRO) : false; 239 if (isSynchronized) 240 { 241 syncFields.add((String) field.get(__PARAM_MAPPING_METADATA_REF)); 242 } 243 } 244 } 245 246 return syncFields; 247 } 248 249 /** 250 * Get the field mapping 251 * @return The mapping 252 */ 253 public Map<String, Map<String, List<String>>> getMapping() 254 { 255 Map<String, Map<String, List<String>>> mapping = new HashMap<>(); 256 257 String mappingAsString = (String) getParameterValues().get(__PARAM_MAPPING); 258 if (StringUtils.isNotEmpty(mappingAsString)) 259 { 260 List<Object> list = _jsonUtils.convertJsonToList(mappingAsString); 261 for (Object obj : list) 262 { 263 @SuppressWarnings("unchecked") 264 Map<String, Object> field = (Map<String, Object>) obj; 265 String metadataRef = (String) field.get(__PARAM_MAPPING_METADATA_REF); 266 267 String prefix = __PARAM_MAPPING_ATTRIBUTE_PREFIX; 268 for (String prefixedUserDirectoryKey : _getUserDirectoryKeys(field, prefix)) 269 { 270 String userDirectoryKey = prefixedUserDirectoryKey.substring(prefix.length()); 271 if (!mapping.containsKey(userDirectoryKey)) 272 { 273 mapping.put(userDirectoryKey, new HashMap<>()); 274 } 275 276 String[] attributes = ((String) field.get(prefixedUserDirectoryKey)).split(","); 277 278 Map<String, List<String>> userDirectoryMapping = mapping.get(userDirectoryKey); 279 userDirectoryMapping.put(metadataRef, Arrays.asList(attributes)); 280 } 281 } 282 } 283 284 return mapping; 285 } 286 287 private Set<String> _getUserDirectoryKeys(Map<String, Object> field, String prefix) 288 { 289 return field.keySet().stream() 290 .filter(name -> name.startsWith(prefix)) 291 .collect(Collectors.toSet()); 292 } 293}