1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.security.spi.impl.ldap;
18
19 import java.security.Principal;
20 import java.util.ArrayList;
21 import java.util.Collection;
22
23 import javax.naming.NamingEnumeration;
24 import javax.naming.NamingException;
25 import javax.naming.directory.Attribute;
26 import javax.naming.directory.Attributes;
27 import javax.naming.directory.DirContext;
28 import javax.naming.directory.SearchControls;
29 import javax.naming.directory.SearchResult;
30
31 import org.apache.commons.lang.StringUtils;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.jetspeed.security.GroupPrincipal;
35 import org.apache.jetspeed.security.SecurityException;
36 import org.apache.jetspeed.security.UserPrincipal;
37 import org.apache.jetspeed.security.impl.GroupPrincipalImpl;
38 import org.apache.jetspeed.security.impl.RolePrincipalImpl;
39 import org.apache.jetspeed.security.impl.UserPrincipalImpl;
40
41 /***
42 * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao
43 * @author <a href="mailto:mike.long@dataline.com">Mike Long </a>, <a
44 * href="mailto:dlestrat@apache.org">David Le Strat</a>
45 */
46 public abstract class LdapPrincipalDaoImpl extends AbstractLdapDao implements LdapPrincipalDao
47 {
48 /*** The logger. */
49 private static final Log logger = LogFactory.getLog(LdapPrincipalDaoImpl.class);
50
51
52 /***
53 * <p>
54 * Default constructor.
55 * </p>
56 *
57 * @throws SecurityException A {@link SecurityException}.
58 */
59 public LdapPrincipalDaoImpl() throws SecurityException
60 {
61 super();
62 }
63
64 /***
65 * <p>
66 * Initializes the dao.
67 * </p>
68 *
69 * @param ldapConfig Holds the ldap binding configuration.
70 * @throws SecurityException A {@link SecurityException}.
71 */
72 public LdapPrincipalDaoImpl(LdapBindingConfig ldapConfig) throws SecurityException
73 {
74 super(ldapConfig);
75 }
76
77 /***
78 * <p>
79 * A template method for creating a concrete principal object.
80 * </p>
81 *
82 * @param principalUid The principal uid.
83 * @return A concrete principal object.
84 */
85 protected abstract Principal makePrincipal(String principalUid);
86
87 /***
88 * <p>
89 * A template method for defining the attributes for a particular LDAP class.
90 * </p>
91 *
92 * @param principalUid The principal uid.
93 * @return The LDAP attributes object for the particular class.
94 */
95 protected abstract Attributes defineLdapAttributes(final String principalUid);
96
97 /***
98 * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao#create(java.lang.String)
99 */
100 public void create(final String principalUid) throws SecurityException
101 {
102 Attributes attrs = defineLdapAttributes(principalUid);
103 logger.debug("creating principal with " + attrs);
104 try
105 {
106 String userDn = getEntryPrefix() + "=" + principalUid;
107 if (!StringUtils.isEmpty(getDnSuffix()))
108 userDn+="," + getDnSuffix();
109
110 logger.debug("userDn = " + userDn);
111
112 ctx.createSubcontext(userDn, attrs);
113 if (logger.isDebugEnabled())
114 {
115 logger.debug("Creating user dn: " + userDn);
116 }
117 }
118 catch (NamingException e)
119 {
120 throw new SecurityException(e);
121 }
122 }
123
124 /***
125 * <p>
126 * Builds the dn suffix.
127 * </p>
128 *
129 * @return The dn suffix.
130 */
131 protected abstract String getDnSuffix();
132
133 /***
134 * <p>
135 * Builds the dn suffix.
136 * </p>
137 *
138 * @return The dn suffix.
139 */
140 protected abstract String getUidAttributeForPrincipal();
141
142
143 /***
144 * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao#delete(java.lang.String)
145 */
146 public void delete(final String principalUid) throws SecurityException
147 {
148 String dn = lookupByUid(principalUid);
149
150 if (dn == null)
151 {
152 return;
153 }
154
155 String rdn;
156 try
157 {
158 rdn = getSubcontextName(dn);
159
160
161 ctx.destroySubcontext(rdn);
162 }
163 catch (NamingException e)
164 {
165 throw new SecurityException(e);
166 }
167 }
168
169 /***
170 * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao#convertUidToLdapAcceptableName(java.lang.String)
171 */
172 public String convertUidToLdapAcceptableName(String fullPath)
173 {
174 if (logger.isErrorEnabled())
175 {
176 logger.debug("Principal fullPath:" + fullPath);
177 }
178 String ldapAcceptableName = fullPath;
179 if (null == fullPath)
180 {
181 return ldapAcceptableName;
182 }
183 else if (fullPath.indexOf(UserPrincipal.PREFS_USER_ROOT) >= 0)
184 {
185 ldapAcceptableName = convertUidWithoutSlashes(UserPrincipalImpl.getPrincipalNameFromFullPath(fullPath));
186 }
187 else if (fullPath.indexOf(GroupPrincipal.PREFS_GROUP_ROOT) >= 0)
188 {
189 ldapAcceptableName = convertUidWithoutSlashes(GroupPrincipalImpl.getPrincipalNameFromFullPath(fullPath));
190 }
191 else if (fullPath.indexOf(GroupPrincipal.PREFS_ROLE_ROOT) >= 0)
192 {
193 ldapAcceptableName = convertUidWithoutSlashes(RolePrincipalImpl.getPrincipalNameFromFullPath(fullPath));
194 }
195 if (logger.isErrorEnabled())
196 {
197 logger.debug("Ldap acceptable name:" + ldapAcceptableName);
198 }
199
200 return ldapAcceptableName;
201 }
202
203 /***
204 * <p>
205 * Returns a well formed uid for LDAP.
206 * </p>
207 *
208 * @param uid The uid.
209 * @return The well formed uid.
210 */
211 private String convertUidWithoutSlashes(String uid)
212 {
213 String uidWithSlashed = uid.replaceAll("/", "&");
214 return uidWithSlashed;
215 }
216
217 /***
218 * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao#find(java.lang.String,
219 * java.lang.String)
220 */
221 public Principal[] find(final String principalUid, String principalType) throws SecurityException
222 {
223 try
224 {
225 SearchControls cons = setSearchControls();
226 NamingEnumeration searchResults = searchByWildcardedUid(convertUidToLdapAcceptableName(principalUid), cons);
227 Collection principals = new ArrayList();
228
229 enumerateOverSearchResults(searchResults, principals);
230
231 return convertPrincipalListToArray(principals);
232 }
233 catch (NamingException e)
234 {
235 throw new SecurityException(e);
236 }
237 }
238
239 /***
240 * <p>
241 * Converts a list of principals to an array of principals.
242 * </p>
243 *
244 * @param principals The list of principals.
245 * @return The array of principals.
246 */
247 private Principal[] convertPrincipalListToArray(Collection principals)
248 {
249 return (Principal[]) principals.toArray(new Principal[principals.size()]);
250 }
251
252 /***
253 * <p>
254 * Build the user principal by enumerating through the search results.
255 * </p>
256 *
257 * @param searchResults The {@link NamingEnumeration} of results.
258 * @param principals The collection of user principals.
259 * @throws NamingException Throws a {@link NamingException}.
260 */
261 private void enumerateOverSearchResults(NamingEnumeration searchResults, Collection principals)
262 throws NamingException
263 {
264 while (searchResults.hasMore())
265 {
266 SearchResult searchResult = (SearchResult) searchResults.next();
267 buildPrincipal(principals, searchResult);
268 }
269 }
270
271 /***
272 * @param principals The collection of principals.
273 * @param searchResult The {@link SearchResult}
274 * @throws NamingException Throws a {@link NamingException}.
275 */
276 private void buildPrincipal(Collection principals, SearchResult searchResult) throws NamingException
277 {
278 if (searchResult.getObject() instanceof DirContext)
279 {
280 Attributes atts = searchResult.getAttributes();
281
282 String uid = (String) getAttribute(getUidAttributeForPrincipal(), atts).getAll().next();
283 Principal principal = makePrincipal(uid);
284
285 principals.add(principal);
286
287 }
288 }
289
290 /***
291 * @param attributeName The attribute name.
292 * @param userAttributes The user {@link Attributes}.
293 * @return The {@link Attribute}.
294 * @throws NamingException Throws a {@link NamingException}.
295 */
296 protected Attribute getAttribute(String attributeName, Attributes userAttributes) throws NamingException
297 {
298 for (NamingEnumeration ae = userAttributes.getAll(); ae.hasMore();)
299 {
300 Attribute attr = (Attribute) ae.next();
301
302 if (attr.getID().equalsIgnoreCase(attributeName))
303 {
304 return attr;
305 }
306 }
307 return null;
308 }
309
310 protected String getSearchDomain() {
311 return this.getUserFilterBase();
312 }
313
314 protected String[] parseAttr(String attr, String replace) {
315 attr = StringUtils.replace(attr, "{u}", replace);
316 int index = attr.indexOf('=');
317
318 if (index != -1){
319 return new String[]{
320 attr.substring(0,index),
321 index < attr.length() -1 ? attr.substring(index + 1) : null};
322 } else {
323 return new String[]{ attr, null };
324 }
325 }
326
327 protected String getGroupDN(String groupPrincipalUid) {
328 return getGroupDN(groupPrincipalUid,true);
329 }
330
331 protected String getGroupDN(String groupPrincipalUid, boolean includeBaseDN) {
332 String groupDN = getGroupIdAttribute() + "=" + groupPrincipalUid;
333 if (!StringUtils.isEmpty(getGroupFilterBase()))
334 groupDN += "," + getGroupFilterBase();
335 if (includeBaseDN && !StringUtils.isEmpty(getRootContext()))
336 groupDN += "," + getRootContext();
337 return groupDN;
338 }
339
340 protected String getRoleDN(String rolePrincipalUid) {
341 return getRoleDN(rolePrincipalUid,true);
342 }
343
344 protected String getRoleDN(String rolePrincipalUid, boolean includeBaseDN) {
345 String roleDN = getRoleIdAttribute() + "=" + rolePrincipalUid;
346 if (!StringUtils.isEmpty(getRoleFilterBase()))
347 roleDN+="," + getRoleFilterBase();
348 if (includeBaseDN && !StringUtils.isEmpty(getRootContext()))
349 roleDN+="," + getRootContext();
350 return roleDN;
351 }
352
353 protected String getUserDN(String userPrincipalUid) {
354 return getUserDN(userPrincipalUid,true);
355 }
356
357 protected String getUserDN(String userPrincipalUid, boolean includeBaseDN) {
358 String userDN = getUserIdAttribute() + "=" + userPrincipalUid;
359 if (!StringUtils.isEmpty(getUserFilterBase()))
360 userDN += "," + getUserFilterBase();
361 if (includeBaseDN && !StringUtils.isEmpty(getRootContext()))
362 userDN += "," + getRootContext();
363 return userDN;
364 }
365
366
367
368
369 }