/******************************************************************************* * Copyright 2014 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. *******************************************************************************/ package at.gv.egovernment.moa.id.moduls; import java.util.Date; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.data.AuthenticationSessionExtensions; import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; import at.gv.egovernment.moa.id.commons.api.IRequest; import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException; import at.gv.egovernment.moa.id.commons.api.exceptions.SessionDataStorageException; import at.gv.egovernment.moa.id.commons.db.dao.session.AuthenticatedSessionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.OldSSOSessionIDStore; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.storage.IAuthenticationSessionStoreage; import at.gv.egovernment.moa.id.util.Random; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; @Service("MOAID_SSOManager") public class SSOManager { private static final String HTMLTEMPLATESDIR = "htmlTemplates/"; private static final String HTMLTEMPLATEFULL = "slo_template.html"; public static String CONTEXTPATH = "contextPath"; private static final String SSOCOOKIE = "MOA_ID_SSO"; private static final String SSOINTERFEDERATION = "MOA_INTERFEDERATION_SSO"; private static final int INTERFEDERATIONCOOKIEMAXAGE = 5 * 60;// sec @Autowired private IAuthenticationSessionStoreage authenticatedSessionStore; @Autowired protected AuthConfiguration authConfig; //@Autowired private MOASessionDBUtils moaSessionDBUtils; /** * Check if interfederation IDP is requested via HTTP GET parameter or if interfederation cookie exists. * Set the requested interfederation IDP as attribte of the {protocolRequest} * * @param httpReq HttpServletRequest * @param httpResp HttpServletResponse * @param protocolRequest Authentication request which is actually in process * @throws SessionDataStorageException * **/ public void checkInterfederationIsRequested(HttpServletRequest httpReq, HttpServletResponse httpResp, IRequest protocolRequest) throws SessionDataStorageException { String interIDP = httpReq.getParameter(MOAIDAuthConstants.INTERFEDERATION_IDP); String interfederationIDP = protocolRequest.getGenericData(RequestImpl.DATAID_INTERFEDERATIOIDP_URL, String.class); if (MiscUtil.isNotEmpty(interfederationIDP)) { Logger.debug("Protocolspecific preprocessing already set interfederation IDP " + interfederationIDP); return; } if (protocolRequest instanceof RequestImpl) { //check if IDP is requested RequestImpl moaReq = (RequestImpl) protocolRequest; if (MiscUtil.isNotEmpty(interIDP)) { Logger.info("Receive SSO request for interfederation IDP " + interIDP); moaReq.setGenericDataToSession(RequestImpl.DATAID_INTERFEDERATIOIDP_URL, interIDP); } else { //check if IDP cookie is set String cookie = getValueFromCookie(httpReq, SSOINTERFEDERATION); if (MiscUtil.isNotEmpty(cookie)) { Logger.info("Receive SSO request for interfederated IDP from Cookie " + cookie); moaReq.setGenericDataToSession(RequestImpl.DATAID_INTERFEDERATIOIDP_URL, cookie); deleteCookie(httpReq, httpResp, SSOINTERFEDERATION); } } } else { Logger.warn("Request is not of type RequestImpl"); } } public void setInterfederationIDPCookie(HttpServletRequest httpReq, HttpServletResponse httpResp, String value) { setCookie(httpReq, httpResp, SSOINTERFEDERATION, value, INTERFEDERATIONCOOKIEMAXAGE); } public boolean isValidSSOSession(String ssoSessionID, IRequest protocolRequest) throws ConfigurationException, SessionDataStorageException { // search SSO Session if (ssoSessionID == null) { Logger.info("No SSO Session cookie found."); return false; } AuthenticatedSessionStore storedSession = authenticatedSessionStore.isValidSessionWithSSOID(ssoSessionID); if (storedSession == null) return false; else { //check if session is out of lifetime Date now = new Date(); long maxSSOSessionTime = authConfig.getSSOCreatedTimeOut() * 1000; Date ssoSessionValidTo = new Date(storedSession.getCreated().getTime() + maxSSOSessionTime); if (now.after(ssoSessionValidTo)) { Logger.info("Found outdated SSO session information. Start reauthentication process ... "); return false; } //check if stored SSO session is a federated SSO session if (protocolRequest != null && storedSession.isInterfederatedSSOSession()) { //in case of federated SSO session, jump to federated IDP for authentication String interfederationIDP = protocolRequest.getGenericData(RequestImpl.DATAID_INTERFEDERATIOIDP_URL, String.class); if (MiscUtil.isEmpty(interfederationIDP)) { InterfederationSessionStore selectedIDP = authenticatedSessionStore.searchInterfederatedIDPFORSSOWithMOASession(storedSession.getSessionid()); if (selectedIDP != null) { //no local SSO session exist -> request interfederated IDP Logger.info("SSO Session refer to federated IDP: " + selectedIDP.getIdpurlprefix()); protocolRequest.setGenericDataToSession( RequestImpl.DATAID_INTERFEDERATIOIDP_URL, selectedIDP.getIdpurlprefix()); } else { Logger.warn("MOASession is marked as interfederated SSO session but no interfederated IDP is found. Switch to local authentication ..."); try { authenticatedSessionStore.destroyInternalSSOSession(storedSession.getSessionid()); } catch (MOADatabaseException e) { Logger.error("Delete MOASession with ID:" + storedSession.getSessionid() + " FAILED!" , e); } } } return false; } return true; } } public AuthenticationSession getInternalMOASession(String ssoSessionID) throws MOADatabaseException { return authenticatedSessionStore.getInternalMOASessionWithSSOID(ssoSessionID); } //TODO: refactor for faster DB access public String getUniqueSessionIdentifier(String ssoSessionID) { try { if (MiscUtil.isNotEmpty(ssoSessionID)) { AuthenticationSession moaSession = authenticatedSessionStore.getInternalMOASessionWithSSOID(ssoSessionID); if (moaSession != null) { AuthenticationSessionExtensions extSessionInformation = authenticatedSessionStore.getAuthenticationSessionExtensions(moaSession.getSessionID()); return extSessionInformation.getUniqueSessionId(); } } } catch (MOADatabaseException e) { Logger.debug("No SSO Session with SSO sessionID: " + ssoSessionID); } return null; } public String existsOldSSOSession(String ssoId) { Logger.trace("Check that the SSOID has already been used"); OldSSOSessionIDStore oldSSOSession = authenticatedSessionStore.checkSSOTokenAlreadyUsed(ssoId); if (oldSSOSession == null) { Logger.debug("SSO session-cookie was not used in parst"); return null; } AuthenticatedSessionStore correspondingMoaSession = oldSSOSession.getMoasession(); if (correspondingMoaSession == null) { Logger.info("Get request with old SSO SessionID but no corresponding SSO Session is found."); return null; } return correspondingMoaSession.getSessionid(); } public String createSSOSessionInformations(String moaSessionID, String OAUrl) { String newSSOId = Random.nextRandom(); if (MiscUtil.isEmpty(moaSessionID) || MiscUtil.isEmpty(OAUrl)) { Logger.warn("MoaSessionID or OAUrl are empty -> SSO is not enabled!"); return null; } return newSSOId; } public void setSSOSessionID(HttpServletRequest httpReq, HttpServletResponse httpResp, String ssoId) { setCookie(httpReq, httpResp, SSOCOOKIE, ssoId, -1); } public String getSSOSessionID(HttpServletRequest httpReq) { return getValueFromCookie(httpReq, SSOCOOKIE); } public void deleteSSOSessionID(HttpServletRequest httpReq, HttpServletResponse httpResp) { deleteCookie(httpReq, httpResp, SSOCOOKIE); } /** * @param entityID * @param request */ public boolean removeInterfederatedSSOIDP(String entityID, HttpServletRequest request) { String ssoSessionID = getSSOSessionID(request); if (MiscUtil.isNotEmpty(ssoSessionID)) { AuthenticatedSessionStore storedSession = authenticatedSessionStore.isValidSessionWithSSOID(ssoSessionID); if (storedSession == null) return false; InterfederationSessionStore selectedIDP = authenticatedSessionStore.searchInterfederatedIDPFORSSOWithMOASessionIDPID(storedSession.getSessionid(), entityID); if (selectedIDP != null) { //no local SSO session exist -> request interfederated IDP Logger.info("Delete interfederated IDP " + selectedIDP.getIdpurlprefix() + " from MOASession " + storedSession.getSessionid()); authenticatedSessionStore.deleteIdpInformation(selectedIDP); } else { Logger.warn("MOASession is marked as interfederated SSO session but no interfederated IDP is found. Switch to local authentication ..."); } return true; } else return false; } private String getValueFromCookie(HttpServletRequest httpReq, String cookieName) { Cookie[] cookies = httpReq.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals(cookieName)) { return cookie.getValue(); } } } return null; } private void setCookie(HttpServletRequest httpReq, HttpServletResponse httpResp, String cookieName, String cookieValue, int maxAge) { Cookie cookie = new Cookie(cookieName, cookieValue); cookie.setMaxAge(maxAge); cookie.setSecure(true); cookie.setHttpOnly(true); cookie.setPath(httpReq.getContextPath()); httpResp.addCookie(cookie); } private void deleteCookie(HttpServletRequest httpReq, HttpServletResponse httpResp, String cookieName) { setCookie(httpReq, httpResp, cookieName, "", 0); } }