1 package com.atlassian.user.impl.ldap.adaptor;
2
3 import com.atlassian.user.EntityException;
4 import com.atlassian.user.Group;
5 import com.atlassian.user.impl.EntityMissingException;
6 import com.atlassian.user.impl.RepositoryException;
7 import com.atlassian.user.impl.ldap.LDAPEntity;
8 import com.atlassian.user.impl.ldap.LDAPGroupFactory;
9 import com.atlassian.user.impl.ldap.properties.LdapSearchProperties;
10 import com.atlassian.user.impl.ldap.repository.LdapContextFactory;
11 import com.atlassian.user.impl.ldap.search.LDAPPagerInfo;
12 import com.atlassian.user.impl.ldap.search.LdapFilterFactory;
13 import com.atlassian.user.impl.ldap.search.page.LDAPEntityPager;
14 import com.atlassian.user.search.page.Pager;
15 import com.atlassian.user.util.LDAPUtils;
16 import com.atlassian.util.profiling.UtilTimerStack;
17 import com.opensymphony.util.TextUtils;
18 import net.sf.ldaptemplate.support.filter.EqualsFilter;
19 import net.sf.ldaptemplate.support.filter.Filter;
20 import org.apache.log4j.Logger;
21
22 import javax.naming.NamingEnumeration;
23 import javax.naming.NamingException;
24 import javax.naming.directory.Attributes;
25 import javax.naming.directory.DirContext;
26 import javax.naming.directory.SearchControls;
27 import javax.naming.directory.SearchResult;
28 import java.text.MessageFormat;
29
30 public abstract class AbstractLDAPGroupAdaptor implements LDAPGroupAdaptor
31 {
32 protected final Logger log = Logger.getLogger(this.getClass());
33
34 protected final LdapSearchProperties searchProperties;
35 private final LdapFilterFactory filterFactory;
36
37 protected final LdapContextFactory repository;
38 protected final LDAPGroupFactory groupFactory;
39
40 protected AbstractLDAPGroupAdaptor(LdapContextFactory repo, LdapSearchProperties searchProperties,
41 LDAPGroupFactory groupFactory, LdapFilterFactory filterFactory)
42 {
43 this.repository = repo;
44 this.searchProperties = searchProperties;
45 this.filterFactory = filterFactory;
46 this.groupFactory = groupFactory;
47 }
48
49 public Group getGroup(String name) throws EntityException
50 {
51 DirContext ctx = null;
52 NamingEnumeration<SearchResult> enume;
53 Group group = null;
54
55 String filter = constructGroupSearchFilter(name).encode();
56 String baseDn = searchProperties.getBaseGroupNamespace();
57
58 try
59 {
60 ctx = repository.getLDAPContext();
61 if (log.isDebugEnabled())
62 log.debug("AbstractLDAPGroupAdapter.getGroup:" + filter);
63
64 enume = ctx.search(baseDn, filter,
65 LDAPUtils.createSearchControls(new String[]{searchProperties.getGroupnameAttribute()}, searchProperties.isGroupSearchScopeAllDepths(),
66 searchProperties.getTimeLimitMillis()));
67 if (enume == null) return null;
68
69 while (enume.hasMoreElements())
70 {
71 SearchResult result = enume.nextElement();
72 Attributes attrs = result.getAttributes();
73 group = groupFactory.getGroup(attrs, result.getName());
74 }
75 }
76 catch (NamingException e)
77 {
78 String msg = "Exception when retrieving LDAP group {0} (base DN: {1}, filter: {2})";
79 throw new RepositoryException(MessageFormat.format(msg, name, baseDn, filter), e);
80 }
81 finally
82 {
83 try
84 {
85 if (ctx != null) ctx.close();
86 }
87 catch (NamingException e)
88 {
89 log.warn("Failed to close LDAP connection after search for group: " + name, e);
90 }
91 }
92
93 return group;
94 }
95
96 public Pager<Group> getGroups() throws EntityException
97 {
98 LDAPPagerInfo ldapPagerInfo = getGroupEntries();
99
100 return new LDAPEntityPager<Group>(repository, groupFactory, ldapPagerInfo);
101 }
102
103 public LDAPPagerInfo getGroupEntries() throws EntityException
104 {
105 return getGroupEntries("*");
106 }
107
108 public LDAPPagerInfo getGroupEntries(String groupName) throws EntityException
109 {
110 return getGroupEntries(groupName, null, null);
111 }
112
113 public LDAPPagerInfo getGroupEntries(String[] attributesToReturn, Filter additionalSearchFilter)
114 throws EntityException
115 {
116 return getGroupEntries("*", attributesToReturn, additionalSearchFilter);
117 }
118
119
120
121
122
123
124 public LDAPPagerInfo getGroupEntries(String groupName, String[] attributesToReturn, Filter additionalSearchFilter)
125 throws RepositoryException
126 {
127 Filter searchFilter = constructGroupSearchFilter(groupName, additionalSearchFilter);
128 return search(searchFilter, attributesToReturn);
129 }
130
131
132
133
134
135 public LDAPPagerInfo search(Filter searchFilter) throws RepositoryException
136 {
137 return search(searchFilter, null);
138 }
139
140
141
142
143
144
145
146 public LDAPPagerInfo search(Filter filter, String[] attributesToReturn) throws RepositoryException
147 {
148 if (UtilTimerStack.isActive())
149 UtilTimerStack.push(this.getClass().getName() + "_search(" + filter + ")");
150
151 try
152 {
153 if (attributesToReturn == null)
154 attributesToReturn = new String[]{searchProperties.getGroupnameAttribute()};
155
156 Filter groupSearchFilter = filterFactory.getGroupSearchFilter();
157 if (filter != null)
158 groupSearchFilter = LDAPUtils.makeAndFilter(groupSearchFilter, filter);
159
160 SearchControls ctls = LDAPUtils.createSearchControls(
161 attributesToReturn, searchProperties.isGroupSearchScopeAllDepths(),
162 searchProperties.getTimeLimitMillis());
163 NamingEnumeration<SearchResult> groupSearchEnume = null;
164
165 if (UtilTimerStack.isActive())
166 UtilTimerStack.push(this.getClass().getName() + "_search_JNDI_RAW_(" + groupSearchFilter + ")");
167 DirContext ctx = null;
168 try
169 {
170 ctx = repository.getLDAPContext();
171
172 log.debug("Searching for groups using base name space:" + searchProperties.getBaseGroupNamespace() +
173 " and encoded filter " + groupSearchFilter.encode());
174
175 groupSearchEnume = ctx.search(searchProperties.getBaseGroupNamespace(), groupSearchFilter.encode(), ctls);
176
177 if (groupSearchEnume.hasMore())
178 log.debug("found at least one group");
179 else
180 log.debug("no groups found");
181 }
182 catch (NamingException e)
183 {
184 throw new RepositoryException(e);
185 }
186 finally
187 {
188 if (UtilTimerStack.isActive())
189 UtilTimerStack.pop(this.getClass().getName() + "_search_JNDI_RAW_(" + groupSearchFilter + ")");
190
191 try
192 {
193 if (ctx != null) ctx.close();
194 }
195 catch (NamingException e)
196 {
197 log.warn("Exception trying to close LDAP context, possible resource leak", e);
198 }
199 }
200
201 return new LDAPPagerInfo(groupSearchEnume, groupSearchFilter,
202 searchProperties.getBaseGroupNamespace(), searchProperties.isGroupSearchScopeAllDepths(),
203 attributesToReturn, searchProperties.getTimeLimitMillis());
204 }
205 finally
206 {
207 if (UtilTimerStack.isActive())
208 UtilTimerStack.pop(this.getClass().getName() + "_search(" + filter + ")");
209 }
210 }
211
212 protected Filter constructGroupSearchFilter(String name)
213 {
214 return constructGroupSearchFilter(name, null);
215 }
216
217 protected Filter constructGroupSearchFilter(String name, Filter patternToAnd)
218 {
219 Filter searchFilter = null;
220
221 if (TextUtils.stringSet(name) && !"*".equals(name))
222 searchFilter = new EqualsFilter(searchProperties.getGroupnameAttribute(), name);
223
224 searchFilter = addGroupSearchFilter(searchFilter);
225
226 if (patternToAnd != null)
227 return LDAPUtils.makeAndFilter(searchFilter, patternToAnd);
228
229 return searchFilter;
230 }
231
232 private Filter addGroupSearchFilter(Filter searchFilter)
233 {
234 return LDAPUtils.makeAndFilter(searchFilter, filterFactory.getGroupSearchFilter());
235 }
236
237
238
239
240
241
242
243
244
245
246
247
248 protected String getFirstPhraseFromDN(String dn)
249 {
250 String[] rdns = dn.split(",");
251 String[] firstPhrase = rdns[0].split("=");
252
253 return firstPhrase[1];
254 }
255
256
257 public String getGroupDN(String groupName) throws EntityException
258 {
259 LDAPPagerInfo ldapPagerInfo = getGroupEntries(groupName, new String[]{"dn"}, null);
260
261 if (!ldapPagerInfo.getNamingEnumeration().hasMoreElements())
262 throw new EntityMissingException("Could not get DN for group [" + groupName + "]");
263
264 SearchResult result = (SearchResult) ldapPagerInfo.getNamingEnumeration().nextElement();
265
266 String groupDN = result.getName();
267
268 if (groupDN.indexOf(searchProperties.getBaseGroupNamespace()) == -1)
269 groupDN = groupDN + "," + searchProperties.getBaseGroupNamespace();
270
271 return groupDN;
272 }
273
274 public String getGroupDN(Group group) throws EntityException
275 {
276 if (group instanceof LDAPEntity)
277 {
278 LDAPEntity entity = (LDAPEntity) group;
279 return entity.getDistinguishedName();
280 }
281 else
282 throw new IllegalArgumentException("Group is not an LDAPEntity");
283 }
284
285 public LDAPGroupFactory getGroupFactory()
286 {
287 return groupFactory;
288 }
289 }