001: package org.tigris.scarab.actions;
002:
003: /* ================================================================
004: * Copyright (c) 2000-2002 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by Collab.Net <http://www.Collab.Net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of Collab.Net.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of Collab.Net.
047: */
048:
049: // Turbine Stuff
050: import java.util.Locale;
051:
052: import org.apache.turbine.RunData;
053: import org.apache.turbine.TemplateContext;
054: import org.apache.turbine.Turbine;
055: import org.apache.turbine.modules.ContextAdapter;
056: import org.apache.turbine.tool.IntakeTool;
057:
058: import org.apache.fulcrum.intake.model.Field;
059: import org.apache.fulcrum.intake.model.Group;
060: import org.apache.fulcrum.security.TurbineSecurity;
061: import org.apache.fulcrum.security.util.TurbineSecurityException;
062:
063: // Scarab Stuff
064: import org.tigris.scarab.om.ScarabUser;
065: import org.tigris.scarab.tools.ScarabRequestTool;
066: import org.tigris.scarab.tools.ScarabLocalizationTool;
067: import org.tigris.scarab.tools.localization.L10NKeySet;
068: import org.tigris.scarab.tools.localization.L10NMessage;
069: import org.tigris.scarab.tools.localization.Localizable;
070: import org.tigris.scarab.util.AnonymousUserUtil;
071: import org.tigris.scarab.util.Email;
072: import org.tigris.scarab.util.ScarabConstants;
073: import org.tigris.scarab.util.Log;
074: import org.tigris.scarab.util.ScarabRuntimeException;
075: import org.tigris.scarab.actions.base.ScarabTemplateAction;
076:
077: // FIXME: remove the methods that reference this
078: import org.tigris.scarab.om.ScarabUserImpl;
079: import org.tigris.scarab.om.ScarabUserImplPeer;
080: import org.tigris.scarab.om.ScarabUserManager;
081:
082: import org.xbill.DNS.Record;
083: import org.xbill.DNS.dns;
084: import org.xbill.DNS.Type;
085:
086: /**
087: * This class is responsible for dealing with the Register
088: * Action.
089: *
090: * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
091: * @version $Id: Register.java 9999 2006-01-31 20:39:01Z dabbous $
092: */
093: public class Register extends ScarabTemplateAction {
094:
095: private boolean checkRFC2505(String email) {
096: // try just the end portion of the domain
097: String domain = parseDomain(email);
098: if (domain != null) {
099: // try to find any A records for the domain
100: Record[] records = dns.getRecords(domain, Type.A);
101: if (records != null || records.length > 0) {
102: return true;
103: }
104: // now try just the domain after the @
105: // this is for domains like foo.co.uk
106: String fullDomain = email.substring(email.indexOf('@') + 1);
107: records = dns.getRecords(fullDomain, Type.A);
108: if (records != null || records.length > 0) {
109: return true;
110: }
111: // now try to find any MX records for the domain
112: records = dns.getRecords(domain, Type.MX);
113: if (records != null || records.length > 0) {
114: return true;
115: }
116: // now try to find any MX records for the fullDomain
117: records = dns.getRecords(fullDomain, Type.MX);
118: if (records != null || records.length > 0) {
119: return true;
120: }
121: }
122: return false;
123: }
124:
125: /**
126: * This manages clicking the "Register" button in the Register.vm
127: * template. As a result, the user will go to the
128: * RegisterConfirm.vm screen.
129: */
130: public void doRegister(RunData data, TemplateContext context)
131: throws Exception {
132: String template = getCurrentTemplate(data, null);
133: String nextTemplate = getNextTemplate(data, template);
134:
135: IntakeTool intake = getIntakeTool(context);
136: if (intake.isAllValid()) {
137: ScarabRequestTool scarabR = getScarabRequestTool(context);
138: ScarabLocalizationTool l10n = getLocalizationTool(context);
139: Object user = data.getUser().getTemp(
140: ScarabConstants.SESSION_REGISTER);
141: Group register = null;
142: if (user != null && user instanceof ScarabUser) {
143: register = intake.get("Register", ((ScarabUser) user)
144: .getQueryKey(), false);
145: } else {
146: register = intake.get("Register",
147: IntakeTool.DEFAULT_KEY, false);
148: }
149:
150: // not quite sure why this happens, but it does, so case
151: // for it and deal with it.
152: if (register == null) {
153: setTarget(data, "Register.vm");
154: scarabR
155: .setAlertMessage(L10NKeySet.RegisterSessionError);
156: return;
157: }
158:
159: String password = register.get("Password").toString();
160: String passwordConfirm = register.get("PasswordConfirm")
161: .toString();
162:
163: // check to make sure the passwords match
164: if (!password.equals(passwordConfirm)) {
165: setTarget(data, template);
166: scarabR.setAlertMessage(L10NKeySet.PasswordsDoNotMatch);
167: return;
168: }
169:
170: // get an anonymous user
171: ScarabUser su = (ScarabUser) (ScarabUser) AnonymousUserUtil
172: .getAnonymousUser();
173: try {
174: register.setProperties(su);
175: } catch (Exception e) {
176: setTarget(data, template);
177: Localizable msg = new L10NMessage(
178: L10NKeySet.ExceptionGeneric, e);
179: scarabR.setAlertMessage(msg);
180: return;
181: }
182:
183: String email = su.getEmail();
184: if (email == null) {
185: setTarget(data, "Register.vm");
186: scarabR
187: .setAlertMessage(L10NKeySet.EnterValidEmailAddress);
188: return;
189: }
190:
191: // check to see if the email is a valid domain (has A records)
192: if (Turbine.getConfiguration().getBoolean(
193: "scarab.register.email.checkRFC2505", false)) {
194: if (!checkRFC2505(email)) {
195: setTarget(data, template);
196: Localizable msg = new L10NMessage(
197: L10NKeySet.EmailHasBadDNS, email);
198: scarabR.setAlertMessage(msg);
199: return;
200: }
201: }
202: String[] badEmails = Turbine.getConfiguration()
203: .getStringArray("scarab.register.email.badEmails");
204: if (badEmails != null && badEmails.length > 0) {
205: for (int i = 0; i < badEmails.length; i++) {
206: if (email.equalsIgnoreCase(badEmails[i])) {
207: setTarget(data, template);
208: Localizable msg = new L10NMessage(
209: L10NKeySet.InvalidEmailAddress, email);
210: scarabR.setAlertMessage(msg);
211: return;
212: }
213: }
214: }
215:
216: // check to see if the user already exists and is not DELETED
217: if (ScarabUserImplPeer.checkExists(su)) {
218: String username = su.getUserName();
219: ScarabUser scarabUser = (ScarabUser) TurbineSecurity
220: .getUser(username);
221: String cs = scarabUser.getConfirmed();
222: if (!cs.equals(ScarabUser.DELETED)) {
223: setTarget(data, template);
224: scarabR
225: .setAlertMessage(L10NKeySet.UsernameExistsAlready);
226: return;
227: }
228: }
229:
230: // put the user object into the context so that it can be
231: // used on the nextTemplate
232: data.getUser()
233: .setTemp(ScarabConstants.SESSION_REGISTER, su);
234: setTarget(data, nextTemplate);
235: }
236: }
237:
238: public void doConfirmregistration(RunData data,
239: TemplateContext context) throws Exception {
240: String template = getCurrentTemplate(data);
241: String nextTemplate = getNextTemplate(data);
242: ScarabRequestTool scarabR = getScarabRequestTool(context);
243:
244: try {
245: // pull the user object from the session
246: ScarabUser su = (ScarabUser) data.getUser().getTemp(
247: ScarabConstants.SESSION_REGISTER);
248: if (su == null) {
249: // assign the template to the cancel template, not the
250: // current template
251: template = getCancelTemplate(data, "Register.vm");
252: throw new ScarabRuntimeException(
253: L10NKeySet.UserObjectNotInSession);
254: }
255:
256: try {
257: // attempt to create a new user!
258: su.createNewUser();
259: } catch (org.apache.fulcrum.security.util.EntityExistsException e) {
260:
261: // The user already exists. Maybe he is DELETED ?
262: su = ScarabUserManager.reactivateUserIfDeleted(su);
263: if (su == null) {
264: Localizable msg = new L10NMessage(
265: L10NKeySet.ExceptionGeneric, e);
266: scarabR.setAlertMessage(msg);
267: setTarget(data, "Confirm.vm");
268: return;
269: }
270: }
271:
272: // grab the ScarabRequestTool object so that we can populate the
273: // User object for redisplay of the form data on the screen
274: if (scarabR != null) {
275: scarabR.setUser(su);
276: }
277:
278: // send an email that is for confirming the registration
279: sendConfirmationEmail(su, context);
280:
281: // set the next template on success
282: setTarget(data, nextTemplate);
283: } catch (Exception e) {
284: setTarget(data, template);
285: Localizable msg = new L10NMessage(
286: L10NKeySet.ExceptionGeneric, e);
287: scarabR.setAlertMessage(msg);
288: Log.get().error(e);
289: return;
290: }
291: }
292:
293: /**
294: * returns you to Register.vm
295: */
296: public void doBack(RunData data, TemplateContext context)
297: throws Exception {
298: // set the template to the template that we should be going back to
299: setTarget(data, data.getParameters().getString(
300: ScarabConstants.CANCEL_TEMPLATE, "Register.vm"));
301: }
302:
303: /**
304: * calls doRegisterConfirm()
305: */
306: public void doPerform(RunData data, TemplateContext context)
307: throws Exception {
308: doConfirmregistration(data, context);
309: }
310:
311: /**
312: * This manages clicking the Confirm button in the Confirm.vm
313: * template. As a result, this will end up sending
314: * the user to the Confirm screen.
315: */
316: public void doConfirm(RunData data, TemplateContext context)
317: throws Exception {
318: String template = getCurrentTemplate(data, null);
319: String nextTemplate = getNextTemplate(data, template);
320:
321: IntakeTool intake = getIntakeTool(context);
322: if (intake.isAllValid()) {
323: ScarabLocalizationTool l10n = getLocalizationTool(context);
324: ScarabRequestTool scarabR = getScarabRequestTool(context);
325: Object user = data.getUser().getTemp(
326: ScarabConstants.SESSION_REGISTER);
327: Group register = null;
328: if (user != null && user instanceof ScarabUser) {
329: register = intake.get("Register", ((ScarabUser) user)
330: .getQueryKey(), false);
331: } else {
332: register = intake.get("Register",
333: IntakeTool.DEFAULT_KEY, false);
334: }
335:
336: if (register == null) {
337: // This is often triggered by self-host issue SCB825.
338: scarabR
339: .setAlertMessage(L10NKeySet.RegisterGroupIsNullError);
340: String msg = "Register group is null: user="
341: + (user != null && user instanceof ScarabUser ? ((ScarabUser) user)
342: .getQueryKey()
343: : "[none]")
344: + " IntakeTool.DEFAULT_KEY="
345: + IntakeTool.DEFAULT_KEY;
346: Log.get().warn(msg);
347: return;
348: }
349: String username = null;
350: String confirm = null;
351: Field usernameField = register.get("UserName");
352: Field confirmField = register.get("Confirm");
353: if (usernameField == null) {
354: scarabR
355: .setAlertMessage(L10NKeySet.UsernameGroupIsNullError);
356: return;
357: } else if (confirmField == null) {
358: scarabR
359: .setAlertMessage(L10NKeySet.ConfirmFieldIsNullError);
360: return;
361: }
362: username = usernameField.toString();
363: confirm = confirmField.toString();
364:
365: // This reference to ScarabUserImpl is ok because this action
366: // is specific to use with that implementation.
367: if (ScarabUserImpl.checkConfirmationCode(username, confirm)) {
368: // update the database to confirm the user
369: if (ScarabUserImpl.confirmUser(username)) {
370: // NO PROBLEMS! :-)
371: ScarabUser confirmedUser = (ScarabUser) TurbineSecurity
372: .getUser(username);
373: // we set this to false and make people login again
374: // because of this issue:
375: // http://scarab.tigris.org/issues/show_bug.cgi?id=115
376: // there may be a better way, but given that on the confirm
377: // screen, we aren't asking for a password and checkConfirmationCode
378: // will return true if someone is already confirmed,
379: // we need to do this for security purposes.
380: confirmedUser.setHasLoggedIn(Boolean.FALSE);
381: data.setUser(confirmedUser);
382: data.save();
383:
384: scarabR
385: .setConfirmMessage(L10NKeySet.AccountConfirmedSuccess);
386: setTarget(data, nextTemplate);
387: } else {
388: scarabR
389: .setAlertMessage(L10NKeySet.AccountConfirmedFailure);
390: setTarget(data, template);
391: }
392: } else // we don't have confirmation! :-(
393: {
394: scarabR
395: .setAlertMessage(L10NKeySet.InvalidConfirmationCode);
396: setTarget(data, template);
397: }
398: }
399: }
400:
401: /**
402: * This manages clicking the "Resend code" button
403: * in the Confirm.vm template.
404: */
405: public void doResendconfirmationcode(RunData data,
406: TemplateContext context) throws Exception {
407: String template = getCurrentTemplate(data, null);
408: ScarabRequestTool scarabR = getScarabRequestTool(context);
409:
410: try {
411: Object user = data.getUser().getTemp(
412: ScarabConstants.SESSION_REGISTER);
413:
414: ScarabLocalizationTool l10n = getLocalizationTool(context);
415: IntakeTool intake = getIntakeTool(context);
416: Group register = null;
417: if (user != null && user instanceof ScarabUser) {
418: register = intake.get("Register", ((ScarabUser) user)
419: .getQueryKey(), false);
420: } else {
421: register = intake.get("Register",
422: IntakeTool.DEFAULT_KEY, false);
423: }
424:
425: if (register == null) {
426: scarabR
427: .setAlertMessage(L10NKeySet.RegisterGroupIsNullError);
428: return;
429: }
430: String username = register.get("UserName").toString();
431: try {
432: // Authenticate the user and get the object.
433: user = TurbineSecurity.getUser(username);
434:
435: // grab the ScarabRequestTool object so that we can
436: // populate the User object for redisplay of the form
437: // data on the screen
438: if (scarabR != null) {
439: scarabR.setUser((ScarabUser) user);
440: }
441: } catch (TurbineSecurityException e) {
442: scarabR.setAlertMessage(L10NKeySet.InvalidUsername);
443: Log.get().error("RegisterConfirm: ", e);
444: return;
445: }
446:
447: // send an email that is for confirming the registration
448: sendConfirmationEmail((ScarabUser) user, context);
449: scarabR.setConfirmMessage(L10NKeySet.ConfirmationCodeSent);
450:
451: // set the next template on success
452: data.getUser().setTemp(ScarabConstants.SESSION_REGISTER,
453: user);
454: intake.remove(register);
455:
456: setTarget(data, "Confirm.vm");
457: } catch (Exception e) {
458: setTarget(data, template);
459: Localizable msg = new L10NMessage(
460: L10NKeySet.ExceptionGeneric, e);
461: scarabR.setAlertMessage(msg);
462: Log.get().error(e);
463: return;
464: }
465: }
466:
467: /**
468: * For an email address like <code>jon@foo.bar.com</code>, parse
469: * and return the TLD <code>bar.com</code>.
470: */
471: String parseDomain(String email) {
472: String result = null;
473: char[] emailChars = email.toCharArray();
474: int dotCount = 0;
475: for (int i = emailChars.length - 1; i >= 0; i--) {
476: if (emailChars[i] == '.') {
477: dotCount++;
478: }
479: if (dotCount == 2 || emailChars[i] == '@') {
480: result = new String(emailChars, i + 1,
481: emailChars.length - (i + 1));
482: break;
483: }
484: }
485: return result;
486: }
487:
488: /**
489: * Send the confirmation code to the given user.
490: */
491: private void sendConfirmationEmail(ScarabUser su,
492: TemplateContext context) throws Exception {
493: Email te = new Email();
494:
495: // Retrieve the charset to be used for the Email.
496: ScarabLocalizationTool l10n = getLocalizationTool(context);
497: Locale locale = l10n.getPrimaryLocale();
498: String charset = Email.getCharset(locale);
499: te.setCharset(charset);
500:
501: te.setContext(new ContextAdapter(context));
502: te.setTo(su.getFirstName() + " " + su.getLastName(), su
503: .getEmail());
504: te.setFrom(Turbine.getConfiguration().getString(
505: "scarab.email.register.fromName", "Scarab System"),
506: Turbine.getConfiguration().getString(
507: "scarab.email.register.fromAddress",
508: "register@localhost"));
509: te.setSubject(L10NKeySet.ConfirmationSubject.getMessage(l10n));
510: te.setTemplate(Turbine.getConfiguration().getString(
511: "scarab.email.register.template",
512: "email/Confirmation.vm"));
513: te.send();
514: }
515: }
|