View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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             //if(!StringUtils.isEmpty(getSearchDomain()))
160             //	rdn+="," + getSearchDomain();
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 }