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.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Date;
24 import java.util.HashMap;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Map;
29 import java.util.MissingResourceException;
30 import java.util.ResourceBundle;
31
32 import javax.portlet.ActionRequest;
33 import javax.portlet.ActionResponse;
34 import javax.portlet.PortletConfig;
35 import javax.portlet.PortletException;
36 import javax.portlet.PortletMode;
37 import javax.portlet.PortletPreferences;
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.SecurityException;
53 import org.apache.jetspeed.security.User;
54 import org.apache.jetspeed.security.UserManager;
55 import org.apache.portals.bridges.util.PreferencesHelper;
56 import org.apache.portals.bridges.velocity.AbstractVelocityMessagingPortlet;
57 import org.apache.portals.gems.util.ValidationHelper;
58 import org.apache.velocity.context.Context;
59
60 /***
61 * This portlet allows a logged on user to change its password.
62 *
63 * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
64 * @author <a href="mailto:chris@bluesunrise.com">Chris Schaefer</a>
65 * @version $Id: $
66 */
67 public class UserRegistrationPortlet extends AbstractVelocityMessagingPortlet
68 {
69
70 private PortalAdministration admin;
71
72 private UserManager userManager;
73
74
75
76 private static final String USER_ATTRIBUTE_EMAIL = "user.business-info.online.email";
77
78
79 private static final String MSG_MESSAGE = "MSG";
80
81 private static final String MSG_USERINFO = "user";
82
83 private static final String MSG_REGED_USER_MSG = "registeredUserMsg";
84
85
86 private static final String IP_ROLES = "roles";
87
88 private static final String IP_GROUPS = "groups";
89
90 private static final String IP_TEMPLATE_LOCATION = "emailTemplateLocation";
91
92 private static final String IP_TEMPLATE_NAME = "emailTemplateName";
93
94 private static final String IP_RULES_NAMES = "rulesNames";
95
96 private static final String IP_RULES_VALUES = "rulesValues";
97
98 private static final String IP_REDIRECT_PATH = "redirectPath";
99
100 private static final String IP_RETURN_URL = "returnURL";
101
102 private static final String IP_OPTION_EMAILS_SYSTEM_UNIQUE = "Option_Emails_System_Unique";
103
104 private static final String IP_OPTION_GENERATE_PASSWORDS = "Option_Generate_Passwords";
105
106 private static final String IP_OPTION_USE_EMAIL_AS_USERNAME = "Option_Use_Email_As_Username";
107
108
109 private static final String CTX_RETURN_URL = "returnURL";
110
111 private static final String CTX_MESSAGE = "MSG";
112
113 private static final String CTX_USERINFO = "user";
114
115 private static final String CTX_FIELDS = "fieldsInOrder";
116
117 private static final String CTX_OPTIONALS = "optionalMap";
118
119 private static final String CTX_REGED_USER_MSG = "registeredUserMsg";
120
121 private static final String CTX_OPTION_GENERATE_PASSWORDS = "CTX_Option_Generate_Passwords";
122
123 private static final String CTX_OPTION_USE_EMAIL_AS_USERNAME = "CTX_Option_Use_Email_As_Username";
124
125
126 private static final String RB_EMAIL_SUBJECT = "email.subject.registration";
127
128 private static final String PATH_SEPARATOR = "/";
129
130 /*** email template to use for merging */
131 private String templateLocation;
132
133 private String templateName;
134
135 private JetspeedTemplateLocator templateLocator;
136
137 /*** localized emailSubject */
138 private String emailSubject = null;
139
140 /*** path where to redirect to after pressing submit on the form */
141 private String redirectPath;
142
143 /*** servlet path of the return url to be printed and href'd in email template */
144 private String returnUrlPath;
145
146 /*** roles */
147 private List roles;
148
149 /*** groups */
150 private List groups;
151
152 /*** profile rules */
153 private Map rules;
154
155 /*** will force the passwords to be generated instead of picked by the user */
156 private boolean optionForceGeneratedPasswords = false;
157
158 /***
159 * will use cause the portlet to use a user request username instead
160 * otherwise forces emailaddress
161 */
162 private boolean optionForceEmailAsUsername = true;
163
164 /*** will check to make sure the email address is unique to the system */
165 private boolean optionForceEmailsToBeSystemUnique = true;
166
167 public void init(PortletConfig config) throws PortletException
168 {
169 super.init(config);
170 admin = (PortalAdministration) getPortletContext().getAttribute(
171 CommonPortletServices.CPS_PORTAL_ADMINISTRATION);
172 if (null == admin) { throw new PortletException(
173 "Failed to find the Portal Administration on portlet initialization"); }
174 userManager = (UserManager) getPortletContext().getAttribute(
175 CommonPortletServices.CPS_USER_MANAGER_COMPONENT);
176 if (null == userManager) { throw new PortletException(
177 "Failed to find the User Manager on portlet initialization"); }
178
179
180 this.roles = getInitParameterList(config, IP_ROLES);
181
182
183 this.groups = getInitParameterList(config, IP_GROUPS);
184
185
186 List names = getInitParameterList(config, IP_RULES_NAMES);
187 List values = getInitParameterList(config, IP_RULES_VALUES);
188 rules = new HashMap();
189 for (int ix = 0; ix < ((names.size() < values.size()) ? names.size()
190 : values.size()); ix++)
191 {
192 rules.put(names.get(ix), values.get(ix));
193 }
194
195 this.templateLocation = config.getInitParameter(IP_TEMPLATE_LOCATION);
196 if (templateLocation == null)
197 {
198 templateLocation = "/WEB-INF/view/userreg/";
199 }
200 templateLocation = getPortletContext().getRealPath(templateLocation);
201 this.templateName = config.getInitParameter(IP_TEMPLATE_NAME);
202 if (templateName == null)
203 {
204 templateName = "userRegistrationEmail.vm";
205 }
206
207 ArrayList roots = new ArrayList(1);
208 roots.add(templateLocation);
209
210 try
211 {
212 templateLocator = new JetspeedTemplateLocator(roots, "email", getPortletContext().getRealPath("/"));
213 templateLocator.start();
214 }
215 catch (FileNotFoundException e)
216 {
217 throw new PortletException("Could not start the template locator.", e);
218 }
219
220
221
222 this.optionForceEmailsToBeSystemUnique = Boolean.valueOf(
223 config.getInitParameter(IP_OPTION_EMAILS_SYSTEM_UNIQUE))
224 .booleanValue();
225 this.optionForceGeneratedPasswords = Boolean.valueOf(
226 config.getInitParameter(IP_OPTION_GENERATE_PASSWORDS))
227 .booleanValue();
228 this.optionForceEmailAsUsername = Boolean.valueOf(
229 config.getInitParameter(IP_OPTION_USE_EMAIL_AS_USERNAME))
230 .booleanValue();
231 if (this.optionForceEmailAsUsername)
232 {
233
234 this.optionForceEmailsToBeSystemUnique = true;
235 }
236 this.returnUrlPath = config.getInitParameter(IP_RETURN_URL);
237 this.redirectPath = config.getInitParameter(IP_REDIRECT_PATH);
238 }
239
240 public void doEdit(RenderRequest request, RenderResponse response)
241 throws PortletException, IOException
242 {
243 response.setContentType("text/html");
244 doPreferencesEdit(request, response);
245 }
246
247 public void doView(RenderRequest request, RenderResponse response)
248 throws PortletException, IOException
249 {
250 response.setContentType("text/html");
251 Context context = getContext(request);
252
253 Object userinfoObject = this
254 .receiveRenderMessage(request, MSG_USERINFO);
255 context.put(CTX_USERINFO, userinfoObject);
256 context.put(CTX_FIELDS, getListOfNonSpecialFormKeys());
257 context.put(CTX_OPTIONALS, getOptionalMap());
258 context.put(CTX_MESSAGE, consumeRenderMessage(request, MSG_MESSAGE));
259 String guid = request.getParameter("newUserGUID");
260 if (guid != null)
261 {
262
263
264
265
266
267 ResourceBundle resource = getPortletConfig().getResourceBundle(
268 request.getLocale());
269 context.put(CTX_REGED_USER_MSG, resource
270 .getString("success.login_above"));
271 } else
272 {
273
274
275
276 context.put(CTX_REGED_USER_MSG, consumeRenderMessage(request,
277 MSG_REGED_USER_MSG));
278 }
279
280 if (this.optionForceEmailAsUsername)
281 {
282 context.put(CTX_OPTION_USE_EMAIL_AS_USERNAME, "TRUE");
283 }
284 if (this.optionForceGeneratedPasswords)
285 {
286 context.put(CTX_OPTION_GENERATE_PASSWORDS, "TRUE");
287 }
288
289 super.doView(request, response);
290 }
291
292 private static final Boolean required = new Boolean(true);
293
294 private static final Boolean optional = new Boolean(false);
295
296 private static final Integer IS_STRING = new Integer(1);
297
298 private static final Integer IS_EMAIL = new Integer(2);
299
300 private static final Integer IS_PHONE = new Integer(3);
301
302 private static final Integer IS_URL = new Integer(4);
303
304 private static final Integer IS_BDATE = new Integer(5);
305
306 protected List getListOfNonSpecialFormKeys()
307 {
308 List l = new ArrayList();
309 for (int i = 0; i < formKeys.length; i++)
310 {
311 String key = (String) formKeys[i][0];
312 if (key.equals("user.name"))
313 {
314
315 } else if (key.equals("user.business-info.online.email"))
316 {
317
318 } else if (key.equals("password"))
319 {
320
321 } else if (key.equals("verifyPassword"))
322 {
323
324 } else
325 {
326
327 l.add(key);
328 }
329 }
330 return l;
331 }
332
333 protected Map getOptionalMap()
334 {
335 Map m = new HashMap();
336 for (int i = 0; i < formKeys.length; i++)
337 {
338 boolean isRequired = ((Boolean) formKeys[i][1]).booleanValue();
339 if (!isRequired)
340 {
341 m.put(formKeys[i][0], "");
342 }
343 }
344 return m;
345 }
346
347
348 protected static Object[][] formKeys =
349 {
350
351
352
353 {"user.business-info.online.email", required , new Integer(80), IS_EMAIL},
354
355
356
357 {"user.name", required , new Integer(80), IS_STRING},
358
359
360
361 {"password", required, new Integer(80), IS_STRING},
362 {"verifyPassword", required, new Integer(80), IS_STRING},
363
364
365
366
367
368
369
370
371
372
373
374 {"user.department", optional , new Integer(80), IS_STRING},
375
376
377
378
379 {"user.name.given", optional , new Integer(30), IS_STRING},
380 {"user.name.family", optional , new Integer(30), IS_STRING},
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415 {"user.business-info.postal.name", optional , new Integer(80), IS_STRING},
416 {"user.business-info.postal.street", optional , new Integer(80), IS_STRING},
417 {"user.business-info.postal.city", optional , new Integer(80), IS_STRING},
418 {"user.business-info.postal.stateprov", optional , new Integer(80), IS_STRING},
419 {"user.business-info.postal.postalcode", optional , new Integer(80), IS_STRING},
420 {"user.business-info.postal.country", optional , new Integer(80), IS_STRING},
421 {"user.business-info.postal.organization", optional , new Integer(80), IS_STRING},
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446 };
447
448 protected boolean validateFormValue(String value, Integer length,
449 Integer validationType)
450 {
451
452 if (validationType.equals(IS_STRING))
453 {
454 if (!ValidationHelper.isAny(value, true, length.intValue())) { return false; }
455 } else if (validationType.equals(IS_EMAIL))
456 {
457 if (!ValidationHelper
458 .isEmailAddress(value, true, length.intValue())) { return false; }
459 } else if (validationType.equals(IS_PHONE))
460 {
461 if (!ValidationHelper.isPhoneNumber(value, true, length.intValue())) { return false; }
462 } else if (validationType.equals(IS_URL))
463 {
464 if (!ValidationHelper.isURL(value, true, length.intValue())) { return false; }
465 } else if (validationType.equals(IS_BDATE))
466 {
467 if (!ValidationHelper.isValidDatetime(value)) { return false; }
468 } else
469 {
470
471 if (!ValidationHelper.isAny(value, true, length.intValue())) { return false; }
472 }
473 return true;
474
475 }
476
477 protected String convertIfNeed(String key, String value)
478 {
479 if ("user.bdate".equals(key))
480 {
481
482 Date d = ValidationHelper.parseDate(value);
483 long timeInmS = d.getTime();
484 return "" + timeInmS;
485 }
486 return value;
487 }
488
489 public void processAction(ActionRequest actionRequest,
490 ActionResponse actionResponse) throws PortletException, IOException
491 {
492 List errors = new LinkedList();
493
494 Map userAttributes = new HashMap();
495
496 Map userInfo = new HashMap();
497 ResourceBundle resource = getPortletConfig().getResourceBundle(
498 actionRequest.getLocale());
499
500 if (actionRequest.getPortletMode() == PortletMode.EDIT)
501 {
502 PortletPreferences prefs = actionRequest.getPreferences();
503 PreferencesHelper.requestParamsToPreferences(actionRequest);
504 prefs.store();
505 actionResponse.setPortletMode(PortletMode.VIEW);
506 return;
507 }
508
509 try
510 {
511
512 for (int i = 0; i < formKeys.length; i++)
513 {
514 try
515 {
516 String key = (String) formKeys[i][0];
517 Boolean isRequired = (Boolean) formKeys[i][1];
518 String value = actionRequest.getParameter(key);
519 if ((value != null) && (value.length() > 0))
520 {
521
522 userInfo.put(key, value);
523
524
525 if (!validateFormValue(value, (Integer) formKeys[i][2],
526 (Integer) formKeys[i][3]))
527 {
528 errors.add(resource
529 .getString("error.invalid-format." + key));
530 }
531
532 if (key.startsWith("user."))
533 {
534 value = convertIfNeed(key, value);
535
536 userAttributes.put(key, value);
537 }
538 } else
539 {
540
541
542 if (isRequired.booleanValue())
543 {
544 errors.add(resource.getString("error.lacking."
545 + key));
546 }
547
548
549 userInfo.put(key, "");
550 }
551 } catch (MissingResourceException mre)
552 {
553 errors.add(resource.getString("error.failed_to_add")
554 + mre.toString());
555 }
556
557 }
558
559 publishRenderMessage(actionRequest, MSG_USERINFO, userInfo);
560
561
562
563
564 if (this.optionForceEmailAsUsername)
565 {
566
567 if (!ValidationHelper.isEmailAddress((String) userInfo
568 .get(USER_ATTRIBUTE_EMAIL), true, 80))
569 {
570 errors.add(resource.getString("error.invalid-format."
571 + USER_ATTRIBUTE_EMAIL));
572 }
573 } else
574 {
575 if (!ValidationHelper.isAny((String) userInfo.get("user.name"),
576 true, 80))
577 {
578 errors.add(resource.getString("error.lacking.user.name"));
579 }
580 }
581
582
583 if (!this.optionForceGeneratedPasswords)
584 {
585 if (!ValidationHelper.isAny((String) userInfo.get("password"),
586 true, 25))
587 {
588 errors.add(resource.getString("error.lacking.password"));
589 }
590 }
591
592 if (optionForceEmailAsUsername)
593 {
594
595 userInfo.put("user.name", userInfo.get(USER_ATTRIBUTE_EMAIL));
596 }
597
598 boolean userIdExistsFlag = true;
599 try
600 {
601 userManager.getUser((String) userInfo.get("user.name"));
602 } catch (SecurityException e)
603 {
604 userIdExistsFlag = false;
605 }
606
607 if (userIdExistsFlag)
608 {
609 errors.add(resource.getString("error.userid_already_exists"));
610 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
611 return;
612 }
613 if (optionForceEmailsToBeSystemUnique)
614 {
615 boolean emailExistsFlag = true;
616 User user = null;
617 try
618 {
619 user = admin.lookupUserFromEmail((String) userInfo
620 .get(USER_ATTRIBUTE_EMAIL));
621 } catch (AdministrationEmailException e1)
622 {
623 emailExistsFlag = false;
624 }
625 if ((emailExistsFlag) || (user != null))
626 {
627 errors
628 .add(resource
629 .getString("error.email_already_exists"));
630 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
631 return;
632 }
633
634 }
635
636 try
637 {
638 if (optionForceGeneratedPasswords)
639 {
640 String password = admin.generatePassword();
641 userInfo.put("password", password);
642 } else
643 {
644 if (userInfo.get("password").equals(
645 userInfo.get("verifyPassword")))
646 {
647
648 } else
649 {
650 errors.add(resource
651 .getString("error.two_passwords_do_not_match"));
652 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
653 return;
654 }
655 }
656 } catch (Exception e)
657 {
658 errors.add(resource.getString("error.failed_to_add")
659 + e.toString());
660 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
661 }
662
663 if (errors.size() > 0)
664 {
665 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
666 return;
667 }
668
669
670 try
671 {
672 PortletPreferences prefs = actionRequest.getPreferences();
673 String template = prefs.getValue("newUserTemplateDirectory", "");
674 if (template.trim().length() == 0)
675 template = null;
676 String subsiteRootFolder = prefs.getValue("subsiteRootFolder", "");
677 if (subsiteRootFolder.trim().length() == 0)
678 subsiteRootFolder = null;
679 List prefRoles = getPreferencesList(prefs, IP_ROLES);
680 if (prefRoles.isEmpty())
681 prefRoles = this.roles;
682 List prefGroups = getPreferencesList(prefs, IP_GROUPS);
683 if (prefGroups.isEmpty())
684 prefGroups = this.groups;
685
686 List names = getPreferencesList(prefs, IP_RULES_NAMES);
687 List values = getPreferencesList(prefs, IP_RULES_VALUES);
688 Map profileRules = new HashMap();
689 for (int ix = 0; ix < ((names.size() < values.size()) ? names.size()
690 : values.size()); ix++)
691 {
692 profileRules.put(names.get(ix), values.get(ix));
693 }
694 if (profileRules.isEmpty())
695 profileRules = this.rules;
696
697 admin.registerUser((String) userInfo.get("user.name"),
698 (String) userInfo.get("password"), prefRoles,
699 prefGroups, userAttributes,
700
701 profileRules, template, subsiteRootFolder);
702
703 String urlGUID = ForgottenPasswordPortlet.makeGUID(
704 (String) userInfo.get("user.name"), (String) userInfo
705 .get("password"));
706
707 userInfo.put(CTX_RETURN_URL, generateReturnURL(actionRequest,
708 actionResponse, urlGUID));
709
710 String templ = getTemplatePath(actionRequest, actionResponse);
711
712 if (templ == null) { throw new Exception(
713 "email template not available"); }
714
715 boolean sendEmail = prefs.getValue("SendEmail", "true").equals("true");
716 if (sendEmail)
717 {
718 admin.sendEmail(getPortletConfig(), (String) userInfo
719 .get(USER_ATTRIBUTE_EMAIL),
720 getEmailSubject(actionRequest), templ, userInfo);
721 }
722
723 if ((this.optionForceEmailAsUsername)
724 || (this.optionForceGeneratedPasswords))
725 {
726 publishRenderMessage(actionRequest, MSG_REGED_USER_MSG,
727 resource.getString("success.check_your_email"));
728 } else
729 {
730 publishRenderMessage(actionRequest, MSG_REGED_USER_MSG,
731 resource.getString("success.login_above"));
732 }
733
734
735 publishRenderMessage(actionRequest, MSG_USERINFO, new HashMap());
736
737 actionResponse.sendRedirect(this.generateRedirectURL(
738 actionRequest, actionResponse));
739
740 } catch (Exception e)
741 {
742 errors.add(resource.getString("error.failed_to_add")
743 + e.toString());
744 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
745 }
746 } catch (MissingResourceException mre)
747 {
748 errors.add(resource.getString("error.failed_to_add")
749 + mre.toString());
750 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
751 } catch (Exception e)
752 {
753 errors
754 .add(resource.getString("error.failed_to_add")
755 + e.toString());
756 publishRenderMessage(actionRequest, MSG_MESSAGE, errors);
757 }
758
759 }
760
761 protected String getEmailSubject(PortletRequest request)
762 {
763 ResourceBundle resource = getPortletConfig().getResourceBundle(
764 request.getLocale());
765 try
766 {
767 this.emailSubject = resource.getString(RB_EMAIL_SUBJECT);
768 } catch (java.util.MissingResourceException mre)
769 {
770 this.emailSubject = null;
771 }
772 if (this.emailSubject == null)
773 this.emailSubject = "Registration Confirmation";
774 return this.emailSubject;
775 }
776
777 protected List getInitParameterList(PortletConfig config, String ipName)
778 {
779 String temp = config.getInitParameter(ipName);
780 if (temp == null) return new ArrayList();
781
782 String[] temps = temp.split("//,");
783 for (int ix = 0; ix < temps.length; ix++)
784 temps[ix] = temps[ix].trim();
785
786 return Arrays.asList(temps);
787 }
788
789 protected List getPreferencesList(PortletPreferences prefs, String prefName)
790 {
791 String temp = prefs.getValue(prefName, "");
792 if (temp == null || temp.trim().length() == 0) return new ArrayList();
793
794 String[] temps = temp.split("//,");
795 for (int ix = 0; ix < temps.length; ix++)
796 temps[ix] = temps[ix].trim();
797
798 return Arrays.asList(temps);
799 }
800
801 protected String generateReturnURL(PortletRequest request,
802 PortletResponse response, String urlGUID)
803 {
804 String fullPath = this.returnUrlPath + "?newUserGUID=" + urlGUID;
805
806 String url = admin.getPortalURL(request, response, fullPath);
807 return url;
808 }
809
810 protected String generateRedirectURL(PortletRequest request,
811 PortletResponse response)
812 {
813 return admin.getPortalURL(request, response, this.redirectPath);
814 }
815
816
817 protected String getTemplatePath(ActionRequest request, ActionResponse response)
818 {
819 if (templateLocator == null)
820 {
821 return templateLocation + PATH_SEPARATOR + templateName;
822 }
823
824 RequestContext requestContext = (RequestContext) request
825 .getAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE);
826 Locale locale = request.getLocale();
827
828 try
829 {
830 LocatorDescriptor locator = templateLocator.createLocatorDescriptor("email");
831 locator.setName(templateName);
832 locator.setMediaType(requestContext.getMediaType());
833 locator.setLanguage(locale.getLanguage());
834 locator.setCountry(locale.getCountry());
835 TemplateDescriptor template = templateLocator.locateTemplate(locator);
836
837 return template.getAppRelativePath();
838 }
839 catch (TemplateLocatorException e)
840 {
841 return templateLocation + PATH_SEPARATOR + templateName;
842 }
843 }
844 }