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