/* * RegisterServlet.java * * Version: $Revision: 3705 $ * * Date: $Date: 2009-04-11 17:02:24 +0000 (Sat, 11 Apr 2009) $ * * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts * Institute of Technology. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of the Hewlett-Packard Company nor the name of the * Massachusetts Institute of Technology nor the names of their * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ package org.dspace.app.webui.servlet; import com.sun.mail.smtp.SMTPAddressFailedException; import org.apache.log4j.Logger; import org.dspace.app.webui.util.JSPManager; import org.dspace.app.webui.util.UIUtil; import org.dspace.authenticate.AuthenticationManager; import org.dspace.authorize.AuthorizeException; import org.dspace.core.*; import org.dspace.eperson.AccountManager; import org.dspace.eperson.EPerson; import javax.mail.MessagingException; import javax.mail.internet.AddressException; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.sql.SQLException; import java.util.Hashtable; /** * Servlet for handling user registration and forgotten passwords. * <P> * This servlet handles both forgotten passwords and initial registration of * users. Which it handles depends on the initialisation parameter "register" - * if it's "true", it is treated as an initial registration and the user is * asked to input their personal information. * <P> * The sequence of events is this: The user clicks on "register" or "I forgot my * password." This servlet then displays the relevant "enter your e-mail" form. * An e-mail address is POSTed back, and if this is valid, a token is created * and e-mailed, otherwise an error is displayed, with another "enter your * e-mail" form. * <P> * When the user clicks on the token URL mailed to them, this servlet receives a * GET with the token as the parameter "KEY". If this is a valid token, the * servlet then displays the "edit profile" or "edit password" screen as * appropriate. */ public class RegisterServlet extends DSpaceServlet { /** Logger */ private static Logger log = Logger.getLogger(RegisterServlet.class); /** The "enter e-mail" step */ public static final int ENTER_EMAIL_PAGE = 1; /** The "enter personal info" page, for a registering user */ public static final int PERSONAL_INFO_PAGE = 2; /** The simple "enter new password" page, for user who's forgotten p/w */ public static final int NEW_PASSWORD_PAGE = 3; /** true = registering users, false = forgotten passwords */ private boolean registering; /** ldap is enabled */ private boolean ldap_enabled; public void init() { registering = getInitParameter("register").equalsIgnoreCase("true"); ldap_enabled = ConfigurationManager.getBooleanProperty("ldap.enable"); } protected void doDSGet(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException { /* * Respond to GETs. A simple GET with no parameters will display the * relevant "type in your e-mail" form. A GET with a "token" parameter * will go to the "enter personal info" or "enter new password" page as * appropriate. */ boolean updated = false; // Get the token String token = request.getParameter("token"); if (token == null) { // Simple "enter your e-mail" page if (registering) { // Registering a new user if (ldap_enabled) JSPManager.showJSP(request, response, "/register/new-ldap-user.jsp"); JSPManager.showJSP(request, response, "/register/new-user.jsp"); } else { // User forgot their password JSPManager.showJSP(request, response, "/register/forgot-password.jsp"); } } else { // We have a token. Find out who the it's for String email = AccountManager.getEmail(context, token); EPerson eperson = null; if (email != null) { eperson = EPerson.findByEmail(context, email); } // Both forms need an EPerson object (if any) request.setAttribute("eperson", eperson); // And the token request.setAttribute("token", token); if (registering && (email != null)) { // Indicate if user can set password boolean setPassword = AuthenticationManager.allowSetPassword(context, request, email); request.setAttribute("set.password", new Boolean(setPassword)); // Forward to "personal info page" JSPManager.showJSP(request, response, "/register/registration-form.jsp"); } else if (!registering && (eperson != null)) { // Token relates to user who's forgotten password JSPManager.showJSP(request, response, "/register/new-password.jsp"); } else { // Duff token! JSPManager.showJSP(request, response, "/register/invalid-token.jsp"); return; } } } protected void doDSPost(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException { /* * POSTs are the result of entering an e-mail in the "forgot my * password" or "new user" forms, or the "enter profile information" or * "enter new password" forms. */ // First get the step int step = UIUtil.getIntParameter(request, "step"); switch (step) { case ENTER_EMAIL_PAGE: processEnterEmail(context, request, response); break; case PERSONAL_INFO_PAGE: processPersonalInfo(context, request, response); break; case NEW_PASSWORD_PAGE: processNewPassword(context, request, response); break; default: log.warn(LogManager.getHeader(context, "integrity_error", UIUtil .getRequestLogInfo(request))); JSPManager.showIntegrityError(request, response); } } /** * Process information from the "enter e-mail" page. If the e-mail * corresponds to a valid user of the system, a token is generated and sent * to that user. * * @param context * current DSpace context * @param request * current servlet request object * @param response * current servlet response object */ private void processEnterEmail(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException { String email = request.getParameter("email"); if (email == null || email.length() > 64) { // Malformed request or entered value is too long. email = ""; } else { email = email.toLowerCase().trim(); } String netid = request.getParameter("netid"); String password = request.getParameter("password"); EPerson eperson = EPerson.findByEmail(context, email); EPerson eperson2 = null; if (netid!=null) eperson2 = EPerson.findByNetid(context, netid.toLowerCase()); try { if (registering) { // If an already-active user is trying to register, inform them so if ((eperson != null && eperson.canLogIn()) || (eperson2 != null && eperson2.canLogIn())) { log.info(LogManager.getHeader(context, "already_registered", "email=" + email)); JSPManager.showJSP(request, response, "/register/already-registered.jsp"); } else { // Find out from site authenticator whether this email can // self-register boolean canRegister = AuthenticationManager.canSelfRegister(context, request, email); if (canRegister) { //-- registering by email if ((!ldap_enabled)||(netid==null)||(netid.trim().equals(""))) { // OK to register. Send token. log.info(LogManager.getHeader(context, "sendtoken_register", "email=" + email)); try { AccountManager.sendRegistrationInfo(context, email); } catch (javax.mail.SendFailedException e) { if (e.getNextException() instanceof SMTPAddressFailedException) { // If we reach here, the email is email is invalid for the SMTP server (i.e. fbotelho). log.info(LogManager.getHeader(context, "invalid_email", "email=" + email)); request.setAttribute("retry", new Boolean(true)); JSPManager.showJSP(request, response, "/register/new-user.jsp"); return; } else { throw e; } } JSPManager.showJSP(request, response, "/register/registration-sent.jsp"); // Context needs completing to write registration data context.complete(); } //-- registering by netid else { //--------- START LDAP AUTH SECTION ------------- if (password!=null && !password.equals("")) { String ldap_provider_url = ConfigurationManager.getProperty("ldap.provider_url"); String ldap_id_field = ConfigurationManager.getProperty("ldap.id_field"); String ldap_search_context = ConfigurationManager.getProperty("ldap.search_context"); // Set up environment for creating initial context Hashtable env = new Hashtable(11); env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(javax.naming.Context.PROVIDER_URL, ldap_provider_url); // Authenticate env.put(javax.naming.Context.SECURITY_AUTHENTICATION, "simple"); env.put(javax.naming.Context.SECURITY_PRINCIPAL, ldap_id_field+"="+netid+","+ldap_search_context); env.put(javax.naming.Context.SECURITY_CREDENTIALS, password); try { // Create initial context DirContext ctx = new InitialDirContext(env); // Close the context when we're done ctx.close(); } catch (NamingException e) { // If we reach here, supplied email/password was duff. log.info(LogManager.getHeader(context, "failed_login", "netid=" + netid + e)); JSPManager.showJSP(request, response, "/login/ldap-incorrect.jsp"); return; } } //--------- END LDAP AUTH SECTION ------------- // Forward to "personal info page" JSPManager.showJSP(request, response, "/register/registration-form.jsp"); } } else { JSPManager.showJSP(request, response, "/register/cannot-register.jsp"); } } } else { if (eperson == null) { // Invalid email address log.info(LogManager.getHeader(context, "unknown_email", "email=" + email)); request.setAttribute("retry", new Boolean(true)); JSPManager.showJSP(request, response, "/register/forgot-password.jsp"); } else if (!eperson.canLogIn()) { // Can't give new password to inactive user log.info(LogManager.getHeader(context, "unregistered_forgot_password", "email=" + email)); JSPManager.showJSP(request, response, "/register/inactive-account.jsp"); } else if (eperson.getRequireCertificate() && !registering) { // User that requires certificate can't get password log.info(LogManager.getHeader(context, "certificate_user_forgot_password", "email=" + email)); JSPManager.showJSP(request, response, "/error/require-certificate.jsp"); } else { // OK to send forgot pw token. log.info(LogManager.getHeader(context, "sendtoken_forgotpw", "email=" + email)); AccountManager.sendForgotPasswordInfo(context, email); JSPManager.showJSP(request, response, "/register/password-token-sent.jsp"); // Context needs completing to write registration data context.complete(); } } } catch (AddressException ae) { // Malformed e-mail address log.info(LogManager.getHeader(context, "bad_email", "email=" + email)); request.setAttribute("retry", new Boolean(true)); if (registering) { if (ldap_enabled) JSPManager.showJSP(request, response, "/register/new-ldap-user.jsp"); else JSPManager.showJSP(request, response, "/register/new-user.jsp"); } else { JSPManager.showJSP(request, response, "/register/forgot-password.jsp"); } } catch (MessagingException me) { // Some other mailing error log.info(LogManager.getHeader(context, "error_emailing", "email=" + email), me); JSPManager.showInternalError(request, response); } } /** * Process information from "Personal information page" * * @param context * current DSpace context * @param request * current servlet request object * @param response * current servlet response object */ private void processPersonalInfo(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException { // Get the token String token = request.getParameter("token"); // Get the email address String email = AccountManager.getEmail(context, token); String netid = request.getParameter("netid"); if ((netid!=null)&&(email==null)) email = request.getParameter("email"); // If the token isn't valid, show an error if (email == null && netid==null) { log.info(LogManager.getHeader(context, "invalid_token", "token=" + token)); // Invalid token JSPManager .showJSP(request, response, "/register/invalid-token.jsp"); return; } // If the token is valid, we create an eperson record if need be EPerson eperson = null; if (email!=null) eperson = EPerson.findByEmail(context, email); EPerson eperson2 = null; if (netid!=null) eperson2 = EPerson.findByNetid(context, netid.toLowerCase()); if (eperson2 !=null) eperson = eperson2; if (eperson == null) { // Need to create new eperson // FIXME: TEMPORARILY need to turn off authentication, as usually // only site admins can create e-people context.setIgnoreAuthorization(true); eperson = EPerson.create(context); eperson.setEmail(email); if (netid!=null) eperson.setNetid(netid.toLowerCase()); eperson.update(); context.setIgnoreAuthorization(false); } // Now set the current user of the context // to the user associated with the token, so they can update their // info context.setCurrentUser(eperson); // Set the user profile info boolean infoOK = EditProfileServlet.updateUserProfile(eperson, request); eperson.setCanLogIn(true); eperson.setSelfRegistered(true); // Give site auth a chance to set/override appropriate fields AuthenticationManager.initEPerson(context, request, eperson); // If the user set a password, make sure it's OK boolean passwordOK = true; if (eperson.getRequireCertificate() == false && netid==null && AuthenticationManager.allowSetPassword(context, request, eperson.getEmail())) { passwordOK = EditProfileServlet.confirmAndSetPassword(eperson, request); } if (infoOK && passwordOK) { // All registered OK. log.info(LogManager.getHeader(context, "usedtoken_register", "email=" + eperson.getEmail())); // delete the token if (token!=null) AccountManager.deleteToken(context, token); // Update user record eperson.update(); request.setAttribute("eperson", eperson); JSPManager.showJSP(request, response, "/register/registered.jsp"); context.complete(); } else { request.setAttribute("token", token); request.setAttribute("eperson", eperson); request.setAttribute("netid", netid); request.setAttribute("missing.fields", new Boolean(!infoOK)); request.setAttribute("password.problem", new Boolean(!passwordOK)); // Indicate if user can set password boolean setPassword = AuthenticationManager.allowSetPassword( context, request, email); request.setAttribute("set.password", new Boolean(setPassword)); JSPManager.showJSP(request, response, "/register/registration-form.jsp"); // Changes to/creation of e-person in DB cancelled context.abort(); } } /** * Process information from "enter new password" * * @param context * current DSpace context * @param request * current servlet request object * @param response * current servlet response object */ private void processNewPassword(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException { // Get the token String token = request.getParameter("token"); // Get the eperson associated with the password change EPerson eperson = AccountManager.getEPerson(context, token); // If the token isn't valid, show an error if (eperson == null) { log.info(LogManager.getHeader(context, "invalid_token", "token=" + token)); // Invalid token JSPManager .showJSP(request, response, "/register/invalid-token.jsp"); return; } // If the token is valid, we set the current user of the context // to the user associated with the token, so they can update their // info context.setCurrentUser(eperson); // Confirm and set the password boolean passwordOK = EditProfileServlet.confirmAndSetPassword(eperson, request); if (passwordOK) { log.info(LogManager.getHeader(context, "usedtoken_forgotpw", "email=" + eperson.getEmail())); eperson.update(); AccountManager.deleteToken(context, token); JSPManager.showJSP(request, response, "/register/password-changed.jsp"); context.complete(); } else { request.setAttribute("password.problem", new Boolean(true)); request.setAttribute("token", token); request.setAttribute("eperson", eperson); JSPManager.showJSP(request, response, "/register/new-password.jsp"); } } }