mitm.djigzo.web.pages.portal.secure.Signup.java Source code

Java tutorial

Introduction

Here is the source code for mitm.djigzo.web.pages.portal.secure.Signup.java

Source

/*
 * Copyright (c) 2011-2012, Martijn Brinkers, Djigzo.
 * 
 * This file is part of Djigzo email encryption.
 *
 * Djigzo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License 
 * version 3, 19 November 2007 as published by the Free Software 
 * Foundation.
 *
 * Djigzo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public 
 * License along with Djigzo. If not, see <http://www.gnu.org/licenses/>
 *
 * Additional permission under GNU AGPL version 3 section 7
 * 
 * If you modify this Program, or any covered work, by linking or 
 * combining it with saaj-api-1.3.jar, saaj-impl-1.3.jar, 
 * wsdl4j-1.6.1.jar (or modified versions of these libraries), 
 * containing parts covered by the terms of Common Development and 
 * Distribution License (CDDL), Common Public License (CPL) the 
 * licensors of this Program grant you additional permission to 
 * convey the resulting work.
 */
package mitm.djigzo.web.pages.portal.secure;

import java.net.URL;

import javax.servlet.http.HttpSession;

import mitm.application.djigzo.UserProperties;
import mitm.application.djigzo.james.PortalInvitationValidator;
import mitm.application.djigzo.james.PortalInvitationValidator.ValidatorException;
import mitm.application.djigzo.ws.LoginWS;
import mitm.application.djigzo.ws.PortalUserWS;
import mitm.application.djigzo.ws.SystemManagerWS;
import mitm.common.mail.EmailAddressUtils;
import mitm.common.properties.HierarchicalPropertiesException;
import mitm.common.ws.WebServiceCheckedException;
import mitm.djigzo.web.common.security.PortalUserDetailsServiceExt;
import mitm.djigzo.web.entities.UserManager;
import mitm.djigzo.web.utils.PasswordCodec;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.tapestry5.Asset;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.PersistenceConstants;
import org.apache.tapestry5.annotations.BeginRender;
import org.apache.tapestry5.annotations.Cached;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.IncludeStylesheet;
import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.corelib.components.Form;
import org.apache.tapestry5.corelib.components.PasswordField;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Value;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.RequestGlobals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.AbstractAuthenticationToken;
import org.springframework.security.providers.ProviderManager;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.ui.AbstractProcessingFilter;
import org.springframework.security.ui.WebAuthenticationDetails;
import org.springframework.security.ui.savedrequest.SavedRequest;
import org.springframework.security.userdetails.UserDetails;

@IncludeStylesheet("context:styles/pages/portal/secure/signup.css")
public class Signup {
    private final static Logger logger = LoggerFactory.getLogger(Signup.class);

    @SuppressWarnings("unused")
    @Inject
    @Path("context:images/logo.png")
    @Property
    private Asset logoAsset;

    @Inject
    private Request request;

    @Inject
    private ComponentResources resources;

    @Inject
    private Messages messages;

    @Inject
    private SystemManagerWS systemManagerWS;

    @Inject
    private UserManager userManager;

    @Inject
    private PasswordCodec passwordCodec;

    @Inject
    private PortalUserWS portalUserWS;

    @Inject
    private PortalUserDetailsServiceExt userDetailsService;

    @Inject
    private LoginWS loginWS;

    @Inject
    private ProviderManager authenticationManager;

    @Inject
    private RequestGlobals requestGlobals;

    /*
     * The new password for the user
     */
    private String newPassword;

    /*
     * Again the new password (should be the same as newPassword) 
     */
    private String repeatNewPassword;

    /*
     * True if and error has occurred
     */
    @Persist(PersistenceConstants.FLASH)
    private boolean error;

    /*
     * Error message if an error has occurred
     */
    @Persist(PersistenceConstants.FLASH)
    private String errorMessage;

    @Component(id = "newPassword", parameters = { "value = newPassword", "validate=required" })
    private PasswordField newPasswordField;

    @SuppressWarnings("unused")
    @Component(id = "repeatNewPassword", parameters = { "value = repeatNewPassword", "validate=required" })
    private PasswordField repeatNewPasswordField;

    @Component
    private Form form;

    /*
     * The email address request parameter
     */
    private String email;

    /*
     * The timestamp request parameter
     */
    private long timestamp;

    /*
     * The mac request parameter
     */
    private String mac;

    /*
     * The number of milliseconds a link is valid
     */
    @Inject
    @Value("${portal.selectpassword.validity}")
    private long validity;

    @Cached
    private UserProperties getUserProperties() throws WebServiceCheckedException {
        return userManager.getUser(email, true).getPreferences().getProperties();
    }

    @BeginRender
    public void beginRender() {
        /* 
         * Make sure userDetailsService has access to the required serviced
         */
        userDetailsService.setPasswordCodec(passwordCodec);
        userDetailsService.setLoginWS(loginWS);
    }

    protected Object onActivate() {
        if (!isBackendRunning()) {
            return null;
        }

        try {
            if (email == null) {
                email = EmailAddressUtils.canonicalizeAndValidate(request.getParameter("email"), true);
            }

            if (timestamp == 0) {
                timestamp = NumberUtils.toLong(request.getParameter("ts"), 0);
            }

            if (mac == null) {
                mac = StringUtils.trimToNull(request.getParameter("mac"));
            }

            if (email == null) {
                throw new ValidatorException("email is not set");
            }

            if (timestamp == 0) {
                throw new ValidatorException("timestamp is not set");
            }

            if (mac == null) {
                throw new ValidatorException("mac is not set");
            }

            if ((System.currentTimeMillis() - timestamp) > validity) {
                throw new ValidatorException(messages.get("sign-up-expired"));
            }

            if (StringUtils.isNotEmpty(getUserProperties().getPortalProperties().getPassword())) {
                /*
                 * A password was already set. Redirect to login page (this is also used to redirect to the
                 * login after the user has selected a portal password)
                 */
                return resources.createPageLink(Login.class, false, email);
            }
        } catch (Exception e) {
            errorMessage = e.getMessage();
            error = true;
        }

        return null;
    }

    private void validateParameters() throws ValidatorException {
        try {
            if ((System.currentTimeMillis() - timestamp) > validity) {
                throw new ValidatorException(messages.get("sign-up-expired"));
            }

            UserProperties userProperties = getUserProperties();

            /*
             * Validate the mac
             */
            PortalInvitationValidator validator = new PortalInvitationValidator();

            validator.setEmail(email);
            validator.setTimestamp(timestamp);
            String check = validator.calulateMAC(userProperties.getServerSecret());

            if (!StringUtils.equals(mac, check)) {
                throw new ValidatorException("The checksum is not correct");
            }

            if (StringUtils.isNotEmpty(userProperties.getPortalProperties().getPassword())) {
                /*
                 * A password was already set.
                 */
                throw new ValidatorException("Password was already set");
            }
        } catch (WebServiceCheckedException e) {
            throw new ValidatorException(e);
        } catch (HierarchicalPropertiesException e) {
            throw new ValidatorException(e);
        }
    }

    protected void onActivate(String email, long timestamp, String mac) {
        this.email = StringUtils.trimToNull(email);
        this.timestamp = timestamp;
        this.mac = StringUtils.trimToNull(mac);
    }

    public Object[] onPassivate() {
        return new Object[] { email, timestamp, mac };
    }

    public void onValidateForm() {
        try {
            if (StringUtils.isEmpty(newPassword)) {
                return;
            }

            if (StringUtils.isEmpty(repeatNewPassword)) {
                return;
            }

            if (!StringUtils.equals(newPassword, repeatNewPassword)) {
                form.recordError(newPasswordField, messages.get("passwords-not-equal"));

                return;
            }

            validateParameters();
        } catch (Exception e) {
            form.recordError("There was a problem. Message: " + e.getMessage());

            logger.error("Error validating form", e);
        }
    }

    /*
     * Retrieves that target URL which was saved by Spring when being redirected to the signup page
     */
    private String getSavedTarget() {
        HttpSession session = requestGlobals.getHTTPServletRequest().getSession(false);

        if (session == null) {
            return null;
        }

        /*
         * Get the saved request from the HTTP session
         */
        SavedRequest savedRequest = (SavedRequest) session
                .getAttribute(AbstractProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY);

        String target = null;

        if (savedRequest != null) {
            target = savedRequest.getFullRequestUrl();

            /*
             * Clear the saved request since we have handled it
             */
            session.removeAttribute(AbstractProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY);
        }

        return target;
    }

    public Object onSuccess() {
        Object result = null;

        try {
            portalUserWS.setEncodedPassword(email, passwordCodec.encodePassword(newPassword));

            authenticate(email, newPassword);

            /*
             * get the saved request from Spring (if any)
             */
            String target = getSavedTarget();

            if (StringUtils.isNotEmpty(target)) {
                logger.debug("redirecting to {}", target);

                result = new URL(target);
            }
        } catch (Exception e) {
            error = true;
            errorMessage = e.getMessage();

            logger.error("Error setting password", e);
        }

        return result;
    }

    /**
     * Programatically authenticate the user
     */
    public void authenticate(String username, String password) {
        try {
            UserDetails details = userDetailsService.loadUserByUsername(username);

            UsernamePasswordAuthenticationToken usernameAndPassword = new UsernamePasswordAuthenticationToken(
                    username, password, details.getAuthorities());

            /*
             * Add details about the authentication (IP address etc.)
             */
            ((AbstractAuthenticationToken) usernameAndPassword)
                    .setDetails(new WebAuthenticationDetails(requestGlobals.getHTTPServletRequest()));

            /*
             * Authenticate, to be 100% certain that username/password is correct
             */
            Authentication authentication = authenticationManager.doAuthentication(usernameAndPassword);

            SecurityContext securityContext = SecurityContextHolder.getContext();

            securityContext.setAuthentication(authentication);

            /*
             * The SecurityContext must be placed in the HTTP session otherwise Spring will not use it
             */
            requestGlobals.getHTTPServletRequest().getSession(true)
                    .setAttribute(HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY, securityContext);
        } catch (AuthenticationException e) {
            SecurityContextHolder.getContext().setAuthentication(null);

            logger.error("Login failed after registration.", e);

            throw e;
        }
    }

    public String getEmail() {
        return email;
    }

    public String getNewPassword() {
        return newPassword;
    }

    public void setNewPassword(String newPassword) {
        this.newPassword = newPassword;
    }

    public String getRepeatNewPassword() {
        return repeatNewPassword;
    }

    public void setRepeatNewPassword(String repeatNewPassword) {
        this.repeatNewPassword = repeatNewPassword;
    }

    public boolean isError() {
        return error;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    @Cached
    public boolean isBackendRunning() {
        boolean running;

        try {
            running = systemManagerWS.isRunning();
        } catch (Exception e) {
            logger.error("Error in isBackendRunning. Backend is propably not running.", e);

            running = false;
        }

        return running;
    }
}