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.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.avalon.framework.component.Component; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.commons.lang3.StringUtils; 027import org.slf4j.Logger; 028 029import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollection; 030import org.ametys.plugins.contentio.synchronize.impl.LDAPCollectionHelper.LDAPCollectionHelperSearchResult; 031import org.ametys.runtime.i18n.I18nizableText; 032 033/** 034 * Implementation of {@link SynchronizableContentsCollection} to be synchronized with a LDAP data source 035 */ 036public class LDAPSynchronizableContentsCollection extends AbstractDataSourceSynchronizableContentsCollection implements Component 037{ 038 private static final String __PARAM_LDAP_SCOPE = "scope"; 039 private static final String __PARAM_LDAP_RELATIVE_DN = "peopleDN"; 040 private static final String __PARAM_LDAP_FILTER = "baseFilter"; 041 042 /** The helper for LDAP connection */ 043 protected LDAPCollectionHelper _ldapHelper; 044 045 @Override 046 public void service(ServiceManager serviceManager) throws ServiceException 047 { 048 super.service(serviceManager); 049 _ldapHelper = (LDAPCollectionHelper) serviceManager.lookup(LDAPCollectionHelper.ROLE); 050 } 051 052 @Override 053 protected Map<String, Map<String, Object>> internalSearch(Map<String, Object> searchParameters, int offset, int limit, List<Object> sort, Logger logger) 054 { 055 // Sort is ignored in LDAP request 056 057 Map<String, List<String>> mapping = getMapping(); 058 Map<String, Map<String, Object>> searchResults = new HashMap<>(); 059 060 String idField = getIdField(); 061 List<String> remoteKeys = mapping.get(idField); 062 if (remoteKeys != null && remoteKeys.size() > 0) 063 { 064 // Filter from search parameters 065 String filter = getFilter(); 066 List<String> filters = new ArrayList<>(); 067 if (StringUtils.isNotEmpty(filter)) 068 { 069 filters.add(filter); 070 } 071 if (searchParameters != null) 072 { 073 for (String parameterName : searchParameters.keySet()) 074 { 075 filters.add(parameterName + "=" + searchParameters.get(parameterName)); 076 } 077 } 078 String filtersReduced = filters.stream().filter(StringUtils::isNotEmpty).map(s -> "(" + s + ")").reduce("", (s1, s2) -> s1 + s2); 079 if (!filtersReduced.isEmpty()) 080 { 081 filtersReduced = "(&" + filtersReduced + ")"; 082 } 083 084 try 085 { 086 String remoteKey = remoteKeys.get(0); 087 LDAPCollectionHelperSearchResult results = _ldapHelper.search(getId(), getRelativeDN(), filtersReduced, getSearchScope(), offset, limit, mapping, remoteKey, logger, getDataSourceId()); 088 089 searchResults = new HashMap<>(); 090 for (Map<String, Object> result : results.searchResults().values()) 091 { 092 Object sccValues = result.get(remoteKey); 093 String transformedId = checkAndTransformIdObjectValue(remoteKey, sccValues, logger); 094 if (transformedId != null) 095 { 096 result.put(SCC_UNIQUE_ID, transformedId); 097 result.put(remoteKey, List.of(transformedId)); 098 searchResults.put(transformedId, result); 099 } 100 } 101 102 _nbError = results.nbErrors(); 103 _hasGlobalError = results.hasGlobalError(); 104 } 105 catch (Exception e) 106 { 107 throw new RuntimeException("An error occured when importing from LDAP UserDirectory", e); 108 } 109 } 110 else 111 { 112 _nbError = 1; 113 logger.error("Missing LDAP attribute in mapping for field '{}' holding the unique identifier", idField); 114 } 115 116 return searchResults; 117 } 118 119 /** 120 * Check if the id object value is correct and transform it if needed 121 * @param remoteKey the remote key 122 * @param idObjectValue the id object value 123 * @param logger the logger 124 * @return The transformed id if the value is correct, null otherwise 125 */ 126 protected String checkAndTransformIdObjectValue(String remoteKey, Object idObjectValue, Logger logger) 127 { 128 Object objectValue = idObjectValue instanceof List<?> ? ((List<?>) idObjectValue).get(0) : idObjectValue; 129 if (objectValue == null || !(objectValue instanceof String)) 130 { 131 logger.warn("The content identifier is mandatory but there is no value for the key : " + remoteKey); 132 return null; 133 } 134 135 return objectValue.toString(); 136 } 137 138 /** 139 * Get the scope for LDAP search 140 * @return The scope 141 */ 142 protected String getSearchScope() 143 { 144 return (String) getParameterValues().get(__PARAM_LDAP_SCOPE); 145 } 146 147 /** 148 * Get the LDAP filter 149 * @return the filter 150 */ 151 protected String getFilter() 152 { 153 return (String) getParameterValues().get(__PARAM_LDAP_FILTER); 154 } 155 156 /** 157 * Get the LDAP relative DN 158 * @return the relative DN 159 */ 160 protected String getRelativeDN() 161 { 162 return (String) getParameterValues().get(__PARAM_LDAP_RELATIVE_DN); 163 } 164 165 @Override 166 protected void configureSearchModel() 167 { 168 for (String columnOrCriteria : _columnsAndCriteria) 169 { 170 _searchModelConfiguration.addCriterion(columnOrCriteria); 171 _searchModelConfiguration.addColumn(columnOrCriteria, new I18nizableText(columnOrCriteria), false); 172 } 173 } 174 175 @Override 176 protected Map<String, Map<String, List<Object>>> getRemoteValues(Map<String, Object> searchParameters, Logger logger) 177 { 178 Map<String, Map<String, List<Object>>> organizedResults = super.getRemoteValues(searchParameters, logger); 179 _ldapHelper.transformTypedAttributes(organizedResults, getContentType(), getMapping().keySet()); 180 return organizedResults; 181 } 182}