AuthenticationController.java

package org.xandercat.pmdb.controller;

import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.xandercat.pmdb.dto.PmdbUser;
import org.xandercat.pmdb.exception.ServiceLimitExceededException;
import org.xandercat.pmdb.form.useradmin.UserForm;
import org.xandercat.pmdb.service.CollectionService;
import org.xandercat.pmdb.service.UserService;
import org.xandercat.pmdb.util.Alerts;
import org.xandercat.pmdb.util.ViewUtil;
import org.xandercat.pmdb.util.format.FormatUtil;

/**
 * Controller for basic authentication and registration functions.
 * 
 * @author Scott Arnold
 */
@Controller
public class AuthenticationController {

	private static final Logger LOGGER = LogManager.getLogger(AuthenticationController.class);
	
	@Value("${pmdb.environment}")
	private String environment;

	@Autowired
	private UserService userService;
	
	@Autowired
	private CollectionService collectionService;
	
	/**
	 * Page for presenting user login.
	 * 
	 * @param model  model
	 * 
	 * @return page for presenting user login
	 */
	@RequestMapping(value="/login.html", method=RequestMethod.GET)
	public String login(Model model) {
		model.addAttribute("environment", environment);
		return "authentication/login";
	}
	
	/**
	 * Page for presenting user login error.
	 * 
	 * @param model  model
	 * 
	 * @return page for presenting user login error
	 */
	@RequestMapping("/login-error.html")
	public String loginError(Model model) {
		model.addAttribute("loginError", "Unable to login.");
		model.addAttribute("environment", environment);
		return "authentication/login";
	}
	
	/**
	 * Process user login and redirect to user home page. Prepares session for user and updates user login information.
	 * 
	 * @param session  session
	 * 
	 * @return redirect to user home page
	 */
	@RequestMapping(value="/afterLogin.html", method=RequestMethod.GET)
	public String loginProcess(HttpSession session) {
		UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
		PmdbUser user = (PmdbUser) authentication.getPrincipal();
		LOGGER.info("User logged in: " + user.getUsername());
		userService.updateLastAccess(user.getUsername());
		try {
			ViewUtil.updateNumShareOffers(collectionService, session, user.getUsername());
		} catch (Exception e) {
			LOGGER.error("Unable to retrieve number of share offers for user.", e);
		}
		return "redirect:/";
	}
	
	/**
	 * Page for presenting new user registration.
	 * 
	 * @param model  model
	 * 
	 * @return page for presenting new user registration
	 */
	@RequestMapping(value="/loginRegister", method=RequestMethod.GET)
	public String register(Model model) {
		model.addAttribute("userForm", new UserForm());
		return "authentication/register";
	}
	
	/**
	 * Process new user registration and present registration result.
	 * 
	 * @param model     model
	 * @param userForm  user information form
	 * @param result    binding result
	 * 
	 * @return registration result page
	 */
	@RequestMapping(value="/loginRegisterSubmit", method=RequestMethod.POST)
	public String registerSubmit(Model model,
			@ModelAttribute("userForm") @Valid UserForm userForm,
			BindingResult result) {
		// password annotation ignores blank passwords, so need to check for that here
		if (FormatUtil.isBlank(userForm.getPasswordPair().getFirst())) {
			result.rejectValue("passwordPair", "{userform.password.required}", "Password cannot be blank.");
		}
		if (FormatUtil.isValidUsername(userForm.getUsername()) && userService.getUser(userForm.getUsername()).isPresent()) {
			result.rejectValue("username", "{userform.username.alreadyexists}", "A user with that username already exists.");
		}
		if (result.hasErrors()) {
			return "authentication/register";
		}
		PmdbUser user = userForm.toUser();
		try {
			userService.registerUser(user, userForm.getPasswordPair().getFirst().trim());
			model.addAttribute("registrationSuccess", Boolean.TRUE);
		} catch (ServiceLimitExceededException slee) {
			if (slee.isInitialTrigger()) {
				LOGGER.error("Excessive registrations.", slee);
			}
			Alerts.setErrorMessage(model, "Too many user accounts have been created in a short amount of time.  Please try again later.");
		} catch (Exception e) {
			LOGGER.error("Unable to register user.", e);
			Alerts.setErrorMessage(model, "The system was unable to register your account.");			
		}
		return "authentication/registerResult";
	}
}