/* * Copyright (c) 2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.identity.sso.saml.ui.session.mgt; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * This class is used to maintain a session map at the SSO FE. This class is introduced * to get rid of the session usage to hold the meta information of a incoming authentication * request. This class implements Singleton since there can be only one session manager. */ public enum FESessionManager { INSTANCE; private static SecureRandom secureRandomInstance; private static MessageDigest messageDigest; private static Log log = LogFactory.getLog(FESessionManager.class); public ConcurrentMap<String, FESessionBean> sessionMap; static { initialize(); } private FESessionManager() { this.sessionMap = new ConcurrentHashMap<String, FESessionBean>(); } /** * Initialize the FESessionManager class. Create the instances of SecureRandom and * MessageDigest and keep them as static references. */ private static void initialize() { try { secureRandomInstance = SecureRandom.getInstance("SHA1PRNG"); messageDigest = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) { log.error("Error when initializing the SAML2 SSO FESessionManager.", e); throw new RuntimeException(e); } } public static FESessionManager getInstance() { return INSTANCE; } /** * Get the corresponding FESessionBean for a particular session id * * @param sessionID session id * @return FESessionBean */ public FESessionBean getFESessionBean(String sessionID) { if (sessionMap.containsKey(sessionID)) { return sessionMap.get(sessionID); } return null; } /** * Add a new session bean object to the session map * * @param sessionBean * @return created session id */ public String addNewSession(FESessionBean sessionBean) { String sessionId = generateSessionId(); sessionMap.put(sessionId, sessionBean); return sessionId; } /** * Remove an existing session. * * @param sessionId session id */ public void removeSession(String sessionId) { if (sessionMap.containsKey(sessionId)) { sessionMap.remove(sessionId); } else { log.warn("The session bean with the ID : " + sessionId + "is not available in the session map"); } } /** * Generate a session id to store the FE session beans * * @return generated session id */ private String generateSessionId() { //generate the random number String randomNum = Integer.toString(secureRandomInstance.nextInt()); //get its digest byte[] result = messageDigest.digest(randomNum.getBytes(StandardCharsets.UTF_8)); return hexEncode(result); } /** * The byte[] returned by MessageDigest does not have a nice * textual representation, so some form of encoding is usually performed. * * @param digestValue digested bite array * @return Encoded string */ private String hexEncode(byte[] digestValue) { StringBuilder result = new StringBuilder(); char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; for (int idx = 0; idx < digestValue.length; ++idx) { byte b = digestValue[idx]; result.append(digits[(b & 0xf0) >> 4]); result.append(digits[b & 0x0f]); } return result.toString(); } }