Java tutorial
/** * The MIT License * Copyright (c) 2015 Population Register Centre * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package fi.vm.kapa.identification.proxy.utils; import fi.vm.kapa.identification.dto.SessionDTO; import fi.vm.kapa.identification.type.AuthMethod; import fi.vm.kapa.identification.type.SessionProfile; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.inject.Singleton; import java.io.File; import java.io.FileReader; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @Service @Singleton public class SessionHandlingUtils { private static final Logger logger = LoggerFactory.getLogger(SessionHandlingUtils.class); private static final String COMMON_DELIM = "::"; private static final String CONCATENATE_KEY = "CONCAT"; private static final String PICK_FIRST_KEY = "FIRST"; private static final String PICK_FIRST_DELIM = " "; private Map<String, String> attributeMap = new HashMap<>(); private Map<String, String> legacyAttributeMap = new HashMap<>(); private ConcurrentMap<String, Map<AuthMethod, SessionDTO>> sessionsCache = new ConcurrentHashMap<>(); @Value("${attribute.map.file}") private String attributeMapFile; @Value("${legacy.attribute.map.file}") private String legacyAttributeMapFile; @Value("${authentication.provider.key}") private String authenticationProviderKey; @Value("${authentication.default.provider.key}") private String authenticationDefaultProviderKey; @Value("${saml.auth.provider.key}") private String samlAuthProviderKey; @Value("${legacy.version.key}") private String legacyVersionKey; @Value("${legacy.version.value}") private String legacyVersionValue; @PostConstruct public void initSessionHandlingService() throws Exception { try { CSVParser csvParser = new CSVParser(new FileReader(new File(attributeMapFile)), CSVFormat.DEFAULT.withDelimiter(';').withCommentMarker('#')); CSVParser csvLegacyParser = new CSVParser(new FileReader(new File(legacyAttributeMapFile)), CSVFormat.DEFAULT.withDelimiter(';').withCommentMarker('#')); /* The attribute mapper files have the following syntax: * [SP-attribute-key];[External-attribute-mapper-key] */ csvParser.forEach(record -> attributeMap.put(record.get(0), record.get(1))); csvLegacyParser.forEach(record -> legacyAttributeMap.put(record.get(0), record.get(1))); } catch (Exception e) { logger.error("Error initializing CSV parser", e); } } public void parseSessionData(SessionDTO session, Map<String, String> spSessionData, String authContextStr, String authProvider) { if (session.getSessionProfile() == SessionProfile.TUNNISTUSFI_LEGACY) { session.addSessionData(samlAuthProviderKey, authContextStr); } else if (session.getSessionProfile() == SessionProfile.VETUMA_SAML2) { session.addSessionData(samlAuthProviderKey, authProvider); } // Only those values what the SP has sent and what the IdP handles will be added to session spSessionData.keySet().forEach(spKey -> { if (attributeMap.containsKey(spKey) && StringUtils.isNotBlank(spSessionData.get(spKey))) { session.addSessionData(attributeMap.get(spKey), spSessionData.get(spKey)); } }); } public void parseLegacyData(SessionDTO session, Map<String, String> spSessionData) { switch (session.getSessionProfile()) { case TUNNISTUSFI_LEGACY: spSessionData.keySet().forEach(spKey -> { if (legacyAttributeMap.containsKey(spKey) && StringUtils.isNotBlank(spSessionData.get(spKey))) { session.addSessionData(legacyAttributeMap.get(spKey), spSessionData.get(spKey)); } }); // This must be checked always since legacy services require this if (!session.getSessionData().containsKey(legacyVersionKey)) { session.addSessionData(legacyVersionKey, legacyVersionValue); } break; case VETUMA_LEGACY: break; } } public void addAdditionalXRoadData(SessionDTO session, Map<String, String> xroadData) { xroadData.keySet().forEach(xrKey -> { if (attributeMap.containsKey(xrKey) && StringUtils.isNotBlank(xroadData.get(xrKey))) { session.addSessionData(attributeMap.get(xrKey), xroadData.get(xrKey)); } }); } public void parseCustomHandledData(SessionDTO session) { Map<String, String> sessionData = session.getSessionData(); if (attributeMap.containsKey(CONCATENATE_KEY)) { String[] concatenate = attributeMap.get(CONCATENATE_KEY).split(COMMON_DELIM); /* The first value must specify the value to which the next * values are concatenated in the order they are listed in */ String concatKey = concatenate[0]; StringBuilder sb = new StringBuilder(); for (int i = 1; i < concatenate.length; i++) { if (sessionData.containsKey(concatenate[i])) { sb.append(sessionData.get(concatenate[i])); sb.append(" "); } } session.addSessionData(concatKey, sb.toString().trim()); } if (attributeMap.containsKey(PICK_FIRST_KEY)) { String[] pickFirst = attributeMap.get(PICK_FIRST_KEY).split(COMMON_DELIM); /* The first value must specify the value to which the next * value is parsed into, this only picks, as the name suggests, * the first value with the given delimiter from the session data */ if (sessionData.containsKey(pickFirst[1])) { session.addSessionData(pickFirst[0], sessionData.get(pickFirst[1]).split(PICK_FIRST_DELIM)[0].trim()); } } } public SessionDTO getSessionByKeyAndAuthMethod(String key, AuthMethod authMethod) { return sessionsCache.getOrDefault(key, Collections.emptyMap()).get(authMethod); } /* This is used during the authentication process session finalising phase. */ public Map<AuthMethod, SessionDTO> getSessionDTOMapByKey(String key) { return sessionsCache.get(key); } public void insertIntoSessionCache(String key, AuthMethod authMethod, SessionDTO session) { Map<AuthMethod, SessionDTO> authMethodSessionDTOMap = sessionsCache.getOrDefault(key, Collections.emptyMap()); if (!authMethodSessionDTOMap.isEmpty()) { //Existing session with same authMethod is overwritten authMethodSessionDTOMap.put(authMethod, session); } else { ConcurrentMap<AuthMethod, SessionDTO> newSessionDTOMap = new ConcurrentHashMap<>(); newSessionDTOMap.put(authMethod, session); authMethodSessionDTOMap = sessionsCache.putIfAbsent(key, newSessionDTOMap); //Check and update existing entry if (authMethodSessionDTOMap != null) { authMethodSessionDTOMap.put(authMethod, session); } } } /* Called when uid is set as the final key or session data is updated */ public void replaceSessionCacheKey(String oldKey, String newKey, AuthMethod authMethod, SessionDTO session) { sessionsCache.remove(oldKey); insertIntoSessionCache(newKey, authMethod, session); } /* Invalidates the session, sets invalidated attribute for all auth methods in session */ public void invalidateCachedSessionsByKey(String key) { sessionsCache.getOrDefault(key, Collections.emptyMap()) .forEach((authMethod, sessionDTO) -> sessionDTO.setVtjDataInvalid(true)); } /* Checks that no session is invalid */ public boolean invalidSessionsInCacheByKey(String key) { boolean invalidSessions = false; Map<AuthMethod, SessionDTO> authMethodSessionDTOMap = sessionsCache.getOrDefault(key, Collections.emptyMap()); if (!authMethodSessionDTOMap.isEmpty()) { for (Map.Entry<AuthMethod, SessionDTO> sessionDTOEntry : authMethodSessionDTOMap.entrySet()) { if (sessionDTOEntry.getValue().isVtjDataInvalid()) { invalidSessions = true; } } } return invalidSessions; } public SessionDTO removeFromSessionCache(String key, AuthMethod authMethod) { Map<AuthMethod, SessionDTO> authMethodSessionDTOMap = sessionsCache.getOrDefault(key, Collections.emptyMap()); SessionDTO removedSession = null; if (!authMethodSessionDTOMap.isEmpty()) { removedSession = authMethodSessionDTOMap.remove(authMethod); if (authMethodSessionDTOMap.isEmpty()) { sessionsCache.remove(key); } } return removedSession != null ? removedSession : new SessionDTO(); } public Map<String, Map<AuthMethod, SessionDTO>> getSessionsCache() { return sessionsCache; } public int getSessionsCacheSize() { return sessionsCache.size(); } public boolean cacheContainsKey(String key) { return sessionsCache.containsKey(key); } public boolean authMethodsInPermittedMethods(String authMethods, String permittedMethods) { Set<String> requestedMethodSet = new HashSet<String>(Arrays.asList(authMethods.split(";"))); Set<String> permittedMethodSet = new HashSet<String>(Arrays.asList(permittedMethods.split(";"))); if (permittedMethodSet.containsAll(requestedMethodSet)) { return true; } return false; } public boolean authMethodInPermittedMethods(String authMethod, String permittedAuthMethods) { Set<String> permittedMethodSet = new HashSet<String>(Arrays.asList(permittedAuthMethods.split(";"))); if (permittedMethodSet.contains(authMethod)) { return true; } return false; } public void debugLogSessionStatus() { logger.debug("----------Sessions status----------"); logger.debug("-----------------------------------"); sessionsCache.forEach((key, sessionDTOMap) -> { logger.debug("***KEY: " + key.toString()); sessionDTOMap.forEach((authMethod, sessionDTO) -> { logger.debug("******AUTHMETHOD: " + authMethod.toString()); logger.debug("------CKEY: " + sessionDTO.getConversationKey()); logger.debug("------REQUESTED METHODS: " + sessionDTO.getRequestedAuthenticationMethods()); logger.debug("------SESSIONID: " + sessionDTO.getSessionId()); logger.debug("------RELYING PARTY: " + sessionDTO.getRelyingPartyEntityId()); sessionDTO.getSessionData().forEach((attrKey, attrValue) -> { logger.debug("------------SESSIONATTR: " + attrKey + " VALUE: " + attrValue); }); logger.debug("------SESSIONPROFILE: " + sessionDTO.getSessionProfile().toString()); logger.debug("------TIMESTAMP: " + sessionDTO.getTimestamp()); logger.debug("------VALIDATED: " + sessionDTO.isValidated()); }); }); } public String usedAuthMethod(AuthMethod authMethod) { return authMethod.name(); } }