/* * JBoss, Home of Professional Open Source * Copyright 2013, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This 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 software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.richfaces.photoalbum.manager; /** * Class encapsulated all functionality, related to working with authenticating/registering users. * * @author Andrey Markhel */ import java.io.File; import java.io.Serializable; import java.text.SimpleDateFormat; import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.inject.Inject; import javax.inject.Named; import org.richfaces.json.JSONObject; import org.richfaces.photoalbum.model.Sex; import org.richfaces.photoalbum.model.User; import org.richfaces.photoalbum.model.actions.IUserAction; import org.richfaces.photoalbum.model.event.ErrorEvent; import org.richfaces.photoalbum.model.event.EventType; import org.richfaces.photoalbum.model.event.EventTypeQualifier; import org.richfaces.photoalbum.model.event.Events; import org.richfaces.photoalbum.model.event.NavEvent; import org.richfaces.photoalbum.model.event.SimpleEvent; import org.richfaces.photoalbum.social.facebook.FacebookBean; import org.richfaces.photoalbum.social.gplus.GooglePlusBean; import org.richfaces.photoalbum.ui.UserPrefsHelper; import org.richfaces.photoalbum.util.ApplicationUtils; import org.richfaces.photoalbum.util.Constants; import org.richfaces.photoalbum.util.Environment; import org.richfaces.photoalbum.util.HashUtils; @Named @ApplicationScoped public class Authenticator implements Serializable { private static final long serialVersionUID = -4585673256547342140L; @Inject LoggedUserTracker userTracker; @Inject IUserAction userAction; private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } private boolean loginFailed = false; private boolean conversationStarted = false; @Inject @Any Event<SimpleEvent> event; @Inject @EventType(Events.ADD_ERROR_EVENT) Event<ErrorEvent> error; @Inject @EventType(Events.UPDATE_MAIN_AREA_EVENT) Event<NavEvent> navEvent; @Inject FileManager fileManager; @Inject UserBean userBean; @Inject FacebookBean fBean; @Inject GooglePlusBean gBean; @Inject UserPrefsHelper uph; private File avatarData; /** * Method, that invoked when user try to login to the application. * * @return boolean indicator, that denotative is user succesfully loginned to the system. * */ public boolean authenticate() { try { // If user with this login and password exist, the user object will be returned user = userBean.logIn(userBean.getUsername(), HashUtils.hash(userBean.getPassword())); if (user != null) { // This check is actual only on livedemo server to prevent hacks. // Check if pre-defined user login. if (Environment.isInProduction() && user.isPreDefined()) { // If true assume that login failed loginFailed(); user = new User(); return false; } addToTracker(user.getId()); // Raise event to controller to update Model event.select(new EventTypeQualifier(Events.AUTHENTICATED_EVENT)).fire(new SimpleEvent()); // Login was successful setLoginFailed(false); return true; } } catch (Exception nre) { loginFailed(); error.fire(new ErrorEvent("Error:" + nre.getMessage())); return false; } return false; } private void addToTracker(Long userId) { // Remove previous session id from users store userTracker.removeUserId(userId); // Mark current user as actual userTracker.addUserId(userId, ApplicationUtils.getSession().getId()); } public boolean authenticateWithFacebook() { JSONObject userInfo = fBean.getUserInfo(); try { String pictureUrl = userInfo.getJSONObject("picture").getJSONObject("data").getString("url"); userBean.setFbPhotoUrl(pictureUrl); String facebookId = userInfo.getString("id"); if (!userBean.isLoggedIn()) { // user is not logged in user = userBean.facebookLogIn(facebookId); // try logging with Facebook if (user != null) { addToTracker(user.getId()); return true; } // Facebook id was not found, creating new account User newUser = new User(); newUser.setFbId(facebookId); newUser.setFirstName(userInfo.getString("first_name")); newUser.setSecondName(userInfo.getString("last_name")); newUser.setEmail(userInfo.getString("email")); String username = userInfo.has("username") ? userInfo.getString("username") : userInfo.getString("first_name"); newUser.setLogin(username); String sex = userInfo.getString("gender"); newUser.setSex(sex.equals("male") ? Sex.MALE : Sex.FEMALE); SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); newUser.setBirthDate(sdf.parse(userInfo.getString("birthday"))); // random password, the user will not be using this to log in newUser.setPasswordHash(HashUtils.hash("facebook" + System.currentTimeMillis())); userAction.register(newUser); userBean.facebookLogIn(facebookId); } else { userBean.facebookLogIn(facebookId); addToTracker(userBean.getUser().getId()); } return true; } catch (Exception nre) { loginFailed(); error.fire(new ErrorEvent("Error:" + nre.getMessage())); return false; } } public boolean authenticateWithGPlus() { JSONObject userInfo = gBean.getUserInfo(); try { // String pictureUrl = userInfo.getJSONObject("picture").getJSONObject("data").getString("url"); // userBean.setFbPhotoUrl(pictureUrl); String gPlusId = userInfo.getString("id"); if (!userBean.isLoggedIn()) { user = userBean.gPlusLogIn(gPlusId); if (user != null) { addToTracker(user.getId()); return true; } User newUser = new User(); newUser.setgPlusId(gPlusId); newUser.setFirstName(userInfo.getJSONObject("name").getString("givenName")); newUser.setSecondName(userInfo.getJSONObject("name").getString("familyName")); newUser.setEmail(userInfo.optString("email", "mail@mail.com")); String username = userInfo.optString("nickname", newUser.getFirstName()); newUser.setLogin(username); String sex = userInfo.getString("gender"); newUser.setSex(sex.equals("male") ? Sex.MALE : Sex.FEMALE); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String birthday = userInfo.optString("birthday", "1900-01-01"); newUser.setBirthDate(sdf.parse(birthday)); // random password, the user will not be using this to log in newUser.setPasswordHash(HashUtils.hash("gPlus" + System.currentTimeMillis())); userAction.register(newUser); userBean.gPlusLogIn(gPlusId); } else { userBean.gPlusLogIn(gPlusId); addToTracker(userBean.getUser().getId()); } return true; } catch (Exception nre) { loginFailed(); error.fire(new ErrorEvent("Error:" + nre.getMessage())); return false; } } /** * Method, that invoked when user logout from application. * * @return outcome string to redirect. * */ public void logout() { long id = userBean.getUser().getId(); userBean.logout(); this.user = null; // Remove user from users store userTracker.removeUserId(id); setConversationStarted(false); startConversation(); } /** * Method, that invoked when user try to register in the application. If registration was successfull, user immediately will * be loginned to the system. * * @param user - user object, that will be passed to registration procedure. * */ public void register(User user) { // Checks if (checkPassword(user) || checkUserExist(user) || checkEmailExist(user.getEmail())) { return; } user.setPasswordHash(HashUtils.hash(user.getPassword())); // This check is actual only on livedemo server to prevent hacks. // Only admins can mark user as pre-defined user.setPreDefined(false); if (!handleAvatar(user)) { return; } try { userAction.register(user); } catch (Exception e) { error.fire(new ErrorEvent(Constants.REGISTRATION_ERROR + ": " + e.getMessage())); return; } // Registration was successful, so we can login this user. try { this.user = userBean.logIn(user.getLogin(), HashUtils.hash(user.getPassword())); } catch (Exception e) { error.fire(new ErrorEvent(Constants.LOGIN_ERROR + "\n" + e.getMessage())); return; } if (this.user == null) { error.fire(new ErrorEvent(Constants.LOGIN_ERROR)); } navEvent.fire(new NavEvent(NavigationEnum.USER_PREFS)); UIComponent root = FacesContext.getCurrentInstance().getViewRoot(); UIComponent component = root.findComponent("overForm"); FacesContext.getCurrentInstance().addMessage(component.getClientId(FacesContext.getCurrentInstance()), new FacesMessage(FacesMessage.SEVERITY_INFO, "Success!", "Registration was successful.")); } /** * Method, that invoked when user want to edit her profile. * */ public void editUser(@Observes @EventType(Events.EDIT_USER_EVENT) SimpleEvent se) { avatarData = uph.getAvatarData(); // If new avatar was uploaded if (avatarData != null) { if (!fileManager.saveAvatar(avatarData, user)) { error.fire(new ErrorEvent(Constants.FILE_IO_ERROR)); return; } avatarData.delete(); avatarData = null; uph.setAvatarData(null); user.setHasAvatar(true); } try { // This check is actual only on livedemo server to prevent hacks. // Prevent hackers to mark user as pre-defined //user.setPreDefined(false); userAction.updateUser(user); } catch (Exception e) { error.fire(new ErrorEvent("Error", Constants.UPDATE_USER_ERROR + " <br/>" + e.getMessage())); return; } } /** * Method, that invoked when user want to go to the registration screen * */ public void goToRegister() { // create new User object user = new User(); setLoginFailed(false); // raise event to controller to prepare Model. event.select(new EventTypeQualifier(Events.START_REGISTER_EVENT)).fire(new SimpleEvent()); } /** * Method, that invoked when new conversation is started. This method prevent instantiation of couples of conversations when * user refresh the whole page. * */ @PostConstruct public void startConversation() { navEvent.fire(new NavEvent(NavigationEnum.ANONYM)); setConversationStarted(true); } private boolean handleAvatar(User user) { avatarData = uph.getAvatarData(); if (avatarData != null) { user.setHasAvatar(true); if (fileManager == null || !fileManager.saveAvatar(avatarData, user)) { error.fire(new ErrorEvent(Constants.AVATAR_SAVING_ERROR)); return false; } } return true; } private boolean checkUserExist(User user) { if (userAction.isUserExist(user.getLogin())) { ApplicationUtils.addFacesMessage(Constants.REGISTER_LOGIN_NAME_ID, Constants.USER_WITH_THIS_LOGIN_ALREADY_EXIST, ""); return true; } return false; } private boolean checkEmailExist(String email) { if (userAction.isEmailExist(email)) { ApplicationUtils.addFacesMessage(Constants.REGISTER_EMAIL_ID, Constants.USER_WITH_THIS_EMAIL_ALREADY_EXIST, ""); return true; } return false; } private boolean checkPassword(User user) { if (!user.getPassword().equals(user.getConfirmPassword())) { ApplicationUtils.addFacesMessage(Constants.REGISTER_CONFIRM_PASSWORD_ID, Constants.CONFIRM_PASSWORD_NOT_EQUALS_PASSWORD, ""); return true; } return false; } private void loginFailed() { setLoginFailed(true); ApplicationUtils.addFacesMessage("overForm:loginPanel", Constants.INVALID_LOGIN_OR_PASSWORD, ""); FacesContext.getCurrentInstance().renderResponse(); } public boolean isLoginFailed() { return loginFailed; } public void setLoginFailed(boolean loginFailed) { this.loginFailed = loginFailed; } public boolean isConversationStarted() { return conversationStarted; } public void setConversationStarted(boolean conversationStarted) { this.conversationStarted = conversationStarted; } }