/** * User utilities. * * @author <a href="mailto:[email protected]">Liang Ding</a> * @version 1.0.1.3, Feb 7, 2012 * @since 0.3.1 */ public final class Users { /** Logger. */ private static final Logger LOGGER = Logger.getLogger(Users.class.getName()); /** User repository. */ private UserRepository userRepository = UserRepositoryImpl.getInstance(); /** User service. */ private UserService userService = UserServiceFactory.getUserService(); /** Article repository. */ private ArticleRepository articleRepository = ArticleRepositoryImpl.getInstance(); /** * Determines whether if exists multiple users in current Solo. * * @return {@code true} if exists, {@code false} otherwise * @throws ServiceException service exception */ public boolean hasMultipleUsers() throws ServiceException { final Query query = new Query().setPageCount(1); try { final JSONArray users = userRepository.get(query).getJSONArray(Keys.RESULTS); return 1 != users.length(); } catch (final RepositoryException e) { LOGGER.log(Level.SEVERE, "Determines multiple users failed", e); throw new ServiceException(e); } catch (final JSONException e) { LOGGER.log(Level.SEVERE, "Determines multiple users failed", e); throw new ServiceException(e); } } /** * Can the current user access an article specified by the given article id? * * @param articleId the given article id * @param request the specified request * @return {@code true} if the current user can access the article, {@code false} otherwise * @throws Exception exception */ public boolean canAccessArticle(final String articleId, final HttpServletRequest request) throws Exception { if (Strings.isEmptyOrNull(articleId)) { return false; } if (isAdminLoggedIn(request)) { return true; } final JSONObject article = articleRepository.get(articleId); final String currentUserEmail = getCurrentUser(request).getString(User.USER_EMAIL); if (!article.getString(Article.ARTICLE_AUTHOR_EMAIL).equals(currentUserEmail)) { return false; } return true; } /** * Checks whether the current request is made by a logged in user (including default user and * administrator lists in <i>users</i>). * * <p>Invokes this method will try to login with cookie first. * * @param request the specified request * @param response the specified response * @return {@code true} if the current request is made by logged in user, returns {@code false} * otherwise */ public boolean isLoggedIn(final HttpServletRequest request, final HttpServletResponse response) { LoginProcessor.tryLogInWithCookie(request, response); final GeneralUser currentUser = userService.getCurrentUser(request); if (null == currentUser) { return false; } return isSoloUser(currentUser.getEmail()) || userService.isUserAdmin(request); } /** * Checks whether the current request is made by logged in administrator. * * @param request the specified request * @return {@code true} if the current request is made by logged in administrator, returns {@code * false} otherwise */ public boolean isAdminLoggedIn(final HttpServletRequest request) { return userService.isUserLoggedIn(request) && userService.isUserAdmin(request); } /** * Gets the current user. * * @param request the specified request * @return the current user, {@code null} if not found */ public JSONObject getCurrentUser(final HttpServletRequest request) { final GeneralUser currentUser = userService.getCurrentUser(request); if (null == currentUser) { return null; } final String email = currentUser.getEmail(); try { return userRepository.getByEmail(email); } catch (final RepositoryException e) { LOGGER.log(Level.SEVERE, "Gets current user by request failed, returns null", e); return null; } } /** * Determines whether the specified email is a user's email of this Solo application. * * @param email the specified email * @return {@code true} if it is, {@code false} otherwise */ public boolean isSoloUser(final String email) { try { final Query query = new Query().setPageCount(1); final JSONObject result = userRepository.get(query); final JSONArray users = result.getJSONArray(Keys.RESULTS); return existEmail(email, users); } catch (final Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); return false; } } /** * Determines whether the specified email exits in the specified users. * * @param email the specified email * @param users the specified user * @return {@code true} if exists, {@code false} otherwise * @throws JSONException json exception */ private boolean existEmail(final String email, final JSONArray users) throws JSONException { for (int i = 0; i < users.length(); i++) { final JSONObject user = users.getJSONObject(i); if (user.getString(User.USER_EMAIL).equalsIgnoreCase(email)) { return true; } } return false; } /** * Gets the {@link Users} singleton. * * @return the singleton */ public static Users getInstance() { return SingletonHolder.SINGLETON; } /** Private default constructor. */ private Users() {} /** * Singleton holder. * * @author <a href="mailto:[email protected]">Liang Ding</a> * @version 1.0.0.0, Jan 12, 2011 */ private static final class SingletonHolder { /** Singleton. */ private static final Users SINGLETON = new Users(); /** Private default constructor. */ private SingletonHolder() {} } }
/** * User query service. * * @author <a href="http://88250.b3log.org">Liang Ding</a> * @version 1.0.0.3, Jul 10, 2013 * @since 0.4.0 */ @Service public class UserQueryService { /** Logger. */ private static final Logger LOGGER = Logger.getLogger(UserQueryService.class.getName()); /** User service. */ private UserService userService = UserServiceFactory.getUserService(); /** User repository. */ @Inject private UserRepository userRepository; /** User management service. */ @Inject private UserMgmtService userMgmtService; /** * Determines whether if exists multiple users in current Solo. * * @return {@code true} if exists, {@code false} otherwise * @throws ServiceException service exception */ public boolean hasMultipleUsers() throws ServiceException { final Query query = new Query().setPageCount(1); try { final JSONArray users = userRepository.get(query).getJSONArray(Keys.RESULTS); return 1 != users.length(); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Determines multiple users failed", e); throw new ServiceException(e); } catch (final JSONException e) { LOGGER.log(Level.ERROR, "Determines multiple users failed", e); throw new ServiceException(e); } } /** * Checks whether the current request is made by a logged in user (including default user and * administrator lists in <i>users</i>). * * <p>Invokes this method will try to login with cookie first. * * @param request the specified request * @param response the specified response * @return {@code true} if the current request is made by logged in user, returns {@code false} * otherwise */ public boolean isLoggedIn(final HttpServletRequest request, final HttpServletResponse response) { userMgmtService.tryLogInWithCookie(request, response); final GeneralUser currentUser = userService.getCurrentUser(request); return null != currentUser; } /** * Checks whether the current request is made by logged in administrator. * * @param request the specified request * @return {@code true} if the current request is made by logged in administrator, returns {@code * false} otherwise */ public boolean isAdminLoggedIn(final HttpServletRequest request) { return userService.isUserLoggedIn(request) && userService.isUserAdmin(request); } /** * Gets the current user. * * @param request the specified request * @return the current user, {@code null} if not found */ public JSONObject getCurrentUser(final HttpServletRequest request) { final GeneralUser currentUser = userService.getCurrentUser(request); if (null == currentUser) { return null; } final String email = currentUser.getEmail(); try { return userRepository.getByEmail(email); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets current user by request failed, returns null", e); return null; } } /** * Gets the administrator. * * @return administrator, returns {@code null} if not found * @throws ServiceException service exception */ public JSONObject getAdmin() throws ServiceException { try { return userRepository.getAdmin(); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets admin failed", e); throw new ServiceException(e); } } /** * Gets a user by the specified email. * * @param email the specified email * @return user, returns {@code null} if not found * @throws ServiceException service exception */ public JSONObject getUserByEmail(final String email) throws ServiceException { try { return userRepository.getByEmail(email); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets user by email[" + email + "] failed", e); throw new ServiceException(e); } } /** * Gets users by the specified request json object. * * @param requestJSONObject the specified request json object, for example, * <pre> * { * "paginationCurrentPageNum": 1, * "paginationPageSize": 20, * "paginationWindowSize": 10, * }, see {@link Pagination} for more details * </pre> * * @return for example, * <pre> * { * "pagination": { * "paginationPageCount": 100, * "paginationPageNums": [1, 2, 3, 4, 5] * }, * "users": [{ * "oId": "", * "userName": "", * "userEmail": "", * "userPassword": "", * "roleName": "" * }, ....] * } * </pre> * * @throws ServiceException service exception * @see Pagination */ public JSONObject getUsers(final JSONObject requestJSONObject) throws ServiceException { final JSONObject ret = new JSONObject(); final int currentPageNum = requestJSONObject.optInt(Pagination.PAGINATION_CURRENT_PAGE_NUM); final int pageSize = requestJSONObject.optInt(Pagination.PAGINATION_PAGE_SIZE); final int windowSize = requestJSONObject.optInt(Pagination.PAGINATION_WINDOW_SIZE); final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize); JSONObject result = null; try { result = userRepository.get(query); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets users failed", e); throw new ServiceException(e); } final int pageCount = result.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_PAGE_COUNT); final JSONObject pagination = new JSONObject(); ret.put(Pagination.PAGINATION, pagination); final List<Integer> pageNums = Paginator.paginate(currentPageNum, pageSize, pageCount, windowSize); pagination.put(Pagination.PAGINATION_PAGE_COUNT, pageCount); pagination.put(Pagination.PAGINATION_PAGE_NUMS, pageNums); final JSONArray users = result.optJSONArray(Keys.RESULTS); ret.put(User.USERS, users); return ret; } /** * Gets a user by the specified user id. * * @param userId the specified user id * @return for example, * <pre> * { * "user": { * "oId": "", * "userName": "", * "userEmail": "", * "userPassword": "" * } * } * </pre> * , returns {@code null} if not found * @throws ServiceException service exception */ public JSONObject getUser(final String userId) throws ServiceException { final JSONObject ret = new JSONObject(); JSONObject user = null; try { user = userRepository.get(userId); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets a user failed", e); throw new ServiceException(e); } if (null == user) { return null; } ret.put(User.USER, user); return ret; } /** * Gets the URL of user logout. * * @return logout URL, returns {@code null} if the user is not logged in */ public String getLogoutURL() { return userService.createLogoutURL("/"); } /** * Gets the URL of user login. * * @param redirectURL redirect URL after logged in * @return login URL */ public String getLoginURL(final String redirectURL) { return userService.createLoginURL(redirectURL); } /** * Sets the user management service with the specified user management service. * * @param userMgmtService the specified user management service */ public void setUserMgmtService(final UserMgmtService userMgmtService) { this.userMgmtService = userMgmtService; } /** * Sets the user repository with the specified user repository. * * @param userRepository the specified user repository */ public void setUserRepository(final UserRepository userRepository) { this.userRepository = userRepository; } }
/** * Login/logout processor. * * <p> * * <p>Initializes administrator. * * @author <a href="http://88250.b3log.org">Liang Ding</a> * @author <a href="mailto:[email protected]">Liyuan Li</a> * @author <a href="mailto:[email protected]">Dongxu Wang</a> * @version 1.1.1.6, Oct 26, 2013 * @since 0.3.1 */ @RequestProcessor public class LoginProcessor { /** Logger. */ private static final Logger LOGGER = Logger.getLogger(LoginProcessor.class.getName()); /** User query service. */ @Inject private UserQueryService userQueryService; /** User service. */ private UserService userService = UserServiceFactory.getUserService(); /** Mail service. */ private MailService mailService = MailServiceFactory.getMailService(); /** User management service. */ @Inject private UserMgmtService userMgmtService; /** Language service. */ @Inject private LangPropsService langPropsService; /** Filler. */ @Inject private Filler filler; /** Preference query service. */ @Inject private PreferenceQueryService preferenceQueryService; /** Option query service. */ @Inject private OptionQueryService optionQueryService; /** Option management service. */ @Inject private OptionMgmtService optionMgmtService; /** Option repository. */ @Inject private OptionRepository optionRepository; /** * Shows login page. * * @param context the specified context * @throws Exception exception */ @RequestProcessing(value = "/login", method = HTTPRequestMethod.GET) public void showLogin(final HTTPRequestContext context) throws Exception { final HttpServletRequest request = context.getRequest(); String destinationURL = request.getParameter(Common.GOTO); if (Strings.isEmptyOrNull(destinationURL)) { destinationURL = Latkes.getServePath() + Common.ADMIN_INDEX_URI; } final HttpServletResponse response = context.getResponse(); userMgmtService.tryLogInWithCookie(request, response); if (null != userService.getCurrentUser(request)) { // User has already logged in response.sendRedirect(destinationURL); return; } renderPage(context, "login.ftl", destinationURL, request); } /** * Logins. * * <p>Renders the response with a json object, for example, * * <pre> * { * "isLoggedIn": boolean, * "msg": "" // optional, exists if isLoggedIn equals to false * } * </pre> * * @param context the specified context */ @RequestProcessing(value = "/login", method = HTTPRequestMethod.POST) public void login(final HTTPRequestContext context) { final HttpServletRequest request = context.getRequest(); final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject jsonObject = new JSONObject(); renderer.setJSONObject(jsonObject); try { jsonObject.put(Common.IS_LOGGED_IN, false); final String loginFailLabel = langPropsService.get("loginFailLabel"); jsonObject.put(Keys.MSG, loginFailLabel); final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse()); final String userEmail = requestJSONObject.getString(User.USER_EMAIL); final String userPwd = requestJSONObject.getString(User.USER_PASSWORD); if (Strings.isEmptyOrNull(userEmail) || Strings.isEmptyOrNull(userPwd)) { return; } LOGGER.log(Level.INFO, "Login[email={0}]", userEmail); final JSONObject user = userQueryService.getUserByEmail(userEmail); if (null == user) { LOGGER.log(Level.WARN, "Not found user[email={0}]", userEmail); return; } if (MD5.hash(userPwd).equals(user.getString(User.USER_PASSWORD))) { Sessions.login(request, context.getResponse(), user); LOGGER.log(Level.INFO, "Logged in[email={0}]", userEmail); jsonObject.put(Common.IS_LOGGED_IN, true); if (Role.VISITOR_ROLE.equals(user.optString(User.USER_ROLE))) { jsonObject.put("to", Latkes.getServePath()); } else { jsonObject.put("to", Latkes.getServePath() + Common.ADMIN_INDEX_URI); } jsonObject.remove(Keys.MSG); return; } LOGGER.log(Level.WARN, "Wrong password[{0}]", userPwd); } catch (final Exception e) { LOGGER.log(Level.ERROR, e.getMessage(), e); } } /** * Logout. * * @param context the specified context * @throws IOException io exception */ @RequestProcessing(value = "/logout", method = HTTPRequestMethod.GET) public void logout(final HTTPRequestContext context) throws IOException { final HttpServletRequest httpServletRequest = context.getRequest(); Sessions.logout(httpServletRequest, context.getResponse()); String destinationURL = httpServletRequest.getParameter(Common.GOTO); if (Strings.isEmptyOrNull(destinationURL)) { destinationURL = "/"; } context.getResponse().sendRedirect(destinationURL); } /** * Shows forgotten password page. * * @param context the specified context * @throws Exception exception */ @RequestProcessing(value = "/forgot", method = HTTPRequestMethod.GET) public void showForgot(final HTTPRequestContext context) throws Exception { final HttpServletRequest request = context.getRequest(); String destinationURL = request.getParameter(Common.GOTO); if (Strings.isEmptyOrNull(destinationURL)) { destinationURL = Latkes.getServePath() + Common.ADMIN_INDEX_URI; } renderPage(context, "reset-pwd.ftl", destinationURL, request); } /** * Resets forgotten password. * * <p>Renders the response with a json object, for example, * * <pre> * { * "isLoggedIn": boolean, * "msg": "" // optional, exists if isLoggedIn equals to false * } * </pre> * * @param context the specified context */ @RequestProcessing(value = "/forgot", method = HTTPRequestMethod.POST) public void forgot(final HTTPRequestContext context) { final HttpServletRequest request = context.getRequest(); final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject jsonObject = new JSONObject(); renderer.setJSONObject(jsonObject); try { jsonObject.put("succeed", false); jsonObject.put(Keys.MSG, langPropsService.get("resetPwdSuccessMsg")); final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse()); final String userEmail = requestJSONObject.getString(User.USER_EMAIL); if (Strings.isEmptyOrNull(userEmail)) { LOGGER.log(Level.WARN, "Why user's email is empty"); return; } LOGGER.log(Level.INFO, "Login[email={0}]", userEmail); final JSONObject user = userQueryService.getUserByEmail(userEmail); if (null == user) { LOGGER.log(Level.WARN, "Not found user[email={0}]", userEmail); jsonObject.put(Keys.MSG, langPropsService.get("userEmailNotFoundMsg")); return; } sendResetUrl(userEmail, jsonObject); } catch (final Exception e) { LOGGER.log(Level.ERROR, e.getMessage(), e); } } /** * Resets forgotten password. * * <p>Renders the response with a json object, for example, * * <pre> * { * "isLoggedIn": boolean, * "msg": "" // optional, exists if isLoggedIn equals to false * } * </pre> * * @param context the specified context */ @RequestProcessing(value = "/reset", method = HTTPRequestMethod.POST) public void reset(final HTTPRequestContext context) { final HttpServletRequest request = context.getRequest(); final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject jsonObject = new JSONObject(); renderer.setJSONObject(jsonObject); try { final JSONObject requestJSONObject; requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse()); final String userEmail = requestJSONObject.getString(User.USER_EMAIL); final String newPwd = requestJSONObject.getString("newPwd"); final JSONObject user = userQueryService.getUserByEmail(userEmail); user.put(User.USER_PASSWORD, newPwd); userMgmtService.updateUser(user); LOGGER.log(Level.DEBUG, "[{0}]'s password updated successfully.", new Object[] {userEmail}); jsonObject.put("succeed", true); jsonObject.put("to", Latkes.getServePath() + "/login?from=reset"); jsonObject.put(Keys.MSG, langPropsService.get("resetPwdSuccessMsg")); } catch (final Exception e) { LOGGER.log(Level.ERROR, e.getMessage(), e); } } /** * Whether user is going to update an expired password out of 24 hours. * * @return whether the password has been expired TODO implement it */ private boolean isPwdExpired() { return false; } /** * Sends the password resetting URL with a random token. * * @param userEmail the given email * @param jsonObject return code and message object * @throws JSONException the JSONException * @throws ServiceException the ServiceException * @throws IOException the IOException * @throws RepositoryException the RepositoryException */ private void sendResetUrl(final String userEmail, final JSONObject jsonObject) throws JSONException, ServiceException, IOException, RepositoryException { final JSONObject preference = preferenceQueryService.getPreference(); final String token = new Randoms().nextStringWithMD5(); final String adminEmail = preference.getString(Preference.ADMIN_EMAIL); final String mailSubject = langPropsService.get("resetPwdMailSubject"); final String mailBody = langPropsService.get("resetPwdMailBody") + " " + Latkes.getServePath() + "/forgot?token=" + token + "&login="******"passwordReset"); option.put(Option.OPTION_VALUE, System.currentTimeMillis()); final Transaction transaction = optionRepository.beginTransaction(); optionRepository.add(option); transaction.commit(); message.setFrom(adminEmail); message.addRecipient(userEmail); message.setSubject(mailSubject); message.setHtmlBody(mailBody); mailService.send(message); jsonObject.put("succeed", true); jsonObject.put("to", Latkes.getServePath() + "/login?from=forgot"); jsonObject.put(Keys.MSG, langPropsService.get("resetPwdSuccessSend")); LOGGER.log( Level.DEBUG, "Sent a mail[mailSubject={0}, mailBody=[{1}] to [{2}]", new Object[] {mailSubject, mailBody, userEmail}); } /** * Render a page template with the destination URL. * * @param context the context * @param pageTemplate the page template * @param destinationURL the destination URL * @param request for reset password page * @throws JSONException the JSONException * @throws ServiceException the ServiceException */ private void renderPage( final HTTPRequestContext context, final String pageTemplate, final String destinationURL, final HttpServletRequest request) throws JSONException, ServiceException { final AbstractFreeMarkerRenderer renderer = new ConsoleRenderer(); renderer.setTemplateName(pageTemplate); context.setRenderer(renderer); final Map<String, Object> dataModel = renderer.getDataModel(); final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale()); final JSONObject preference = preferenceQueryService.getPreference(); dataModel.putAll(langs); dataModel.put(Common.GOTO, destinationURL); dataModel.put(Common.YEAR, String.valueOf(Calendar.getInstance().get(Calendar.YEAR))); dataModel.put(Common.VERSION, SoloServletListener.VERSION); dataModel.put(Common.STATIC_RESOURCE_VERSION, Latkes.getStaticResourceVersion()); dataModel.put(Preference.BLOG_TITLE, preference.getString(Preference.BLOG_TITLE)); final String token = request.getParameter("token"); final String email = request.getParameter("login"); final JSONObject tokenObj = optionQueryService.getOptionById(token); if (tokenObj == null) { dataModel.put("inputType", "email"); } else { // TODO verify the expired time in the tokenObj dataModel.put("inputType", "password"); dataModel.put("userEmailHidden", email); } final String from = request.getParameter("from"); if ("forgot".equals(from)) { dataModel.put("resetMsg", langPropsService.get("resetPwdSuccessSend")); } else if ("reset".equals(from)) { dataModel.put("resetMsg", langPropsService.get("resetPwdSuccessMsg")); } else { dataModel.put("resetMsg", ""); } Keys.fillRuntime(dataModel); filler.fillMinified(dataModel); } }