1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.portlets.registration;
18
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.security.Principal;
22 import java.util.ArrayList;
23 import java.util.Date;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.Map;
30 import java.util.ResourceBundle;
31 import java.util.Set;
32 import java.util.prefs.Preferences;
33
34 import javax.portlet.ActionRequest;
35 import javax.portlet.ActionResponse;
36 import javax.portlet.PortletConfig;
37 import javax.portlet.PortletException;
38 import javax.portlet.PortletRequest;
39 import javax.portlet.PortletResponse;
40 import javax.portlet.RenderRequest;
41 import javax.portlet.RenderResponse;
42
43 import org.apache.jetspeed.CommonPortletServices;
44 import org.apache.jetspeed.PortalReservedParameters;
45 import org.apache.jetspeed.administration.AdministrationEmailException;
46 import org.apache.jetspeed.administration.PortalAdministration;
47 import org.apache.jetspeed.locator.JetspeedTemplateLocator;
48 import org.apache.jetspeed.locator.LocatorDescriptor;
49 import org.apache.jetspeed.locator.TemplateDescriptor;
50 import org.apache.jetspeed.locator.TemplateLocatorException;
51 import org.apache.jetspeed.request.RequestContext;
52 import org.apache.jetspeed.security.PasswordCredential;
53 import org.apache.jetspeed.security.SecurityException;
54 import org.apache.jetspeed.security.User;
55 import org.apache.jetspeed.security.UserManager;
56 import org.apache.jetspeed.security.UserPrincipal;
57 import org.apache.portals.bridges.velocity.AbstractVelocityMessagingPortlet;
58 import org.apache.portals.gems.util.ValidationHelper;
59 import org.apache.velocity.context.Context;
60
61 /***
62 * This portlet allows a logged on user to change its password.
63 *
64 * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
65 * @author <a href="mailto:chris@bluesunrise.com">Chris Schaefer</a>
66 * @version $Id: $
67 */
68 public class ForgottenPasswordPortlet extends AbstractVelocityMessagingPortlet
69 {
70 private PortalAdministration admin;
71
72 private UserManager userManager;
73
74
75 private static final String RP_EMAIL_ADDRESS = "email";
76
77
78 private static final String MSG_MESSAGE = "MSG";
79 private static final String MSG_CHANGEDPW_MSG = "CH_PWD_MSD";
80
81
82 private static final String CTX_EMAIL_ADDRESS = "email";
83
84 private static final String CTX_RETURN_URL = "returnURL";
85
86 private static final String CTX_NEW_PASSWORD = "password";
87
88 private static final String CTX_USER_NAME = "username";
89
90 private static final String CTX_MESSAGE = "MSG";
91
92 private static final String CTX_CHANGEDPW_MSG = "updatedPWMsg";
93
94
95 private static final String IP_REDIRECT_PATH = "redirectPath";
96
97 private static final String IP_RETURN_URL = "returnURL";
98
99 private static final String IP_TEMPLATE_LOCATION = "emailTemplateLocation";
100
101 private static final String IP_TEMPLATE_NAME = "emailTemplateName";
102
103
104 private static final String RB_EMAIL_SUBJECT = "email.subject.forgotten.password";
105
106 private static final String PATH_SEPARATOR = "/";
107
108 /*** email template to use for merging */
109 private String templateLocation;
110
111 private String templateName;
112
113 private JetspeedTemplateLocator templateLocator;
114
115 /*** servlet path of the return url to be printed and href'd in email template */
116 private String returnUrlPath;
117
118 /*** path where to redirect to after pressing submit on the form */
119 private String redirectPath;
120
121 /*** localized emailSubject */
122 private String emailSubject = null;
123
124 public void init(PortletConfig config) throws PortletException
125 {
126 super.init(config);
127 admin = (PortalAdministration) getPortletContext().getAttribute(
128 CommonPortletServices.CPS_PORTAL_ADMINISTRATION);
129 if (null == admin) { throw new PortletException(
130 "Failed to find the Portal Administration on portlet initialization"); }
131 userManager = (UserManager) getPortletContext().getAttribute(
132 CommonPortletServices.CPS_USER_MANAGER_COMPONENT);
133 if (null == userManager) { throw new PortletException(
134 "Failed to find the User Manager on portlet initialization"); }
135
136 this.returnUrlPath = config.getInitParameter(IP_RETURN_URL);
137 this.redirectPath = config.getInitParameter(IP_REDIRECT_PATH);
138 this.templateLocation = config.getInitParameter(IP_TEMPLATE_LOCATION);
139 if (templateLocation == null)
140 {
141 templateLocation = "/WEB-INF/view/userreg/";
142 }
143 templateLocation = getPortletContext().getRealPath(templateLocation);
144 this.templateName = config.getInitParameter(IP_TEMPLATE_NAME);
145 if (templateName == null)
146 {
147 templateName = "forgottenPasswdEmail.vm";
148 }
149
150 ArrayList roots = new ArrayList(1);
151 roots.add(templateLocation);
152
153 try
154 {
155 templateLocator = new JetspeedTemplateLocator(roots, "email", getPortletContext().getRealPath("/"));
156 templateLocator.start();
157 }
158 catch (FileNotFoundException e)
159 {
160 throw new PortletException("Could not start the template locator.", e);
161 }
162
163
164 }
165
166 private boolean isValidGUID(String guid)
167 {
168 Map map = admin.getNewLoginInfo(guid);
169
170 if (map != null) { return true; }
171 return false;
172 }
173
174 private boolean updatePasswordFromGUID(String guid)
175 {
176 Map map = admin.getNewLoginInfo(guid);
177
178 String userName = (String) map.get("user.name");
179 String newPassword = (String) map.get("password");
180
181
182 try
183 {
184 userManager.setPassword(userName, null, newPassword);
185 userManager.setPasswordUpdateRequired(userName, true);
186
187 admin.removeNewLoginInfo(guid);
188 } catch (SecurityException e)
189 {
190 return false;
191 }
192 return true;
193 }
194
195 public void doView(RenderRequest request, RenderResponse response)
196 throws PortletException, IOException
197 {
198 response.setContentType("text/html");
199 Context context = getContext(request);
200 String email = request.getParameter(RP_EMAIL_ADDRESS);
201 String guid = request.getParameter("guid");
202
203 ResourceBundle resource = getPortletConfig().getResourceBundle(request.getLocale());
204
205 if (guid != null)
206 {
207 if(isValidGUID(guid))
208 {
209 try
210 {
211 updatePasswordFromGUID(guid);
212 context
213 .put(CTX_CHANGEDPW_MSG, resource.getString("forgotten.successful_pw_update"));
214 } catch (Exception e)
215 {
216 context.put(CTX_MESSAGE,resource.getString("forgotten.unable_to_update_pw"));
217 }
218 } else {
219
220 context
221 .put(CTX_CHANGEDPW_MSG,resource.getString("forgotten.password_update_link_invalid"));
222 }
223 } else {
224
225 context.put(CTX_CHANGEDPW_MSG,consumeRenderMessage(request, MSG_CHANGEDPW_MSG));
226 }
227 context.put(CTX_EMAIL_ADDRESS, email);
228 context.put(CTX_MESSAGE, consumeRenderMessage(request, MSG_MESSAGE));
229 super.doView(request, response);
230 }
231
232 public static String makeGUID(String user, String newpw)
233 {
234
235 long num = (long) user.hashCode() + (long) newpw.hashCode();
236 long d = new Date().getTime();
237 long val = num * d;
238 String retval = Long.toHexString(val);
239 return retval;
240 }
241
242 public void processAction(ActionRequest request, ActionResponse response)
243 throws PortletException, IOException
244 {
245 List errors = new LinkedList();
246
247 String email = request.getParameter(RP_EMAIL_ADDRESS);
248 Locale locale = request.getLocale();
249
250 ResourceBundle resource = getPortletConfig().getResourceBundle(locale);
251
252
253 if (!ValidationHelper.isEmailAddress(email, true, 80))
254 {
255 errors.add(resource.getString("forgotten.invalid_email_format_entered"));
256 }
257
258 if (errors.size() > 0)
259 {
260 publishRenderMessage(request, MSG_MESSAGE, errors);
261 return;
262 }
263
264 User user = null;
265 try
266 {
267 user = admin.lookupUserFromEmail(email);
268 } catch (Exception e)
269 {
270 publishRenderMessage(
271 request,
272 MSG_MESSAGE,
273 makeMessage(resource.getString("forgotten.email_address_not_found")));
274 return;
275 }
276
277 try
278 {
279 String userName = getUserName(user);
280
281 String newPassword = admin.generatePassword();
282
283 String urlGUID = makeGUID(userName, newPassword);
284
285 Preferences pref = user.getUserAttributes();
286 String[] keys = pref.keys();
287 Map userAttributes = new HashMap();
288 if (keys != null)
289 {
290 for (int ix = 0; ix < keys.length; ix++)
291 {
292
293
294 userAttributes.put(keys[ix], pref.get(keys[ix], ""));
295 }
296 }
297
298 userAttributes.put(CTX_RETURN_URL, generateReturnURL(request,
299 response, urlGUID));
300 userAttributes.put(CTX_NEW_PASSWORD, newPassword);
301 userAttributes.put(CTX_USER_NAME, userName);
302
303 String templ = getTemplatePath(request, response);
304
305 if (templ == null)
306 {
307 throw new Exception("email template not available");
308 }
309 admin.sendEmail(this.getPortletConfig(), email,
310 getEmailSubject(request),templ, userAttributes);
311
312
313
314 Map map = new HashMap();
315 map.put("user.name",userName);
316 map.put("password",newPassword);
317 admin.putNewLoginInfo(urlGUID, map);
318
319 publishRenderMessage(
320 request,
321 MSG_CHANGEDPW_MSG,
322 makeMessage(resource.getString("an_email_has_been_sent")));
323
324 response.sendRedirect(generateRedirectURL(request, response));
325 }
326 catch (AdministrationEmailException e)
327 {
328 publishRenderMessage(request, CTX_MESSAGE, makeMessage(e
329 .getMessage()));
330 }
331 catch (Exception e)
332 {
333 publishRenderMessage(request, CTX_MESSAGE,
334 makeMessage(resource.getString("failed_to_send") + e.toString()));
335 }
336
337 }
338
339 protected String getEmailSubject(PortletRequest request)
340 {
341 ResourceBundle resource = getPortletConfig().getResourceBundle(
342 request.getLocale());
343 try
344 {
345 this.emailSubject = resource.getString(RB_EMAIL_SUBJECT);
346 } catch (Exception e)
347 {
348
349 }
350 if (this.emailSubject == null)
351 this.emailSubject = "Password Notification";
352 return this.emailSubject;
353 }
354
355 protected String generateReturnURL(PortletRequest request,
356 PortletResponse response,
357 String urlGUID)
358 {
359 String fullPath = this.returnUrlPath + "?guid=" + urlGUID;
360
361 String url = admin.getPortalURL(request, response, fullPath);
362 return url;
363 }
364
365 protected String generateRedirectURL(PortletRequest request,
366 PortletResponse response)
367
368 {
369 return admin.getPortalURL(request, response, this.redirectPath);
370 }
371
372 protected String getUserName(User user)
373 {
374 Principal principal = null;
375 Iterator principals = user.getSubject().getPrincipals().iterator();
376 while (principals.hasNext())
377 {
378 Object o = principals.next();
379 if (o instanceof UserPrincipal)
380 {
381 principal = (Principal) o;
382 return principal.toString();
383 }
384
385 }
386 return null;
387 }
388
389 protected String getPassword(User user)
390 {
391 PasswordCredential credential = null;
392
393 Set credentials = user.getSubject().getPrivateCredentials();
394 Iterator iter = credentials.iterator();
395 while (iter.hasNext())
396 {
397 Object o = iter.next();
398 if (o instanceof PasswordCredential)
399 {
400 credential = (PasswordCredential) o;
401 char[] charar = credential.getPassword();
402
403 return new String(charar);
404 }
405 }
406 return null;
407 }
408
409 protected List makeMessage(String msg)
410 {
411 List errors = new LinkedList();
412 errors.add(msg);
413 return errors;
414 }
415
416 protected String getTemplatePath(ActionRequest request, ActionResponse response)
417 {
418 if (templateLocator == null)
419 {
420 return templateLocation + PATH_SEPARATOR + templateName;
421 }
422
423 RequestContext requestContext = (RequestContext) request
424 .getAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE);
425 Locale locale = request.getLocale();
426
427 try
428 {
429 LocatorDescriptor locator = templateLocator.createLocatorDescriptor("email");
430 locator.setName(templateName);
431 locator.setMediaType(requestContext.getMediaType());
432 locator.setLanguage(locale.getLanguage());
433 locator.setCountry(locale.getCountry());
434 TemplateDescriptor template = templateLocator.locateTemplate(locator);
435
436 return template.getAppRelativePath();
437 }
438 catch (TemplateLocatorException e)
439 {
440 return templateLocation + PATH_SEPARATOR + templateName;
441 }
442 }
443
444 }