1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kim.dao.impl;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
20 import org.kuali.rice.kim.api.identity.entity.Entity;
21 import org.kuali.rice.kim.api.identity.entity.EntityDefault;
22 import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
23 import org.kuali.rice.kim.api.identity.principal.Principal;
24 import org.kuali.rice.kim.api.identity.privacy.EntityPrivacyPreferences;
25 import org.kuali.rice.kim.dao.LdapPrincipalDao;
26 import org.kuali.rice.kim.impl.identity.PersonImpl;
27 import org.kuali.rice.kim.util.Constants;
28 import org.springframework.ldap.SizeLimitExceededException;
29 import org.springframework.ldap.core.ContextMapper;
30 import org.springframework.ldap.core.ContextMapperCallbackHandler;
31 import org.springframework.ldap.core.DistinguishedName;
32 import org.springframework.ldap.core.LdapTemplate;
33 import org.springframework.ldap.filter.AndFilter;
34 import org.springframework.ldap.filter.LikeFilter;
35 import org.springframework.ldap.filter.NotFilter;
36 import org.springframework.ldap.filter.OrFilter;
37
38 import javax.naming.directory.SearchControls;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.regex.Matcher;
45 import java.util.regex.Pattern;
46
47 import static org.kuali.rice.core.util.BufferedLogger.*;
48 import static org.kuali.rice.kns.lookup.LookupUtils.getSearchResultsLimit;
49
50
51
52
53
54
55
56 public class LdapPrincipalDaoImpl implements LdapPrincipalDao {
57 private Constants kimConstants;
58 private LdapTemplate template;
59 private ParameterService parameterService;
60
61
62 private Map<String, ContextMapper> contextMappers;
63
64 public LdapPrincipalDaoImpl() {
65 }
66
67
68
69
70 public Principal getPrincipal(String principalId) {
71 if (principalId == null) {
72 return null;
73 }
74 Map<String, Object> criteria = new HashMap();
75 criteria.put(getKimConstants().getKimLdapIdProperty(), principalId);
76 List<Principal> results = search(Principal.class, criteria);
77
78 if (results.size() > 0) {
79 return results.get(0);
80 }
81
82 return null;
83 }
84
85
86
87
88 public Principal getPrincipalByName(String principalName) {
89 if (principalName == null) {
90 return null;
91 }
92 Map<String, Object> criteria = new HashMap();
93 criteria.put(getKimConstants().getKimLdapNameProperty(), principalName);
94 List<Principal> results = search(Principal.class, criteria);
95
96 if (results.size() > 0) {
97 return results.get(0);
98 }
99
100 return null;
101 }
102
103 public <T> List<T> search(Class<T> type, Map<String, Object> criteria) {
104 AndFilter filter = new AndFilter();
105
106 for (Map.Entry<String, Object> entry : criteria.entrySet()) {
107
108 if (entry.getValue() == null) {
109 entry.setValue("null");
110 }
111 if (entry.getValue() instanceof Iterable) {
112 OrFilter orFilter = new OrFilter();
113 for (String value : (Iterable<String>) entry.getValue()) {
114 if (value.startsWith("!")) {
115 orFilter.or(new NotFilter(new LikeFilter(entry.getKey(), value.substring(1))));
116 } else {
117 orFilter.or(new LikeFilter(entry.getKey(), value));
118 }
119 }
120 filter.and(orFilter);
121 }
122 else {
123 if (((String)entry.getValue()).startsWith("!")) {
124 filter.and(new NotFilter(new LikeFilter(entry.getKey(), ((String)entry.getValue()).substring(1))));
125 } else {
126 filter.and(new LikeFilter(entry.getKey(), (String) entry.getValue()));
127 }
128 }
129 };
130
131 info("Using filter ", filter);
132
133 debug("Looking up mapper for ", type.getSimpleName());
134 final ContextMapper customMapper = contextMappers.get(type.getSimpleName());
135
136 ContextMapperCallbackHandler callbackHandler = new CustomContextMapperCallbackHandler(customMapper);
137
138 try {
139 getLdapTemplate().search(DistinguishedName.EMPTY_PATH,
140 filter.encode(),
141 getSearchControls(), callbackHandler);
142 }
143 catch (SizeLimitExceededException e) {
144
145 }
146
147 return callbackHandler.getList();
148 }
149
150 protected SearchControls getSearchControls() {
151 SearchControls retval = new SearchControls();
152 retval.setCountLimit(getSearchResultsLimit(PersonImpl.class).longValue());
153 retval.setSearchScope(SearchControls.SUBTREE_SCOPE);
154 return retval;
155 }
156
157
158
159
160
161
162
163 public Entity getEntity(String entityId) {
164 if (entityId == null) {
165 return null;
166 }
167 Map<String, Object> criteria = new HashMap();
168 criteria.put(getKimConstants().getKimLdapIdProperty(), entityId);
169
170 List<Entity> results = search(Entity.class, criteria);
171
172 debug("Got results from info lookup ", results, " with size ", results.size());
173
174 if (results.size() > 0) {
175 return results.get(0);
176 }
177
178 return null;
179 }
180
181
182
183
184
185
186 public Entity getEntityByPrincipalId(String principalId) {
187 if (principalId == null) {
188 return null;
189 }
190 final Principal principal = getPrincipal(principalId);
191 if (principal != null && !StringUtils.isBlank(principal.getEntityId())) {
192 return getEntity(principal.getEntityId());
193 }
194 return null;
195 }
196
197 public EntityDefault getEntityDefault(String entityId) {
198 if (entityId == null) {
199 return null;
200 }
201 Map<String, Object> criteria = new HashMap();
202 criteria.put(getKimConstants().getKimLdapIdProperty(), entityId);
203
204 List<EntityDefault> results = search(EntityDefault.class, criteria);
205
206 debug("Got results from info lookup ", results, " with size ", results.size());
207
208 if (results.size() > 0) {
209 return results.get(0);
210 }
211
212 return null;
213 }
214
215
216
217
218
219
220 public EntityDefault getEntityDefaultByPrincipalId(String principalId) {
221 return getEntityDefault(principalId);
222 }
223
224 public EntityDefault getEntityDefaultByPrincipalName(String principalName) {
225 Map<String, Object> criteria = new HashMap();
226 criteria.put(getKimConstants().getKimLdapNameProperty(), principalName);
227
228 List<EntityDefault> results = search(EntityDefault.class, criteria);
229 if (results.size() > 0) {
230 return results.get(0);
231 }
232
233 return null;
234 }
235
236 public Entity getEntityByPrincipalName(String principalName) {
237 Map<String, Object> criteria = new HashMap();
238 criteria.put(getKimConstants().getKimLdapNameProperty(), principalName);
239
240 List<Entity> results = search(Entity.class, criteria);
241 if (results.size() > 0) {
242 return results.get(0);
243 }
244
245 return null;
246 }
247
248 public List<EntityDefault> lookupEntityDefault(Map<String,String> searchCriteria, boolean unbounded) {
249 List<EntityDefault> results = new ArrayList();
250 Map<String, Object> criteria = getLdapLookupCriteria(searchCriteria);
251
252 results = search(EntityDefault.class, criteria);
253
254 return results;
255 }
256
257 public List<String> lookupEntityIds(Map<String,String> searchCriteria) {
258 final List<String> results = new ArrayList<String>();
259 final Map<String, Object> criteria = getLdapLookupCriteria(searchCriteria);
260
261 for (final Entity entity : search(Entity.class, criteria)) {
262 results.add(entity.getId());
263 }
264
265 return results;
266 }
267
268
269
270
271
272
273 protected Map<String, Object> getLdapLookupCriteria(Map<String, String> searchCriteria) {
274 Map<String, Object> criteria = new HashMap();
275 boolean hasTaxId = false;
276
277 for (Map.Entry<String, String> criteriaEntry : searchCriteria.entrySet()) {
278 debug(String.format("Searching with criteria %s = %s", criteriaEntry.getKey(), criteriaEntry.getValue()));
279 String valueName = criteriaEntry.getKey();
280 Object value = criteriaEntry.getValue();
281 if (!criteriaEntry.getValue().equals("*")) {
282 valueName = String.format("%s.%s", criteriaEntry.getKey(), criteriaEntry.getValue());
283 }
284
285 if (!value.equals("*") && isMapped(valueName)) {
286 value = getLdapValue(valueName);
287 debug(value, " mapped to valueName ", valueName);
288 }
289
290 if (isMapped(criteriaEntry.getKey())) {
291 debug(String.format("Setting attribute to (%s, %s)",
292 getLdapAttribute(criteriaEntry.getKey()),
293 value));
294 final String key = getLdapAttribute(criteriaEntry.getKey());
295 if (!criteria.containsKey(key)) {
296 criteria.put(key, value);
297 }
298 }
299 else if (criteriaEntry.getKey().equalsIgnoreCase(getKimConstants().getExternalIdProperty())) {
300 criteria.put(getKimConstants().getKimLdapIdProperty(), value);
301 }
302 else if (criteriaEntry.getKey().equalsIgnoreCase(getKimConstants().getExternalIdTypeProperty())
303 && value.toString().equals(getKimConstants().getTaxExternalIdTypeCode())) {
304 hasTaxId = true;
305 }
306 }
307 return criteria;
308 }
309
310 public EntityPrivacyPreferences getEntityPrivacyPreferences(String entityId) {
311 if (entityId == null) {
312 return null;
313 }
314 Map<String, Object> criteria = new HashMap();
315 criteria.put(getKimConstants().getKimLdapIdProperty(), entityId);
316
317 List<EntityPrivacyPreferences> results = search(EntityPrivacyPreferences.class, criteria);
318 if (results.size() > 0) {
319 return results.get(0);
320 }
321
322 return null;
323 }
324
325 public Map<String, EntityNamePrincipalName> getDefaultNamesForPrincipalIds(List<String> principalIds) {
326 Map<String, Object> criteria = new HashMap();
327 Map<String, EntityNamePrincipalName> retval = new HashMap();
328 criteria.put(getKimConstants().getKimLdapIdProperty(), principalIds);
329
330 List<EntityNamePrincipalName> results = search(EntityNamePrincipalName.class, criteria);
331
332 for (EntityNamePrincipalName nameInfo : results) {
333 retval.put(nameInfo.getPrincipalName(), nameInfo);
334 }
335 return retval;
336 }
337
338 public Map<String, EntityNamePrincipalName> getDefaultNamesForEntityIds(List<String> entityIds) {
339 return getDefaultNamesForPrincipalIds(entityIds);
340 }
341
342 protected Matcher getKimAttributeMatcher(String kimAttribute) {
343 String mappedParamValue = getParameterService().getParameterValueAsString(getKimConstants().getParameterNamespaceCode(),
344 getKimConstants().getParameterDetailTypeCode(),
345 getKimConstants().getMappedParameterName());
346
347 String regexStr = String.format("(%s|.*;%s)=([^=;]*).*", kimAttribute, kimAttribute);
348 debug("Matching KIM attribute with regex ", regexStr);
349 Matcher retval = Pattern.compile(regexStr).matcher(mappedParamValue);
350
351 if (!retval.matches()) {
352 mappedParamValue = getParameterService().getParameterValueAsString(getKimConstants().getParameterNamespaceCode(),
353 getKimConstants().getParameterDetailTypeCode(),
354 getKimConstants().getMappedValuesName());
355 retval = Pattern.compile(regexStr).matcher(mappedParamValue);
356 }
357
358 return retval;
359 }
360
361 protected boolean isMapped(String kimAttribute) {
362 debug("Matching " + kimAttribute);
363 debug("Does ", kimAttribute, " match? ", getKimAttributeMatcher(kimAttribute).matches());
364 return getKimAttributeMatcher(kimAttribute).matches();
365 }
366
367 protected String getLdapAttribute(String kimAttribute) {
368 Matcher matcher = getKimAttributeMatcher(kimAttribute);
369 debug("Does ", kimAttribute, " match? ", matcher.matches());
370 if (matcher.matches()) {
371 return matcher.group(2);
372 } else {
373 return null;
374 }
375 }
376
377 protected Object getLdapValue(String kimAttribute) {
378 Matcher matcher = getKimAttributeMatcher(kimAttribute);
379 debug("Does ", kimAttribute, " match? ", matcher.matches());
380 if (!matcher.matches()) {
381 return null;
382 }
383 String value = matcher.group(2);
384
385
386 if (value.contains(",")) {
387 return Arrays.asList(value.split(","));
388 }
389
390 return value;
391 }
392
393 public void setKimConstants(Constants constants) {
394 this.kimConstants = constants;
395 }
396
397 public Constants getKimConstants() {
398 return kimConstants;
399 }
400
401 public ParameterService getParameterService() {
402 return this.parameterService;
403 }
404
405 public void setParameterService(ParameterService service) {
406 this.parameterService = service;
407 }
408
409 public LdapTemplate getLdapTemplate() {
410 return template;
411 }
412
413 public void setLdapTemplate(LdapTemplate template) {
414 this.template = template;
415 }
416
417 public Map<String, ContextMapper> getContextMappers() {
418 return this.contextMappers;
419 }
420
421 public void setContextMappers(final Map<String, ContextMapper> contextMappers) {
422 this.contextMappers = contextMappers;
423 }
424
425
426
427
428
429
430
431 private static final class CustomContextMapperCallbackHandler extends ContextMapperCallbackHandler {
432 public CustomContextMapperCallbackHandler(ContextMapper mapper) {
433 super(mapper);
434 }
435 }
436 }