uk.co.jassoft.markets.api.UserController.java Source code

Java tutorial

Introduction

Here is the source code for uk.co.jassoft.markets.api.UserController.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package uk.co.jassoft.markets.api;

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import org.springframework.beans.factory.annotation.Value;
import uk.co.jassoft.email.EmailSenderService;
import uk.co.jassoft.markets.datamodel.error.ApiError;
import uk.co.jassoft.markets.datamodel.user.OAuth2Provider;
import uk.co.jassoft.markets.datamodel.user.User;
import uk.co.jassoft.markets.datamodel.user.UserBuilder;
import uk.co.jassoft.markets.datamodel.user.Users;
import uk.co.jassoft.markets.exceptions.user.*;
import uk.co.jassoft.markets.repository.UserRepository;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.util.*;

/**
 * @author Jonny
 */
@RestController
@RequestMapping("/user")
public class UserController extends BaseController {
    private static final Logger LOG = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private EmailSenderService emailSenderService;

    @Value("${OAUTH_GOOGLE_TOKEN}")
    private String oauthGoogleToken;

    private final PasswordEncoder encoder = new BCryptPasswordEncoder();

    @PreAuthorize("isFullyAuthenticated()")
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public @ResponseBody User getCurrentUser(final HttpServletResponse response) throws UnknownHostException {
        User user = getUser();

        response.setHeader("Cache-Control", "no-cache");
        return user.clean();
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public @ResponseBody User getUser(final HttpServletResponse response, @PathVariable String id)
            throws UnknownHostException {
        response.setHeader("Cache-Control", "no-cache");
        return userRepository.findOne(id).clean();
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "/{id}/role/{role}", method = RequestMethod.GET)
    public @ResponseBody User assignRoleToUser(final HttpServletResponse response, @PathVariable String id,
            @PathVariable String role) throws UnknownHostException {
        response.setHeader("Cache-Control", "no-cache");
        User user = userRepository.findOne(id);

        user.getRoles().add(role);

        return userRepository.save(user).clean();
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public @ResponseBody Users getUsers(final HttpServletResponse response) throws UnknownHostException {
        List<User> users = userRepository.findAll();

        Users usersToReturn = new Users();

        for (User user : users)
            usersToReturn.add(user.clean());

        response.setHeader("Cache-Control", "no-cache");
        return usersToReturn;
    }

    @PreAuthorize("isAnonymous()")
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public @ResponseBody User register(final HttpServletResponse response, @RequestBody User user)
            throws UnknownHostException, UserException {
        if (userRepository.findByEmail(user.getEmail()) != null)
            throw new UserExistsException("User Exists with Email " + user.getEmail());

        user.setPassword(encoder.encode(user.getPassword()));
        user.setActivationId(UUID.randomUUID().toString());

        user = userRepository.save(user);

        try {
            Map model = new HashMap();
            model.put("user", user);

            emailSenderService.send(user.getEmail(), "Market Reaction Account Confirmation", model);
        } catch (Exception exception) {
            LOG.error("Failed to send user confirmation email", exception);

            throw new UserConfirmationEmailFailedException(exception.getMessage());
        }

        response.setHeader("Cache-Control", "no-cache");
        return user.clean();
    }

    @PreAuthorize("isAnonymous()")
    @RequestMapping(value = "/register/confirm", method = RequestMethod.POST)
    public @ResponseBody User confirm(final HttpServletResponse response, @RequestBody String activationId)
            throws UnknownHostException, UserException {
        User user = userRepository.findByActivationId(activationId);

        if (user == null)
            throw new UnknownActivationCodeException("Activation Code " + activationId + " is not recognised");

        user.setActivated(true);

        userRepository.save(user);

        response.setHeader("Cache-Control", "no-cache");
        return user.clean();
    }

    @PreAuthorize("isAnonymous()")
    @RequestMapping(value = "/authenticate", method = RequestMethod.POST)
    public @ResponseBody User authenticate(final HttpServletResponse response,
            @RequestBody Map<String, String> credentials) throws UnknownHostException, UserException {
        User user = userRepository.findByEmail(credentials.get("email"));

        if (user == null)
            throw new UserNotExistsException("User does not Exist with Email " + credentials.get("email"));

        if (!encoder.matches(credentials.get("password"), user.getPassword()))
            throw new UserIncorrectCredentialsException(
                    "Credentials not valid for Email " + credentials.get("email"));

        if (!user.isActivated())
            throw new UserNotActivatedException("User not activated with Email " + credentials.get("email"));

        user.setToken(UUID.randomUUID().toString());
        user.setTokenExpiry(new DateTime(DateTimeZone.UTC).plusHours(24).toDate());
        user.setLastLogin(new Date());

        user = userRepository.save(user);

        response.setHeader("Cache-Control", "no-cache");
        return user.clean();
    }

    @PreAuthorize("isFullyAuthenticated()")
    @RequestMapping(value = "/logout", method = RequestMethod.POST)
    public @ResponseBody User logout(final HttpServletResponse response) throws UnknownHostException {
        User user = getUser();

        user.setToken(null);
        user.setTokenExpiry(new Date());

        user = userRepository.save(user);

        response.setHeader("Cache-Control", "no-cache");
        return user.clean();
    }

    @PreAuthorize("isFullyAuthenticated()")
    @RequestMapping(value = "/updatePassword", method = RequestMethod.POST)
    public @ResponseBody User updatePassword(final HttpServletResponse response,
            @RequestBody Map<String, String> passwords) throws UnknownHostException, UserException {

        User user = getUser();

        if (!encoder.matches(passwords.get("currentPassword"), user.getPassword()))
            throw new UserIncorrectCredentialsException("Current Password Invalid");

        if (!passwords.get("newPassword").equals(passwords.get("newPasswordConfirm")))
            throw new UserIncorrectCredentialsException("New passwords do not match");

        user.setPassword(encoder.encode(passwords.get("newPassword")));

        user = userRepository.save(user);

        response.setHeader("Cache-Control", "no-cache");
        return user.clean();
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "/{id}/enable", method = RequestMethod.GET)
    public @ResponseBody User enableUser(final HttpServletResponse response, @PathVariable String id)
            throws UnknownHostException {
        User user = userRepository.findOne(id);

        user.setActivated(true);

        userRepository.save(user);

        response.setHeader("Cache-Control", "no-cache");
        return user.clean();
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "/{id}/disable", method = RequestMethod.GET)
    public @ResponseBody User disableUser(final HttpServletResponse response, @PathVariable String id)
            throws UnknownHostException {
        User user = userRepository.findOne(id);

        user.setActivated(false);

        userRepository.save(user);

        response.setHeader("Cache-Control", "no-cache");
        return user.clean();
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "/{id}/delete", method = RequestMethod.GET)
    public @ResponseBody void deleteUser(final HttpServletResponse response, @PathVariable String id)
            throws UnknownHostException {
        response.setHeader("Cache-Control", "no-cache");
        userRepository.delete(id);
    }

    @PreAuthorize("isAnonymous()")
    @RequestMapping(value = "/oauth2/google", method = RequestMethod.POST)
    public @ResponseBody User oauth2(final HttpServletResponse response, @RequestBody String token)
            throws IOException, UserException, GeneralSecurityException {

        GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(),
                JacksonFactory.getDefaultInstance()).setAudience(Arrays.asList(oauthGoogleToken))
                        // If you retrieved the token on Android using the Play Services 8.3 API or newer, set
                        // the issuer to "https://accounts.google.com". Otherwise, set the issuer to
                        // "accounts.google.com". If you need to verify tokens from multiple sources, build
                        // a GoogleIdTokenVerifier for each issuer and try them both.
                        .setIssuer("accounts.google.com").build();

        // (Receive idTokenString by HTTPS POST)

        GoogleIdToken idToken = verifier.verify(token);
        if (idToken != null) {
            GoogleIdToken.Payload payload = idToken.getPayload();

            // Print user identifier
            //            String userId = payload.getSubject();
            //            System.out.println("User ID: " + userId);

            // Get profile information from payload
            String email = payload.getEmail();
            boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
            String familyName = (String) payload.get("family_name");
            String givenName = (String) payload.get("given_name");
            Date expiry = new Date(((Long) payload.get("exp")) * 1000);
            Date loggedIn = new Date(((Long) payload.get("iat")) * 1000);

            if (emailVerified) {

                User user = userRepository.findByEmail(email);

                if (user == null) {
                    // TODO - Create user
                    user = userRepository.save(
                            UserBuilder.anUser().withEmail(email).withForename(givenName).withSurname(familyName)
                                    .withActivated(true).withOAuth2Provider(OAuth2Provider.GOOGLE).build());
                }

                if (user.getoAuth2Provider() == null || !user.getoAuth2Provider().equals(OAuth2Provider.GOOGLE)) {
                    throw new UserExistsException("User Exists with Email " + user.getEmail());
                }

                user.setToken(UUID.randomUUID().toString());
                user.setTokenExpiry(expiry);
                user.setLastLogin(loggedIn);

                user = userRepository.save(user);

                response.setHeader("Cache-Control", "no-cache");
                return user.clean();
            }

        }

        throw new UserIncorrectCredentialsException("Invalid ID token");

    }

    @ExceptionHandler({ UserException.class })
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiError handleException(Exception exception) {
        if (exception instanceof UserExistsException)
            return new ApiError(101, exception.getMessage());

        if (exception instanceof UnknownActivationCodeException)
            return new ApiError(103, exception.getMessage());

        if (exception instanceof UserNotExistsException)
            return new ApiError(104, exception.getMessage());

        if (exception instanceof UserIncorrectCredentialsException)
            return new ApiError(105, exception.getMessage());

        if (exception instanceof UserNotActivatedException)
            return new ApiError(106, exception.getMessage());

        if (exception instanceof UserConfirmationEmailFailedException)
            return new ApiError(107, exception.getMessage());

        return new ApiError(999, "Unknown Error [" + exception.toString() + "]");
    }
}