package eu.musesproject.server.authentication; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.json.JSONException; import org.json.JSONObject; import eu.musesproject.client.model.JSONIdentifiers; import eu.musesproject.server.contextdatareceiver.JSONManager; import eu.musesproject.server.db.handler.DBManager; import eu.musesproject.server.entity.Users; import eu.musesproject.server.eventprocessor.util.Constants; import eu.musesproject.server.scheduler.ModuleType; /* * #%L * MUSES Server * %% * Copyright (C) 2013 - 2014 S2 Grupo * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ public class AuthenticationManager { private static AuthenticationManager authenticationManagerSingleton = null; public Logger logger = Logger.getLogger(AuthenticationManager.class.getName()); //private List<String> authSessionIdList = new ArrayList<String>(); // several threads will add and remove items from list. the list must be thread safe. // the best solution is to let tomcat handle the authentication entirely by having security constraints defined. Even if you want to do it manually then // you have to clean up all the sessions that have timed out in order to not get memory leaks. Beside that a set is more appropriate in this case instead // of a list. you do not want duplicates of the same session id stored several times. private Set<String> authSessionIdList = Collections.synchronizedSet(new HashSet<String>()); private static DBManager dbManager = new DBManager(ModuleType.EP); /** * Creare authentication manager singleton if not created * @return singleton object */ public static AuthenticationManager getInstance(){ // this is the old non thread-safe code. assume the singleton has not yet been assigned and then two threads at the same time check to see if the // singleton is null. both will create their own instance which will defeat the purpose of a singleton. the correct thread-safe version // is available below. // if (authenticationManagerSingleton == null) { // authenticationManagerSingleton = new AuthenticationManager(); // } // return authenticationManagerSingleton; if (authenticationManagerSingleton == null) { synchronized(AuthenticationManager.class) { if (authenticationManagerSingleton == null) { authenticationManagerSingleton = new AuthenticationManager(); } } } return authenticationManagerSingleton; } public JSONObject authenticate(JSONObject root, String sessionId){ String username = null; String password = null; String deviceId = null; JSONObject response = null; try { // retrieveCredentials username = root.getString(JSONIdentifiers.AUTH_USERNAME); password = root.getString(JSONIdentifiers.AUTH_PASSWORD); deviceId = root.getString(JSONIdentifiers.AUTH_DEVICE_ID); logger.log(Level.INFO,"Login attempt with credentials: " + username + "-" + password + "-" + deviceId); // Authentication // with // database Users user = dbManager.getUserByUsername(username); if ((user != null)&&(user.getPassword().equalsIgnoreCase(password)&&(user.getEnabled()==1))){ logger.log(Level.INFO, "Authentication successful"); authSessionIdList.add(sessionId); // Send authentication response with success message response = JSONManager.createJSON(JSONIdentifiers.AUTH_RESPONSE, Constants.SUCCESS, "Successfully authenticated"); logger.log(Level.INFO, response.toString()); } else if (user == null) { logger.log(Level.INFO, "Authentication failed: user not found"); // Send authentication response with failure message response = JSONManager.createJSON(JSONIdentifiers.AUTH_RESPONSE, Constants.FAIL, "User not found"); logger.log(Level.INFO, response.toString()); } else if (user.getEnabled()!=1) { logger.log(Level.INFO, "Authentication failed: user not enabled"); // Send authentication response with failure message response = JSONManager.createJSON(JSONIdentifiers.AUTH_RESPONSE, Constants.FAIL, "User not enabled"); logger.log(Level.INFO, response.toString()); }else { logger.log(Level.INFO, "Authentication failed"); // Send authentication response with failure message response = JSONManager.createJSON(JSONIdentifiers.AUTH_RESPONSE, Constants.FAIL, "Incorrect password"); logger.log(Level.INFO, response.toString()); } } catch (JSONException e) { e.printStackTrace(); } return response; } public JSONObject logout(JSONObject root, String sessionId){ String username = null; String deviceId = null; JSONObject response = null; try { // retrieveCredentials username = root.getString(JSONIdentifiers.AUTH_USERNAME); deviceId = root.getString(JSONIdentifiers.AUTH_DEVICE_ID); System.out.println("Logout attempt : " + username + "-" + deviceId); // Authentication if (isAuthenticated(sessionId)){ logger.log(Level.INFO, "Logout successful"); authSessionIdList.remove(sessionId); // Send authentication response with success message response = JSONManager.createJSON(JSONIdentifiers.LOGOUT_RESPONSE, Constants.SUCCESS, "Successfully logged out"); logger.log(Level.INFO, response.toString()); } else { logger.log(Level.INFO, "Logout failed"); // Send authentication response with failure message response = JSONManager.createJSON(JSONIdentifiers.LOGOUT_RESPONSE, Constants.FAIL, "No session found, you are already logged out."); logger.log(Level.INFO, response.toString()); } } catch (JSONException e) { e.printStackTrace(); } return response; } // public List<String> getAuthSessionIdList() { // return authSessionIdList; //} // we can not allow any external call replace the implementation. what if they replace it with a non thread-safe variant //public void setAuthSessionIdList(List<String> authSessionIdList) { // this.authSessionIdList = authSessionIdList; //} public boolean isAuthenticated(String sessionId) { return authSessionIdList.contains(sessionId); } }