org.osiam.addons.self_administration.controller.ChangeEmailController.java Source code

Java tutorial

Introduction

Here is the source code for org.osiam.addons.self_administration.controller.ChangeEmailController.java

Source

/*
 * Copyright (C) 2013 tarent AG
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package org.osiam.addons.self_administration.controller;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.osiam.addons.self_administration.Config;
import org.osiam.addons.self_administration.exception.OsiamException;
import org.osiam.addons.self_administration.one_time_token.OneTimeToken;
import org.osiam.addons.self_administration.template.RenderAndSendEmail;
import org.osiam.addons.self_administration.util.SelfAdministrationHelper;
import org.osiam.addons.self_administration.util.UserObjectMapper;
import org.osiam.client.OsiamConnector;
import org.osiam.client.exception.OsiamClientException;
import org.osiam.client.exception.OsiamRequestException;
import org.osiam.client.oauth.AccessToken;
import org.osiam.client.user.BasicUser;
import org.osiam.resources.helper.SCIMHelper;
import org.osiam.resources.scim.Email;
import org.osiam.resources.scim.Extension;
import org.osiam.resources.scim.ExtensionFieldType;
import org.osiam.resources.scim.UpdateUser;
import org.osiam.resources.scim.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.google.common.base.Optional;
import com.google.common.base.Strings;

/**
 * Controller for change E-Mail process.
 */
@Controller
@RequestMapping(value = "/email")
public class ChangeEmailController {

    private static final Logger LOGGER = LoggerFactory.getLogger(ChangeEmailController.class);

    @Autowired
    private UserObjectMapper mapper;

    @Autowired
    private RenderAndSendEmail renderAndSendEmailService;

    @Autowired
    private OsiamConnector osiamConnector;

    @Autowired
    private Config config;

    /**
     * Generates a HTTP form with the fields for change email purpose.
     */
    @RequestMapping(method = RequestMethod.GET)
    public void index(HttpServletResponse response) throws IOException {
        // load the html file as stream
        InputStream inputStream = getClass().getResourceAsStream("/change_email.html");
        String htmlContent = IOUtils.toString(inputStream, "UTF-8");
        // replacing the url
        String replacedAll = htmlContent.replace("$CHANGELINK", config.getClientEmailChangeUri());

        // replace all lib links
        replacedAll = replacedAll.replace("$BOOTSTRAP", config.getBootStrapLib());
        replacedAll = replacedAll.replace("$ANGULAR", config.getAngularLib());
        replacedAll = replacedAll.replace("$JQUERY", config.getJqueryLib());

        InputStream in = IOUtils.toInputStream(replacedAll);
        // set the content type
        response.setContentType("text/html");
        IOUtils.copy(in, response.getOutputStream());
    }

    /**
     * Saving the new E-Mail temporary, generating confirmation token and sending an E-Mail to the old registered
     * address.
     *
     * @param authorization
     *            Authorization header with HTTP Bearer authorization and a valid access token
     * @param newEmailValue
     *            The new email address value
     * @return The HTTP status code
     * @throws IOException
     *             If the updated user object can't mapped to json
     */
    @RequestMapping(method = RequestMethod.POST, value = "/change", produces = "application/json")
    public ResponseEntity<String> change(@RequestHeader("Authorization") final String authorization,
            @RequestParam("newEmailValue") final String newEmailValue) throws IOException {

        User updatedUser;
        final OneTimeToken confirmationToken = new OneTimeToken();
        try {
            updatedUser = getUpdatedUserForEmailChange(SelfAdministrationHelper.extractAccessToken(authorization),
                    newEmailValue, confirmationToken);
        } catch (OsiamRequestException e) {
            LOGGER.warn(e.getMessage());
            return SelfAdministrationHelper.createErrorResponseEntity(e.getMessage(),
                    HttpStatus.valueOf(e.getHttpStatusCode()));
        } catch (OsiamClientException e) {
            LOGGER.error(e.getMessage());
            return SelfAdministrationHelper.createErrorResponseEntity(e.getMessage(),
                    HttpStatus.INTERNAL_SERVER_ERROR);
        }

        String activateLink = SelfAdministrationHelper.createLinkForEmail(config.getEmailChangeLinkPrefix(),
                updatedUser.getId(), "confirmToken", confirmationToken.getToken());

        // build the Map with the link for replacement
        Map<String, Object> mailVariables = new HashMap<>();
        mailVariables.put("activatelink", activateLink);
        mailVariables.put("user", updatedUser);

        Locale locale = SelfAdministrationHelper.getLocale(updatedUser.getLocale());

        try {
            renderAndSendEmailService.renderAndSendEmail("changeemail", config.getFromAddress(), newEmailValue,
                    locale, mailVariables);
        } catch (OsiamException e) {
            String message = "Problems creating email for confirming new user: " + e.getMessage();
            LOGGER.error(message);
            return SelfAdministrationHelper.createErrorResponseEntity(message, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        return new ResponseEntity<>(mapper.writeValueAsString(updatedUser), HttpStatus.OK);
    }

    /**
     * Puts the new email an the confirmation token into the extensions of the user of the given token.
     *
     * @param token
     * @param newEmail
     * @param confirmationToken
     * @return User which has the values in his extension
     */
    private User getUpdatedUserForEmailChange(String token, String newEmail, OneTimeToken confirmationToken) {
        final AccessToken accessToken = new AccessToken.Builder(token).build();
        final BasicUser user = osiamConnector.getCurrentUserBasic(accessToken);

        final Extension extension = new Extension.Builder(Config.EXTENSION_URN)
                .setField(Config.CONFIRMATION_TOKEN_FIELD, confirmationToken.toString())
                .setField(Config.TEMP_EMAIL_FIELD, newEmail).build();

        final UpdateUser updateUser = new UpdateUser.Builder().updateExtension(extension).build();

        return osiamConnector.updateUser(user.getId(), updateUser, accessToken);
    }

    /**
     * Validating the confirm token and saving the new email value as primary email if the validation was successful.
     *
     * @param authorization
     *            Authorization header with HTTP Bearer authorization and a valid access token
     * @param userId
     *            The user id for the user whom email address should be changed
     * @param confirmationToken
     *            The previously generated confirmation token from the confirmation email
     * @return The HTTP status code and the updated user if successful
     * @throws IOException
     *
     */
    @RequestMapping(method = RequestMethod.POST, value = "/confirm", produces = "application/json")
    public ResponseEntity<String> confirm(@RequestHeader("Authorization") final String authorization,
            @RequestParam("userId") final String userId,
            @RequestParam("confirmToken") final String confirmationToken) throws IOException {

        if (Strings.isNullOrEmpty(confirmationToken)) {
            String message = "The submitted confirmation token is invalid!";
            LOGGER.warn(message);
            return SelfAdministrationHelper.createErrorResponseEntity(message, HttpStatus.FORBIDDEN);
        }

        User updatedUser;
        Optional<Email> oldEmail;

        try {
            AccessToken accessToken = new AccessToken.Builder(
                    SelfAdministrationHelper.extractAccessToken(authorization)).build();
            User user = osiamConnector.getUser(userId, accessToken);

            Extension extension = user.getExtension(Config.EXTENSION_URN);
            final OneTimeToken storedConfirmationToken = OneTimeToken
                    .fromString(extension.getFieldAsString(Config.CONFIRMATION_TOKEN_FIELD));

            if (storedConfirmationToken.isExpired(config.getConfirmationTokenTimeout())) {
                UpdateUser updateUser = new UpdateUser.Builder()
                        .deleteExtensionField(extension.getUrn(), Config.CONFIRMATION_TOKEN_FIELD)
                        .deleteExtensionField(extension.getUrn(), Config.TEMP_EMAIL_FIELD).build();
                osiamConnector.updateUser(userId, updateUser, accessToken);

                String message = "The submitted confirmation token is invalid!";
                LOGGER.warn(message);
                return SelfAdministrationHelper.createErrorResponseEntity(message, HttpStatus.FORBIDDEN);
            }

            if (!storedConfirmationToken.getToken().equals(confirmationToken)) {
                String message = "The submitted confirmation token is invalid!";
                LOGGER.warn(message);
                return SelfAdministrationHelper.createErrorResponseEntity(message, HttpStatus.FORBIDDEN);
            }

            String newEmail = extension.getField(Config.TEMP_EMAIL_FIELD, ExtensionFieldType.STRING);
            oldEmail = SCIMHelper.getPrimaryOrFirstEmail(user);

            UpdateUser updateUser = getPreparedUserForEmailChange(extension, newEmail, oldEmail.get());

            updatedUser = osiamConnector.updateUser(userId, updateUser, accessToken);
        } catch (OsiamRequestException e) {
            LOGGER.warn(e.getMessage());
            return SelfAdministrationHelper.createErrorResponseEntity(e.getMessage(),
                    HttpStatus.valueOf(e.getHttpStatusCode()));
        } catch (OsiamClientException e) {
            LOGGER.error(e.getMessage());
            return SelfAdministrationHelper.createErrorResponseEntity(e.getMessage(),
                    HttpStatus.INTERNAL_SERVER_ERROR);
        } catch (NoSuchElementException e) {
            String message = "The submitted confirmation token is invalid!";
            LOGGER.warn(message);
            return SelfAdministrationHelper.createErrorResponseEntity(message, HttpStatus.FORBIDDEN);
        }

        Locale locale = SelfAdministrationHelper.getLocale(updatedUser.getLocale());

        // build the Map with the link for replacement
        Map<String, Object> mailVariables = new HashMap<>();
        mailVariables.put("user", updatedUser);

        try {
            renderAndSendEmailService.renderAndSendEmail("changeemailinfo", config.getFromAddress(),
                    oldEmail.get().getValue(), locale, mailVariables);
        } catch (OsiamException e) {
            String message = "Problems creating email for confirming new user email: " + e.getMessage();
            LOGGER.error(message);
            return SelfAdministrationHelper.createErrorResponseEntity(message, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        return new ResponseEntity<>(mapper.writeValueAsString(updatedUser), HttpStatus.OK);
    }

    private UpdateUser getPreparedUserForEmailChange(Extension extension, String newEmail, Email oldEmail) {
        Email email = new Email.Builder(oldEmail).setValue(newEmail).build();

        return new UpdateUser.Builder().addEmail(email).deleteEmail(oldEmail)
                .deleteExtensionField(extension.getUrn(), Config.CONFIRMATION_TOKEN_FIELD)
                .deleteExtensionField(extension.getUrn(), Config.TEMP_EMAIL_FIELD).build();
    }
}