001/* 002 * Copyright 2010 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.externaldata.data.ldap; 017 018import java.util.ArrayList; 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.List; 023import java.util.Map; 024 025import javax.naming.directory.SearchControls; 026import javax.naming.directory.SearchResult; 027 028import org.apache.commons.lang.StringUtils; 029 030import org.ametys.core.datasource.DataSourceClientInteraction.DataSourceType; 031import org.ametys.core.util.ldap.AbstractLDAPConnector; 032import org.ametys.core.util.ldap.ScopeEnumerator; 033import org.ametys.plugins.externaldata.data.DataInclusionException; 034import org.ametys.plugins.externaldata.data.DataSourceFactory; 035import org.ametys.plugins.externaldata.data.Query.ResultType; 036import org.ametys.runtime.plugin.component.PluginAware; 037 038/** 039 * LDAP Data Source factory. 040 */ 041public class LdapDataSourceFactory extends AbstractLDAPConnector implements DataSourceFactory<LdapQuery, LdapQueryResult>, PluginAware 042{ 043 /** The relative DN for users */ 044 public static final String QUERY_CONFIGURATION_RELATIVE_DN = "relativeDN"; 045 046 /** The search scope of the query */ 047 public static final String QUERY_CONFIGURATION_SCOPE = "scope"; 048 049 /** The LDAp attributes to return */ 050 public static final String QUERY_CONFIGURATION_ATTRIBUTES = "attributes"; 051 052 /** Constraint query parameter. */ 053 public static final String QUERY_CONFIGURATION_CONSTRAINT = "constraint"; 054 055 /** Query configuration parameters. */ 056 public static final List<String> QUERY_CONFIGURATION_PARAMETERS = Arrays.asList( 057 QUERY_CONFIGURATION_RELATIVE_DN, 058 QUERY_CONFIGURATION_SCOPE, 059 QUERY_CONFIGURATION_ATTRIBUTES, 060 QUERY_CONFIGURATION_CONSTRAINT); 061 062 private String _id; 063 064 @Override 065 public void setPluginInfo(String pluginName, String featureName, String id) 066 { 067 _id = id; 068 } 069 070 @Override 071 public Collection<DataSourceType> getHandledTypes() 072 { 073 return Collections.singleton(DataSourceType.LDAP); 074 } 075 076 077 @Override 078 public Collection<String> getQueryConfigurationParameters(String type) 079 { 080 return QUERY_CONFIGURATION_PARAMETERS; 081 } 082 083 084 @Override 085 public LdapQuery buildQuery(String id, String type, String name, String description, ResultType resultType, String dataSourceId, Map<String, String> additionalConfiguration) throws DataInclusionException 086 { 087 String relativeDN = StringUtils.defaultString(additionalConfiguration.get(QUERY_CONFIGURATION_RELATIVE_DN)); 088 String attributes = StringUtils.defaultString(additionalConfiguration.get(QUERY_CONFIGURATION_ATTRIBUTES)); 089 String constraint = StringUtils.defaultString(additionalConfiguration.get(QUERY_CONFIGURATION_CONSTRAINT)); 090 String scope = StringUtils.defaultString(additionalConfiguration.get(QUERY_CONFIGURATION_SCOPE)); 091 092// if (StringUtils.isBlank(attributes)) 093// { 094// throw new DataInclusionException("Impossible to build the LDAP query : returning attributes must be provided"); 095// } 096 097 LdapQuery query = new LdapQuery(); 098 099 query.setId(id); 100 query.setFactory(this._id); 101 query.setName(name); 102 query.setDescription(description); 103 query.setResultType(resultType); 104 query.setDataSourceId(dataSourceId); 105 106 query.setRelativeDN(relativeDN); 107 query.setAttributes(attributes); 108 query.setConstraint(constraint); 109 query.setScope(scope); 110 111 return query; 112 } 113 114 @Override 115 public LdapQueryResult execute(LdapQuery query, Map<String, String> parameterValues) throws DataInclusionException 116 { 117 return execute(query, parameterValues, 0, Integer.MAX_VALUE); 118 } 119 120 public LdapQueryResult execute(LdapQuery query, Map<String, String> parameterValues, int offset, int limit) throws DataInclusionException 121 { 122 List<SearchResult> results = null; 123 try 124 { 125 String dataSourceId = query.getDataSourceId(); 126 _delayedInitialize(dataSourceId); 127 128 Map<String, String> attributeMap = query.getAttributesAsMap(); 129 130 int paramCount = query.getParameters().size(); 131 Object[] values = new Object[paramCount]; 132 133 // Replace all the parameters by "{x}" placeholders and fill the parameter values array. 134 int paramIndex = 0; 135 String constraint = query.getConstraint(); 136 for (String paramName : query.getParameters().keySet()) 137 { 138 if (parameterValues.containsKey(paramName)) 139 { 140 constraint = constraint.replaceAll("\\$\\{" + paramName + "(\\[[^\\]]*\\])?\\}", "{" + paramIndex + "}"); 141 values[paramIndex] = parameterValues.get(paramName); 142 paramIndex++; 143 } 144 else 145 { 146 String regexp = "\\([^()=,\\s]*=[^$()]*\\$\\{" + paramName + "(\\[[^\\]]*\\])?\\}[^\\)]*\\)"; 147 constraint = constraint.replaceAll(regexp, ""); 148 } 149 } 150 151 // Search filter. 152 StringBuilder filter = new StringBuilder(); 153 // filter.append("(&").append(_dataSource.getFilter()); 154 if (StringUtils.isNotBlank(constraint)) 155 { 156 filter.append(constraint); 157 } 158 159 List<String> columnLabels = new ArrayList<>(attributeMap.keySet()); 160 161 // Create the controls : the attributes to return are the values of the map. 162 SearchControls controls = _getSearchControls(attributeMap.values(), query.getScope()); 163 164 // Execute the search. 165 results = _search(query.getRelativeDN(), filter.toString(), values, controls, offset, limit); 166 167 // Extract and return the results. 168 LdapQueryResult queryResult = new LdapQueryResult(results, columnLabels, attributeMap); 169 170 return queryResult; 171 } 172 catch (Exception e) 173 { 174 throw new DataInclusionException("Unable to execute the LDAP query.", e); 175 } 176 } 177 178 /** 179 * Get the LDAP search controls. 180 * @param attributes the attributes to return. 181 * @param scopeStr the scope as a String. 182 * @return the search controls. 183 * @throws DataInclusionException If an error occurred 184 */ 185 protected SearchControls _getSearchControls(Collection<String> attributes, String scopeStr) throws DataInclusionException 186 { 187 // Paramètres de recherche 188 SearchControls controls = new SearchControls(); 189 190 String[] attrArray = attributes.toArray(new String[attributes.size()]); 191 192 controls.setReturningAttributes(attrArray); 193 194 controls.setSearchScope(_getScope(scopeStr)); 195 196 return controls; 197 } 198 199 /** 200 * Get the scope as an integer (handlable by the SearchControls) from the scope string. 201 * @param scopeStr the scope string. 202 * @return the scope as an integer. 203 * @throws DataInclusionException If an error occurred 204 */ 205 protected int _getScope(String scopeStr) throws DataInclusionException 206 { 207 try 208 { 209 return ScopeEnumerator.parseScope(scopeStr); 210 } 211 catch (IllegalArgumentException e) 212 { 213 throw new DataInclusionException("Unable to parse scope", e); 214 } 215 } 216}