%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.jetspeed.security.spi.impl.ldap.LdapUserCredentialDaoImpl |
|
|
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.util.Hashtable; |
|
20 | ||
21 | import javax.naming.AuthenticationException; |
|
22 | import javax.naming.Context; |
|
23 | import javax.naming.InitialContext; |
|
24 | import javax.naming.NamingEnumeration; |
|
25 | import javax.naming.NamingException; |
|
26 | import javax.naming.directory.Attribute; |
|
27 | import javax.naming.directory.Attributes; |
|
28 | import javax.naming.directory.BasicAttributes; |
|
29 | import javax.naming.directory.DirContext; |
|
30 | import javax.naming.directory.SearchControls; |
|
31 | import javax.naming.directory.SearchResult; |
|
32 | ||
33 | import org.apache.commons.lang.StringUtils; |
|
34 | import org.apache.commons.logging.Log; |
|
35 | import org.apache.commons.logging.LogFactory; |
|
36 | import org.apache.jetspeed.i18n.KeyedMessage; |
|
37 | import org.apache.jetspeed.security.SecurityException; |
|
38 | ||
39 | /** |
|
40 | * @see org.apache.jetspeed.security.spi.impl.ldap.LdapUserCredentialDao |
|
41 | * @author <a href="mailto:mike.long@dataline.com">Mike Long </a>, <a href="mailto:dlestrat@apache.org">David Le Strat</a> |
|
42 | */ |
|
43 | public class LdapUserCredentialDaoImpl extends AbstractLdapDao implements LdapUserCredentialDao |
|
44 | { |
|
45 | /** The logger. */ |
|
46 | 0 | private static final Log logger = LogFactory.getLog(LdapUserCredentialDaoImpl.class); |
47 | ||
48 | /** The password attribute. */ |
|
49 | ||
50 | /** |
|
51 | * <p> |
|
52 | * Default constructor. |
|
53 | * </p> |
|
54 | * |
|
55 | * @throws SecurityException A {@link SecurityException}. |
|
56 | */ |
|
57 | public LdapUserCredentialDaoImpl() throws SecurityException |
|
58 | { |
|
59 | 0 | super(); |
60 | 0 | } |
61 | ||
62 | /** |
|
63 | * <p> |
|
64 | * Initializes the dao. |
|
65 | * </p> |
|
66 | * |
|
67 | * @param ldapConfig Holds the ldap binding configuration. |
|
68 | * |
|
69 | * @throws SecurityException A {@link SecurityException}. |
|
70 | */ |
|
71 | public LdapUserCredentialDaoImpl(LdapBindingConfig ldapConfig) throws SecurityException |
|
72 | { |
|
73 | 0 | super(ldapConfig); |
74 | 0 | } |
75 | ||
76 | /** |
|
77 | * <p> |
|
78 | * Updates the password for the specified user. |
|
79 | * </p> |
|
80 | */ |
|
81 | public void changePassword(final String uid, class="keyword">final String password) throws SecurityException |
|
82 | { |
|
83 | 0 | validateUid(uid); |
84 | 0 | validatePassword(password); |
85 | 0 | logger.debug("changePassword for " + uid + " with " + password); |
86 | 0 | String userDn = lookupByUid(uid); |
87 | 0 | logger.debug("userDn = " + userDn); |
88 | try |
|
89 | { |
|
90 | 0 | setPassword(userDn, password); |
91 | } |
|
92 | 0 | catch (NamingException e) |
93 | { |
|
94 | 0 | throw new SecurityException(e); |
95 | 0 | } |
96 | 0 | } |
97 | ||
98 | /** |
|
99 | * <p> |
|
100 | * Looks up the user by the UID attribute. If this lookup succeeds, this |
|
101 | * method then attempts to authenticate the user using the password, |
|
102 | * throwing an AuthenticationException if the password is incorrect or an |
|
103 | * OperationNotSupportedException if the password is empty. |
|
104 | * </p> |
|
105 | * |
|
106 | * @param uid The uid. |
|
107 | * @param password The password. |
|
108 | * @throws SecurityException Throws a {@link SecurityException}. |
|
109 | */ |
|
110 | public boolean authenticate(final String uid, class="keyword">final String password) throws SecurityException |
|
111 | { |
|
112 | 0 | validateUid(uid); |
113 | 0 | validatePassword(password); |
114 | try |
|
115 | { |
|
116 | 0 | Hashtable env = this.ctx.getEnvironment(); |
117 | //String savedPassword = String.valueOf(getPassword(uid)); |
|
118 | 0 | String oldCredential = (String)env.get(Context.SECURITY_CREDENTIALS); |
119 | 0 | String oldUsername = (String)env.get(Context.SECURITY_PRINCIPAL); |
120 | ||
121 | 0 | String dn = lookupByUid(uid); |
122 | 0 | if ( dn == null ) |
123 | 0 | throw new SecurityException(class="keyword">new KeyedMessage("User " + uid + " not found")); |
124 | ||
125 | // Build user dn using lookup value, just appending the user filter after the uid won't work when users |
|
126 | // are/can be stored in a subtree (searchScope sub-tree) |
|
127 | // The looked up dn though is/should always be correct, just need to append the root context. |
|
128 | 0 | if (!StringUtils.isEmpty(getRootContext())) |
129 | 0 | dn +="," + getRootContext(); |
130 | ||
131 | 0 | env.put(Context.SECURITY_PRINCIPAL,dn); |
132 | 0 | env.put(Context.SECURITY_CREDENTIALS,password); |
133 | 0 | new InitialContext(env); |
134 | 0 | env.put(Context.SECURITY_PRINCIPAL,oldUsername); |
135 | 0 | env.put(Context.SECURITY_CREDENTIALS,oldCredential); |
136 | 0 | return true; |
137 | } |
|
138 | 0 | catch (AuthenticationException e) |
139 | { |
|
140 | 0 | return false; |
141 | } |
|
142 | 0 | catch (NamingException e) |
143 | { |
|
144 | 0 | throw new SecurityException(e); |
145 | } |
|
146 | } |
|
147 | ||
148 | /** |
|
149 | * @see org.apache.jetspeed.security.spi.impl.ldap.LdapUserCredentialDao#getPassword(java.lang.String) |
|
150 | */ |
|
151 | public char[] getPassword(final String uid) throws SecurityException |
|
152 | { |
|
153 | 0 | validateUid(uid); |
154 | try |
|
155 | { |
|
156 | 0 | SearchControls cons = setSearchControls(); |
157 | 0 | NamingEnumeration results = searchByWildcardedUid(uid, cons); |
158 | ||
159 | 0 | return getPassword(results, uid); |
160 | } |
|
161 | 0 | catch (NamingException e) |
162 | { |
|
163 | 0 | throw new SecurityException(e); |
164 | } |
|
165 | } |
|
166 | ||
167 | /** |
|
168 | * <p> |
|
169 | * Set the user's password. |
|
170 | * </p> |
|
171 | * |
|
172 | * @param userDn The user. |
|
173 | * @param password The password. |
|
174 | * @throws NamingException Throws a {@link NamingException}. |
|
175 | */ |
|
176 | private void setPassword(final String userDn, class="keyword">final String password) throws NamingException |
|
177 | { |
|
178 | 0 | logger.debug("setPassword userDn = " + userDn); |
179 | 0 | String rdn = getSubcontextName(userDn); |
180 | //if (!StringUtils.isEmpty(getUserFilterBase())) |
|
181 | // rdn+="," + getUserFilterBase(); |
|
182 | 0 | logger.debug("setPassword rdn = " + rdn); |
183 | 0 | Attributes attrs = new BasicAttributes(false); |
184 | ||
185 | 0 | attrs.put(getUserPasswordAttribute(), password); |
186 | 0 | ctx.modifyAttributes(rdn, DirContext.REPLACE_ATTRIBUTE, attrs); |
187 | 0 | } |
188 | ||
189 | /** |
|
190 | * <p> |
|
191 | * Get the password. |
|
192 | * </p> |
|
193 | * |
|
194 | * @param results The {@link NamingEnumeration}. |
|
195 | * @param uid The uid. |
|
196 | * @return The password as an array of char. |
|
197 | * @throws NamingException Throws a {@link NamingException}. |
|
198 | */ |
|
199 | private char[] getPassword(final NamingEnumeration results, class="keyword">final String uid) throws NamingException |
|
200 | { |
|
201 | 0 | if (!results.hasMore()) |
202 | { |
|
203 | 0 | throw new NamingException("Could not find any user with uid[" + uid + "]"); |
204 | } |
|
205 | ||
206 | 0 | Attributes userAttributes = getFirstUser(results); |
207 | ||
208 | 0 | char[] rawPassword = convertRawPassword(getAttribute(getUserPasswordAttribute(), userAttributes)); |
209 | 0 | return rawPassword; |
210 | } |
|
211 | ||
212 | /** |
|
213 | * <p> |
|
214 | * Get the attribute. |
|
215 | * </p> |
|
216 | * |
|
217 | * @param attributeName The attribute name. |
|
218 | * @param userAttributes The user {@link Attributes}. |
|
219 | * @return The {@link Attribute} |
|
220 | * @throws NamingException Throws a {@link NamingException}. |
|
221 | */ |
|
222 | private Attribute getAttribute(String attributeName, Attributes userAttributes) throws NamingException |
|
223 | { |
|
224 | 0 | for (NamingEnumeration ae = userAttributes.getAll(); ae.hasMore();) |
225 | { |
|
226 | 0 | Attribute attr = (Attribute) ae.next(); |
227 | ||
228 | 0 | if (attr.getID().equalsIgnoreCase(attributeName)) |
229 | { |
|
230 | 0 | return attr; |
231 | } |
|
232 | 0 | } |
233 | 0 | return null; |
234 | } |
|
235 | ||
236 | /** |
|
237 | * <p> |
|
238 | * This method converts an ascii password to a char array. It needs to be |
|
239 | * improved to do proper unicode conversion. |
|
240 | * </p> |
|
241 | * |
|
242 | * @param attr The {@link Attribute}. |
|
243 | */ |
|
244 | private char[] convertRawPassword(Attribute attr) throws NamingException |
|
245 | { |
|
246 | 0 | char[] class="keyword">charPass = null; |
247 | ||
248 | 0 | if ( attr != null ) |
249 | { |
|
250 | 0 | byte[] rawPass = (byte[]) attr.getAll().next(); |
251 | 0 | charPass = new char[rawPass.length]; |
252 | ||
253 | 0 | for (int i = 0; i < rawPass.length; i++) |
254 | { |
|
255 | // I know I lose the sign and this is only good for ascii text. |
|
256 | 0 | charPass[i] = (char) rawPass[i]; |
257 | } |
|
258 | 0 | } |
259 | else |
|
260 | { |
|
261 | 0 | charPass = new char[0]; |
262 | } |
|
263 | 0 | return charPass; |
264 | } |
|
265 | ||
266 | /** |
|
267 | * <p> |
|
268 | * Gets the first matching user. |
|
269 | * </p> |
|
270 | * |
|
271 | * @param results The results to find the user in. |
|
272 | * @return The Attributes. |
|
273 | * @throws NamingException Throws a {@link NamingException}. |
|
274 | */ |
|
275 | private Attributes getFirstUser(NamingEnumeration results) throws NamingException |
|
276 | { |
|
277 | 0 | SearchResult result = (SearchResult) results.next(); |
278 | 0 | Attributes answer = result.getAttributes(); |
279 | ||
280 | 0 | return answer; |
281 | } |
|
282 | ||
283 | protected String getEntryPrefix() { |
|
284 | 0 | return this.getUserIdAttribute(); |
285 | } |
|
286 | ||
287 | protected String getSearchSuffix() { |
|
288 | 0 | return this.getUserFilter(); |
289 | } |
|
290 | ||
291 | protected String getSearchDomain() { |
|
292 | 0 | return this.getUserFilterBase(); |
293 | } |
|
294 | ||
295 | protected String[] getObjectClasses() { |
|
296 | 0 | return this.getUserObjectClasses(); |
297 | } |
|
298 | ||
299 | protected String[] getAttributes() { |
|
300 | 0 | return this.getUserAttributes(); |
301 | } |
|
302 | ||
303 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |