/**
* Copyright (C) 2011 JTalks.org Team
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jtalks.jcommune.web.controller;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang.StringUtils;
import org.jtalks.common.model.entity.Group;
import org.jtalks.jcommune.model.dto.LoginUserDto;
import org.jtalks.jcommune.model.dto.RegisterUserDto;
import org.jtalks.jcommune.model.dto.UserDto;
import org.jtalks.jcommune.model.entity.JCUser;
import org.jtalks.jcommune.model.entity.Language;
import org.jtalks.jcommune.plugin.api.core.ExtendedPlugin;
import org.jtalks.jcommune.plugin.api.core.Plugin;
import org.jtalks.jcommune.plugin.api.core.RegistrationPlugin;
import org.jtalks.jcommune.plugin.api.exceptions.NoConnectionException;
import org.jtalks.jcommune.plugin.api.exceptions.NotFoundException;
import org.jtalks.jcommune.plugin.api.exceptions.UnexpectedErrorException;
import org.jtalks.jcommune.plugin.api.filters.TypeFilter;
import org.jtalks.jcommune.plugin.api.web.dto.json.JsonResponse;
import org.jtalks.jcommune.plugin.api.web.dto.json.JsonResponseStatus;
import org.jtalks.jcommune.service.*;
import org.jtalks.jcommune.service.exceptions.MailingFailedException;
import org.jtalks.jcommune.service.exceptions.UserTriesActivatingAccountAgainException;
import org.jtalks.jcommune.service.nontransactional.MailService;
import org.jtalks.jcommune.service.util.AuthenticationStatus;
import org.jtalks.jcommune.web.dto.RestorePasswordDto;
import org.jtalks.jcommune.web.interceptors.RefererKeepInterceptor;
import org.jtalks.jcommune.web.util.MutableHttpRequest;
import org.jtalks.jcommune.web.validation.editors.DefaultStringEditor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.support.RequestContextUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* This controller handles custom authentication actions
* like user registration or password restore.
* <p/>
* Basic actions like username/password verification are
* to be performed by Spring Security
*
* @author Evgeniy Naumenko
* @author Andrey Pogorelov
*/
@Controller
public class UserController {
public static final String REGISTRATION = "registration";
public static final String LOGIN = "login";
public static final String AFTER_REGISTRATION = "afterRegistration";
public static final String REFERER_ATTR = "referer";
public static final String AUTH_FAIL_URL = "redirect:/login?login_error=1";
public static final String AUTH_SERVICE_FAIL_URL = "redirect:/login?login_error=3";
public static final String REG_SERVICE_CONNECTION_ERROR_URL = "redirect:/user/new?reg_error=1";
public static final String REG_SERVICE_UNEXPECTED_ERROR_URL = "redirect:/user/new?reg_error=2";
public static final String REG_SERVICE_HONEYPOT_FILLED_ERROR_URL = "redirect:/user/new?reg_error=3";
public static final String REG_SERVICE_SPAM_PROTECTION_ERROR_URL = "redirect:/user/new?reg_error=4";
public static final String USER_SEARCH = "userSearch";
public static final String NULL_REPRESENTATION = "null";
public static final String MAIN_PAGE_REFERER = "/";
public static final String CUSTOM_ERROR = "customError";
public static final String CONNECTION_ERROR = "connectionError";
public static final String UNEXPECTED_ERROR = "unexpectedError";
public static final String HONEYPOT_CAPTCHA_ERROR = "honeypotCaptchaNotNull";
public static final String SPAM_PROTECTION_ERROR = "spamProtectionError";
public static final String LOGIN_DTO = "loginUserDto";
public static final String USERS_ATTR_NAME ="users";
public static final String GROUPS_ATTR_NAME ="groups";
protected static final String ATTR_USERNAME = "username";
private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);
private static final String REMEMBER_ME_ON = "on";
private final UserService userService;
private final Authenticator authenticator;
private final PluginService pluginService;
private final UserService plainPasswordUserService;
private final MailService mailService;
private final RetryTemplate retryTemplate;
private final ComponentService componentService;
private final GroupService groupService;
private final SpamProtectionService spamProtectionService;
private final RequestCache requestCache;
/**
* @param userService to delegate business logic invocation
* @param authenticator default authenticator
* @param pluginService for communication with available registration or authentication plugins
* @param plainPasswordUserService strategy for authenticating by password without hashing
* @param mailService to send account confirmation
* @param componentService to check component permissions
* @param spamProtectionService to check is email in blacklist
*/
@Autowired
public UserController(UserService userService, Authenticator authenticator, PluginService pluginService,
UserService plainPasswordUserService, MailService mailService,
RetryTemplate retryTemplate, ComponentService componentService,
GroupService groupService, SpamProtectionService spamProtectionService,
RequestCache requestCache) {
this.userService = userService;
this.authenticator = authenticator;
this.pluginService = pluginService;
this.plainPasswordUserService = plainPasswordUserService;
this.mailService = mailService;
this.retryTemplate = retryTemplate;
this.componentService = componentService;
this.groupService = groupService;
this.spamProtectionService = spamProtectionService;
this.requestCache = requestCache;
}
/**
* This method turns the trim binder on. Trim binder
* removes leading and trailing spaces from the submitted fields.
* So, it ensures, that all validations will be applied to
* trimmed field values only.
* <p/> There is no need for trim edit password fields,
* so they are processed with {@link DefaultStringEditor}
*
* @param binder Binder object to be injected
*/
@InitBinder({"dto", "newUser"})
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
binder.registerCustomEditor(String.class, "userDto.username", new StringTrimmerEditor(false));
binder.registerCustomEditor(String.class, "userDto.password", new DefaultStringEditor(false));
binder.registerCustomEditor(String.class, "passwordConfirm", new DefaultStringEditor(false));
}
/**
* Renders a page to restore user's password.
* Registration e-mail is required.
*
* @return view page name
*/
@RequestMapping(value = "/password/restore", method = RequestMethod.GET)
public ModelAndView showRestorePasswordPage() {
return new ModelAndView("restorePassword")
.addObject("dto", new RestorePasswordDto());
}
/**
* Tries to restore a password by email.
* If e-mail given has not been registered
* before view with an error will be returned.
*
* @param dto with email address to identify the user
* @param result email validation result
* @return view with a parameters bound
*/
@RequestMapping(value = "/password/restore", method = RequestMethod.POST)
public ModelAndView restorePassword(@Valid @ModelAttribute("dto") RestorePasswordDto dto, BindingResult result) {
ModelAndView mav = new ModelAndView("restorePassword");
if (result.hasErrors()) {
return mav;
}
try {
userService.restorePassword(dto.getUserEmail());
mav.addObject("message", "label.restorePassword.completed");
} catch (MailingFailedException e) {
result.addError(new FieldError("dto", "email", "email.failed"));
}
return mav;
}
/**
* Render registration page with bind objects to form.
* Also checks if user is already logged in.
* If so he is redirected to main page.
*
* @param request Servlet request.
* @param locale To set currently selected language as user's default
* @return {@code ModelAndView} with "registration" view, any additional html from registration plugins and
* {@link org.jtalks.jcommune.model.dto.RegisterUserDto} with name "newUser
*/
@RequestMapping(value = "/user/new", method = RequestMethod.GET)
public ModelAndView registrationPage(HttpServletRequest request, Locale locale) {
JCUser currentUser = userService.getCurrentUser();
if (currentUser.isAnonymous()) {
Map<String, String> registrationPlugins = getRegistrationPluginsHtml(request, locale);
return new ModelAndView(REGISTRATION)
.addObject("newUser", new RegisterUserDto())
.addObject("registrationPlugins", registrationPlugins);
} else {
return new ModelAndView("redirect:" + MAIN_PAGE_REFERER);
}
}
/**
* Register {@link org.jtalks.jcommune.model.entity.JCUser} from populated in form {@link RegisterUserDto}.
* <p/>
* todo: redirect to the latest url we came from instead of root
*
* @param registerUserDto {@link RegisterUserDto} populated in form
* @param request Servlet request.
* @param locale to set currently selected language as user's default
* @return redirect to / if registration successful or back to "/registration" if failed
*/
@RequestMapping(value = "/user/new", method = RequestMethod.POST)
public ModelAndView registerUser(@ModelAttribute("newUser") RegisterUserDto registerUserDto,
HttpServletRequest request,
Locale locale) {
if (isHoneypotCaptchaFilled(registerUserDto, getClientIpAddress(request))) {
return new ModelAndView(REG_SERVICE_HONEYPOT_FILLED_ERROR_URL);
}
UserDto userDto = registerUserDto.getUserDto();
if (spamProtectionService.isEmailInBlackList(userDto.getEmail())) {
logBotInfo(userDto, request);
return new ModelAndView(REG_SERVICE_SPAM_PROTECTION_ERROR_URL);
}
Map<String, String> registrationPlugins = getRegistrationPluginsHtml(request, locale);
BindingResult errors;
try {
userDto.setLanguage(Language.byLocale(locale));
errors = authenticator.register(registerUserDto);
} catch (NoConnectionException e) {
return new ModelAndView(REG_SERVICE_CONNECTION_ERROR_URL);
} catch (UnexpectedErrorException e) {
return new ModelAndView(REG_SERVICE_UNEXPECTED_ERROR_URL);
}
if (errors.hasErrors()) {
ModelAndView mav = new ModelAndView(REGISTRATION);
mav.addObject("registrationPlugins", registrationPlugins);
mav.addAllObjects(errors.getModel());
return mav;
}
return new ModelAndView(AFTER_REGISTRATION);
}
/**
* Register {@link org.jtalks.jcommune.model.entity.JCUser} from populated {@link RegisterUserDto}.
* <p/>
*
* @param registerUserDto {@link RegisterUserDto} populated in form
* @param request Servlet request.
* @param locale to set currently selected language as user's default
* @return redirect validation result in JSON format
*/
@RequestMapping(value = "/user/new_ajax", method = RequestMethod.POST)
@ResponseBody
public JsonResponse registerUserAjax(@ModelAttribute("newUser") RegisterUserDto registerUserDto,
HttpServletRequest request,
Locale locale) {
if (isHoneypotCaptchaFilled(registerUserDto, getClientIpAddress(request))) {
return getCustomErrorJsonResponse(HONEYPOT_CAPTCHA_ERROR);
}
UserDto userDto = registerUserDto.getUserDto();
if (spamProtectionService.isEmailInBlackList(userDto.getEmail())) {
logBotInfo(userDto, request);
return getCustomErrorJsonResponse(SPAM_PROTECTION_ERROR);
}
BindingResult errors;
try {
userDto.setLanguage(Language.byLocale(locale));
errors = authenticator.register(registerUserDto);
} catch (NoConnectionException e) {
return getCustomErrorJsonResponse(CONNECTION_ERROR);
} catch (UnexpectedErrorException e) {
return getCustomErrorJsonResponse(UNEXPECTED_ERROR);
}
if (errors.hasErrors()) {
return new JsonResponse(JsonResponseStatus.FAIL, errors.getAllErrors());
}
return new JsonResponse(JsonResponseStatus.SUCCESS);
}
private void logBotInfo(UserDto userDto, HttpServletRequest request) {
LOGGER.warn("Spam protection alert! Bot tries to register. Username - [{}], email - [{}], ip - [{}]",
new String[]{userDto.getUsername(),
userDto.getEmail(), getClientIpAddress(request)});
}
/**
* Detects the presence honeypot captcha filing error.
* If honeypot captcha filled it means that bot try to register. .
* @see <a href="http://jira.jtalks.org/browse/JC-1750">JIRA issue</a>
*/
private boolean isHoneypotCaptchaFilled(RegisterUserDto registerUserDto, String ip) {
if (registerUserDto.getHoneypotCaptcha() != null) {
LOGGER.warn("Bot tried to register. Username - {}, email - {}, ip - {}",
new String[]{registerUserDto.getUserDto().getUsername(),
registerUserDto.getUserDto().getEmail(),ip});
return true;
}
return false;
}
private JsonResponse getCustomErrorJsonResponse(String customError) {
return new JsonResponse(JsonResponseStatus.FAIL,
new ImmutableMap.Builder<String, String>().put(CUSTOM_ERROR, customError).build());
}
/**
* Get html from available registration plugins.
*
* @param request request
* @param locale user locale
* @return map as pairs pluginId - html
*/
private Map<String, String> getRegistrationPluginsHtml(HttpServletRequest request, Locale locale) {
Map<String, String> registrationPlugins = new HashMap<>();
for (Map.Entry<Long, RegistrationPlugin> entry : pluginService.getRegistrationPlugins().entrySet()) {
String pluginId = String.valueOf(entry.getKey());
String html = entry.getValue().getHtml(request, pluginId, locale);
if (html != null) {
registrationPlugins.put(pluginId, html);
}
}
return registrationPlugins;
}
@RequestMapping(value = "/user/new_ajax", method = RequestMethod.GET)
@ResponseBody
public JsonResponse registrationForm(HttpServletRequest request, Locale locale) {
Map<String, String> registrationPlugins = getRegistrationPluginsHtml(request, locale);
return new JsonResponse(JsonResponseStatus.SUCCESS, registrationPlugins);
}
@RequestMapping(value = "/plugin/{pluginId}/{action}")
public void pluginAction(@PathVariable String pluginId, @PathVariable String action,
HttpServletRequest request, HttpServletResponse response) {
try {
Plugin plugin = pluginService.getPluginById(pluginId, new TypeFilter(ExtendedPlugin.class));
((ExtendedPlugin) plugin).doAction(pluginId, action, request, response);
} catch (org.jtalks.common.service.exceptions.NotFoundException ex) {
LOGGER.error("Can't perform action {}: plugin with id {} not found", action, pluginId);
}
}
/**
* Activates user account with UUID-based URL
* We use UUID's to be sure activation link cannot be generated from username
* by script or any other tool.
*
* @param uuid unique entity identifier
* @param request Servlet request.
* @param response Servlet response.
* @return redirect to the login page
* @throws org.jtalks.jcommune.plugin.api.exceptions.UnexpectedErrorException
* @throws org.jtalks.jcommune.plugin.api.exceptions.NoConnectionException
*/
@RequestMapping(value = "user/activate/{uuid}")
public String activateAccount(@PathVariable String uuid, HttpServletRequest request, HttpServletResponse response)
throws Exception {
try {
JCUser user = userService.getByUuid(uuid);
authenticator.activateAccount(user.getUuid());
MutableHttpRequest wrappedRequest = new MutableHttpRequest(request);
wrappedRequest.addParameter(AbstractRememberMeServices.DEFAULT_PARAMETER, "true");
LoginUserDto loginUserDto = new LoginUserDto(user.getUsername(), user.getPassword(), true, getClientIpAddress(request));
retryTemplate.execute(new LoginRetryCallback(loginUserDto, request, response, plainPasswordUserService));
return "redirect:/";
} catch (NotFoundException e) {
return "errors/activationExpired";
} catch (UserTriesActivatingAccountAgainException e) {
return "redirect:/";
}
}
/**
* Shows login page. Also checks if user is already logged in.
* If so he is redirected to referer page.
*
* @param request Current servlet request
* @return login view name or redirect to main page
*/
@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView loginPage(HttpServletRequest request, HttpServletResponse response) {
JCUser currentUser = userService.getCurrentUser();
String referer = getReferer(request, response);
if (currentUser.isAnonymous()) {
ModelAndView mav = new ModelAndView(LOGIN);
mav.addObject(REFERER_ATTR, referer);
LoginUserDto loginUserDto = new LoginUserDto();
mav.addObject(LOGIN_DTO, loginUserDto);
return mav;
} else {
return new ModelAndView("redirect:" + referer);
}
}
/**
* Gets request referrer - a page user was directed from e.g. when user followed a link or there was a redirect. In
* most cases when user browses our forum we put the referer on our own - the page user previously was at. This is
* done so that we can sign in and sign out user and redirect him back to original page.
*/
private String getReferer(HttpServletRequest request, HttpServletResponse response) {
String referer = request.getHeader("referer");
SavedRequest savedRequest = requestCache.getRequest(request, response);
HttpSession session = request.getSession(false);
if (session != null) {
if (savedRequest != null) {
referer = savedRequest.getRedirectUrl();
} else {
String customReferer =
String.valueOf(session.getAttribute(RefererKeepInterceptor.CUSTOM_REFERER));
/** We need check this !NULL_REPRESENTATION.equals(referer) strange condition
* because after CookieTheftException customReferer equals "null" (not null)
*/
if (customReferer != null && !NULL_REPRESENTATION.equals(customReferer)) {
referer = customReferer;
}
}
}
return referer;
}
/*
* This method can't get LoginUserDto object as parameter because in this case imposible
* to provide setting request parameter "_spring_security_remember_me".
* This parameter should be setted for remember-me functional implementation.
*/
@RequestMapping(value = "/login_ajax", method = RequestMethod.POST)
@ResponseBody
public JsonResponse loginAjax(@RequestParam("userName") String username,
@RequestParam("password") String password,
@RequestParam(value = "_spring_security_remember_me", defaultValue = "off")
String rememberMe,
HttpServletRequest request, HttpServletResponse response) throws Exception {
LoginUserDto loginUserDto = new LoginUserDto(username, password, rememberMe.equals(REMEMBER_ME_ON),
getClientIpAddress(request));
AuthenticationStatus authenticationStatus;
try {
authenticationStatus = retryTemplate.execute(new LoginRetryCallback(loginUserDto, request, response,
userService));
} catch (NoConnectionException e) {
return getCustomErrorJsonResponse("connectionError");
} catch (UnexpectedErrorException e) {
return getCustomErrorJsonResponse("unexpectedError");
}
if (authenticationStatus.equals(AuthenticationStatus.AUTHENTICATED)) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
localeResolver.setLocale(request, response, userService.getCurrentUser().getLanguage().getLocale());
return new JsonResponse(JsonResponseStatus.SUCCESS);
} else if(authenticationStatus.equals(AuthenticationStatus.NOT_ENABLED)){
JCUser user;
try {
user = userService.getByUsername(username);
} catch (NotFoundException e) {
return getCustomErrorJsonResponse("unexpectedError");
}
return new JsonResponse(JsonResponseStatus.FAIL, user.getId());
} else {
return new JsonResponse(JsonResponseStatus.FAIL);
}
}
/**
* Handles login action.
* @param loginUserDto {@link RegisterUserDto} populated in form
* @param referer referer url
* @param request servlet request
* @param response servlet response
* @return "success" or "fail" response status
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ModelAndView login(@ModelAttribute(LOGIN_DTO) LoginUserDto loginUserDto,
@RequestParam(REFERER_ATTR) String referer,
@RequestParam(value = "_spring_security_remember_me", defaultValue = "off")
String rememberMe,
HttpServletRequest request, HttpServletResponse response) throws Exception {
boolean isAuthenticated;
loginUserDto.setRememberMe(rememberMe.equals(REMEMBER_ME_ON));
loginUserDto.setClientIp(getClientIpAddress(request));
if (referer == null || referer.contains(LOGIN)) {
referer = MAIN_PAGE_REFERER;
}
try {
isAuthenticated = retryTemplate.execute(new LoginRetryCallback(loginUserDto, request, response,
userService)).equals(AuthenticationStatus.AUTHENTICATED);
} catch (NoConnectionException e) {
return new ModelAndView(AUTH_SERVICE_FAIL_URL);
} catch (UnexpectedErrorException e) {
return new ModelAndView(AUTH_SERVICE_FAIL_URL);
}
if (isAuthenticated) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
localeResolver.setLocale(request, response, userService.getCurrentUser().getLanguage().getLocale());
return new ModelAndView("redirect:" + referer);
} else {
ModelAndView modelAndView = new ModelAndView(AUTH_FAIL_URL);
modelAndView.addObject(ATTR_USERNAME, loginUserDto.getUserName());
modelAndView.addObject(REFERER_ATTR, referer);
return modelAndView;
}
}
/**
* Get usernames by pattern
*
* @param pattern some part of username
* @return list of usernames as json
*/
@RequestMapping(value = "/usernames", method = RequestMethod.POST)
@ResponseBody
public JsonResponse usernameList(@RequestParam("pattern") String pattern) {
return new JsonResponse(JsonResponseStatus.SUCCESS, userService.getUsernames(pattern));
}
private String getClientIpAddress(HttpServletRequest request) {
String ipAddress = request.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
ipAddress = request.getRemoteAddr();
}
return ipAddress;
}
@RequestMapping(value = "/confirm", method=RequestMethod.GET)
@ResponseBody
public JsonResponse sendEmailConfirmation(@RequestParam("id") long id){
try {
JCUser recipient = userService.get(id);
mailService.sendAccountActivationMail(recipient);
} catch (Exception e) {
return new JsonResponse(JsonResponseStatus.FAIL);
}
return new JsonResponse(JsonResponseStatus.SUCCESS);
}
@ResponseBody
@RequestMapping(value = "/user/{userID}/groups", method=RequestMethod.GET)
public JsonResponse userGroups(@PathVariable("userID") long userID){
try {
long forumId = componentService.getComponentOfForum().getId();
List<Long> groupsIDs = userService.getUserGroupIDs(forumId, userID);
return new JsonResponse(JsonResponseStatus.SUCCESS, groupsIDs);
} catch (Exception e) {
return new JsonResponse(JsonResponseStatus.FAIL);
}
}
@ResponseBody
@RequestMapping(value = "/user/{userID}/groups/{groupID}", method=RequestMethod.POST)
public JsonResponse addUserToGroup(@PathVariable long userID, @PathVariable long groupID){
try {
long forumId = componentService.getComponentOfForum().getId();
userService.addUserToGroup(forumId, userID, groupID);
return new JsonResponse(JsonResponseStatus.SUCCESS);
} catch (Exception e) {
return new JsonResponse(JsonResponseStatus.FAIL);
}
}
@ResponseBody
@RequestMapping(value = "/user/{userID}/groups/{groupID}", method=RequestMethod.DELETE)
public JsonResponse deleteUserFromGroup(@PathVariable long userID, @PathVariable long groupID){
try {
long forumId = componentService.getComponentOfForum().getId();
userService.deleteUserFromGroup(forumId, userID, groupID);
return new JsonResponse(JsonResponseStatus.SUCCESS);
} catch (Exception e) {
return new JsonResponse(JsonResponseStatus.FAIL);
}
}
@RequestMapping(value = "/users/list", method = RequestMethod.GET)
public ModelAndView searchUsers(@RequestParam(required = false) String searchKey) {
ModelAndView mav = new ModelAndView(USER_SEARCH);
long forumId = componentService.getComponentOfForum().getId();
if (StringUtils.isBlank(searchKey)) {
componentService.checkPermissionsForComponent(forumId);
} else {
List<JCUser> users = userService.findByUsernameOrEmail(forumId, searchKey.trim());
mav.addObject(USERS_ATTR_NAME, users);
List<Group> groups = groupService.getAll();
mav.addObject(GROUPS_ATTR_NAME, groups);
}
return mav;
}
private class LoginRetryCallback implements RetryCallback<AuthenticationStatus, Exception> {
private LoginUserDto loginUserDto;
private HttpServletRequest request;
private HttpServletResponse response;
private UserService userService;
private LoginRetryCallback(LoginUserDto loginUserDto, HttpServletRequest request,
HttpServletResponse response, UserService userService) {
this.loginUserDto = loginUserDto;
this.request = request;
this.response = response;
this.userService = userService;
}
@Override
public AuthenticationStatus doWithRetry(RetryContext context) throws UnexpectedErrorException, NoConnectionException {
return userService.loginUser(loginUserDto, request, response);
}
}
}