001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.security.spi.impl.ldap;
018:
019: import java.security.Principal;
020: import java.util.ArrayList;
021: import java.util.Collection;
022:
023: import javax.naming.NamingEnumeration;
024: import javax.naming.NamingException;
025: import javax.naming.directory.Attribute;
026: import javax.naming.directory.Attributes;
027: import javax.naming.directory.DirContext;
028: import javax.naming.directory.SearchControls;
029: import javax.naming.directory.SearchResult;
030:
031: import org.apache.commons.lang.StringUtils;
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.apache.jetspeed.security.GroupPrincipal;
035: import org.apache.jetspeed.security.SecurityException;
036: import org.apache.jetspeed.security.UserPrincipal;
037: import org.apache.jetspeed.security.impl.GroupPrincipalImpl;
038: import org.apache.jetspeed.security.impl.RolePrincipalImpl;
039: import org.apache.jetspeed.security.impl.UserPrincipalImpl;
040:
041: /**
042: * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao
043: * @author <a href="mailto:mike.long@dataline.com">Mike Long </a>, <a
044: * href="mailto:dlestrat@apache.org">David Le Strat</a>
045: */
046: public abstract class LdapPrincipalDaoImpl extends AbstractLdapDao
047: implements LdapPrincipalDao {
048: /** The logger. */
049: private static final Log logger = LogFactory
050: .getLog(LdapPrincipalDaoImpl.class);
051:
052: /**
053: * <p>
054: * Default constructor.
055: * </p>
056: *
057: * @throws SecurityException A {@link SecurityException}.
058: */
059: public LdapPrincipalDaoImpl() throws SecurityException {
060: super ();
061: }
062:
063: /**
064: * <p>
065: * Initializes the dao.
066: * </p>
067: *
068: * @param ldapConfig Holds the ldap binding configuration.
069: * @throws SecurityException A {@link SecurityException}.
070: */
071: public LdapPrincipalDaoImpl(LdapBindingConfig ldapConfig)
072: throws SecurityException {
073: super (ldapConfig);
074: }
075:
076: /**
077: * <p>
078: * A template method for creating a concrete principal object.
079: * </p>
080: *
081: * @param principalUid The principal uid.
082: * @return A concrete principal object.
083: */
084: protected abstract Principal makePrincipal(String principalUid);
085:
086: /**
087: * <p>
088: * A template method for defining the attributes for a particular LDAP class.
089: * </p>
090: *
091: * @param principalUid The principal uid.
092: * @return The LDAP attributes object for the particular class.
093: */
094: protected abstract Attributes defineLdapAttributes(
095: final String principalUid);
096:
097: /**
098: * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao#create(java.lang.String)
099: */
100: public void create(final String principalUid)
101: throws SecurityException {
102: Attributes attrs = defineLdapAttributes(principalUid);
103: logger.debug("creating principal with " + attrs);
104: try {
105: String userDn = getEntryPrefix() + "=" + principalUid;
106: if (!StringUtils.isEmpty(getDnSuffix()))
107: userDn += "," + getDnSuffix();
108:
109: logger.debug("userDn = " + userDn);
110:
111: ctx.createSubcontext(userDn, attrs);
112: if (logger.isDebugEnabled()) {
113: logger.debug("Creating user dn: " + userDn);
114: }
115: } catch (NamingException e) {
116: throw new SecurityException(e);
117: }
118: }
119:
120: /**
121: * <p>
122: * Builds the dn suffix.
123: * </p>
124: *
125: * @return The dn suffix.
126: */
127: protected abstract String getDnSuffix();
128:
129: /**
130: * <p>
131: * Builds the dn suffix.
132: * </p>
133: *
134: * @return The dn suffix.
135: */
136: protected abstract String getUidAttributeForPrincipal();
137:
138: /**
139: * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao#delete(java.lang.String)
140: */
141: public void delete(final String principalUid)
142: throws SecurityException {
143: String dn = lookupByUid(principalUid);
144:
145: if (dn == null) {
146: return;
147: }
148:
149: String rdn;
150: try {
151: rdn = getSubcontextName(dn);
152: //if(!StringUtils.isEmpty(getSearchDomain()))
153: // rdn+="," + getSearchDomain();
154: ctx.destroySubcontext(rdn);
155: } catch (NamingException e) {
156: throw new SecurityException(e);
157: }
158: }
159:
160: /**
161: * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao#convertUidToLdapAcceptableName(java.lang.String)
162: */
163: public String convertUidToLdapAcceptableName(String fullPath) {
164: if (logger.isErrorEnabled()) {
165: logger.debug("Principal fullPath:" + fullPath);
166: }
167: String ldapAcceptableName = fullPath;
168: if (null == fullPath) {
169: return ldapAcceptableName;
170: } else if (fullPath.indexOf(UserPrincipal.PREFS_USER_ROOT) >= 0) {
171: ldapAcceptableName = convertUidWithoutSlashes(UserPrincipalImpl
172: .getPrincipalNameFromFullPath(fullPath));
173: } else if (fullPath.indexOf(GroupPrincipal.PREFS_GROUP_ROOT) >= 0) {
174: ldapAcceptableName = convertUidWithoutSlashes(GroupPrincipalImpl
175: .getPrincipalNameFromFullPath(fullPath));
176: } else if (fullPath.indexOf(GroupPrincipal.PREFS_ROLE_ROOT) >= 0) {
177: ldapAcceptableName = convertUidWithoutSlashes(RolePrincipalImpl
178: .getPrincipalNameFromFullPath(fullPath));
179: }
180: if (logger.isErrorEnabled()) {
181: logger.debug("Ldap acceptable name:" + ldapAcceptableName);
182: }
183:
184: return ldapAcceptableName;
185: }
186:
187: /**
188: * <p>
189: * Returns a well formed uid for LDAP.
190: * </p>
191: *
192: * @param uid The uid.
193: * @return The well formed uid.
194: */
195: private String convertUidWithoutSlashes(String uid) {
196: String uidWithSlashed = uid.replaceAll("/", "&");
197: return uidWithSlashed;
198: }
199:
200: /**
201: * @see org.apache.jetspeed.security.spi.impl.ldap.LdapPrincipalDao#find(java.lang.String,
202: * java.lang.String)
203: */
204: public Principal[] find(final String principalUid,
205: String principalType) throws SecurityException {
206: try {
207: SearchControls cons = setSearchControls();
208: NamingEnumeration searchResults = searchByWildcardedUid(
209: convertUidToLdapAcceptableName(principalUid), cons);
210: Collection principals = new ArrayList();
211:
212: enumerateOverSearchResults(searchResults, principals);
213:
214: return convertPrincipalListToArray(principals);
215: } catch (NamingException e) {
216: throw new SecurityException(e);
217: }
218: }
219:
220: /**
221: * <p>
222: * Converts a list of principals to an array of principals.
223: * </p>
224: *
225: * @param principals The list of principals.
226: * @return The array of principals.
227: */
228: private Principal[] convertPrincipalListToArray(
229: Collection principals) {
230: return (Principal[]) principals
231: .toArray(new Principal[principals.size()]);
232: }
233:
234: /**
235: * <p>
236: * Build the user principal by enumerating through the search results.
237: * </p>
238: *
239: * @param searchResults The {@link NamingEnumeration} of results.
240: * @param principals The collection of user principals.
241: * @throws NamingException Throws a {@link NamingException}.
242: */
243: private void enumerateOverSearchResults(
244: NamingEnumeration searchResults, Collection principals)
245: throws NamingException {
246: while (searchResults.hasMore()) {
247: SearchResult searchResult = (SearchResult) searchResults
248: .next();
249: buildPrincipal(principals, searchResult);
250: }
251: }
252:
253: /**
254: * @param principals The collection of principals.
255: * @param searchResult The {@link SearchResult}
256: * @throws NamingException Throws a {@link NamingException}.
257: */
258: private void buildPrincipal(Collection principals,
259: SearchResult searchResult) throws NamingException {
260: if (searchResult.getObject() instanceof DirContext) {
261: Attributes atts = searchResult.getAttributes();
262:
263: String uid = (String) getAttribute(
264: getUidAttributeForPrincipal(), atts).getAll()
265: .next();
266: Principal principal = makePrincipal(uid);
267:
268: principals.add(principal);
269:
270: }
271: }
272:
273: /**
274: * @param attributeName The attribute name.
275: * @param userAttributes The user {@link Attributes}.
276: * @return The {@link Attribute}.
277: * @throws NamingException Throws a {@link NamingException}.
278: */
279: protected Attribute getAttribute(String attributeName,
280: Attributes userAttributes) throws NamingException {
281: for (NamingEnumeration ae = userAttributes.getAll(); ae
282: .hasMore();) {
283: Attribute attr = (Attribute) ae.next();
284:
285: if (attr.getID().equalsIgnoreCase(attributeName)) {
286: return attr;
287: }
288: }
289: return null;
290: }
291:
292: protected String getSearchDomain() {
293: return this .getUserFilterBase();
294: }
295:
296: protected String[] parseAttr(String attr, String replace) {
297: attr = StringUtils.replace(attr, "{u}", replace);
298: int index = attr.indexOf('=');
299:
300: if (index != -1) {
301: return new String[] {
302: attr.substring(0, index),
303: index < attr.length() - 1 ? attr
304: .substring(index + 1) : null };
305: } else {
306: return new String[] { attr, null };
307: }
308: }
309:
310: protected String getGroupDN(String groupPrincipalUid) {
311: return getGroupDN(groupPrincipalUid, true);
312: }
313:
314: protected String getGroupDN(String groupPrincipalUid,
315: boolean includeBaseDN) {
316: String groupDN = getGroupIdAttribute() + "="
317: + groupPrincipalUid;
318: if (!StringUtils.isEmpty(getGroupFilterBase()))
319: groupDN += "," + getGroupFilterBase();
320: if (includeBaseDN && !StringUtils.isEmpty(getRootContext()))
321: groupDN += "," + getRootContext();
322: return groupDN;
323: }
324:
325: protected String getRoleDN(String rolePrincipalUid) {
326: return getRoleDN(rolePrincipalUid, true);
327: }
328:
329: protected String getRoleDN(String rolePrincipalUid,
330: boolean includeBaseDN) {
331: String roleDN = getRoleIdAttribute() + "=" + rolePrincipalUid;
332: if (!StringUtils.isEmpty(getRoleFilterBase()))
333: roleDN += "," + getRoleFilterBase();
334: if (includeBaseDN && !StringUtils.isEmpty(getRootContext()))
335: roleDN += "," + getRootContext();
336: return roleDN;
337: }
338:
339: protected String getUserDN(String userPrincipalUid) {
340: return getUserDN(userPrincipalUid, true);
341: }
342:
343: protected String getUserDN(String userPrincipalUid,
344: boolean includeBaseDN) {
345: String userDN = getUserIdAttribute() + "=" + userPrincipalUid;
346: if (!StringUtils.isEmpty(getUserFilterBase()))
347: userDN += "," + getUserFilterBase();
348: if (includeBaseDN && !StringUtils.isEmpty(getRootContext()))
349: userDN += "," + getRootContext();
350: return userDN;
351: }
352:
353: }
|