/* * 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.auth.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringEscapeUtils; import org.opensaml.saml2.core.LogoutResponse; import org.opensaml.saml2.metadata.SingleLogoutService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.auth.IAuthenticationManager; import at.gv.egiz.eaaf.core.api.idp.slo.ISLOInformationContainer; import at.gv.egiz.eaaf.core.exceptions.EAAFException; import at.gv.egiz.eaaf.core.exceptions.GUIBuildException; import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; import at.gv.egiz.eaaf.core.impl.utils.HTTPUtils; import at.gv.egiz.eaaf.core.impl.utils.Random; import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; import at.gv.egiz.eaaf.modules.pvp2.idp.impl.PVPSProfilePendingRequest; import at.gv.egovernment.moa.id.auth.frontend.builder.DefaultGUIFormBuilderConfiguration; import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.commons.utils.MOAIDMessageProvider; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.id.data.SLOInformationContainer; import at.gv.egovernment.moa.id.moduls.SSOManager; import at.gv.egovernment.moa.id.protocols.pvp2x.builder.SingleLogOutBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NOSLOServiceDescriptorException; import at.gv.egovernment.moa.id.storage.IAuthenticationSessionStoreage; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moa.util.URLEncoder; /** * @author tlenz * */ @Controller public class IDPSingleLogOutServlet extends AbstractController { @Autowired SSOManager ssoManager; @Autowired IAuthenticationManager authManager; @Autowired IAuthenticationSessionStoreage authenicationStorage; @Autowired SingleLogOutBuilder sloBuilder; @RequestMapping(value = "/idpSingleLogout", method = {RequestMethod.GET}) public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Logger.debug("Receive IDP-initiated SingleLogOut"); String authURL = HTTPUtils.extractAuthURLFromRequest(req); try { if (!AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix().contains(authURL)) { Logger.warn("Requested URL " + authURL + " is not in PublicPrefix Configuration"); resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Request not allowed"); return; } } catch (MOAIDException e) { Logger.error("Internal Server Error.", e); resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error"); return; } String ssoid = ssoManager.getSSOSessionID(req); Object restartProcessObj = StringEscapeUtils.escapeHtml(req.getParameter(MOAIDAuthConstants.PARAM_SLORESTART)); Object tokkenObj = StringEscapeUtils.escapeHtml(req.getParameter(MOAIDAuthConstants.PARAM_SLOSTATUS)); String tokken = null; String status = null; if (tokkenObj != null && tokkenObj instanceof String) { tokken = (String) tokkenObj; try { status = transactionStorage.get(tokken, String.class); if (MiscUtil.isNotEmpty(status)) { transactionStorage.remove(tokken); } DefaultGUIFormBuilderConfiguration config = new DefaultGUIFormBuilderConfiguration( authURL, DefaultGUIFormBuilderConfiguration.VIEW_SINGLELOGOUT, null); if (MOAIDAuthConstants.SLOSTATUS_SUCCESS.equals(status)) config.putCustomParameter("successMsg", MOAIDMessageProvider.getInstance().getMessage("slo.00", null)); else config.putCustomParameterWithOutEscaption("errorMsg", MOAIDMessageProvider.getInstance().getMessage("slo.01", null)); guiBuilder.build(resp, config, "Single-LogOut GUI"); } catch (GUIBuildException e) { handleErrorNoRedirect(e, req, resp, false); } catch (MOADatabaseException e) { handleErrorNoRedirect(e, req, resp, false); } catch (EAAFException e) { handleErrorNoRedirect(e, req, resp, false); } return; } else if (MiscUtil.isNotEmpty(ssoid)) { try { if (ssoManager.isValidSSOSession(ssoid, null)) { String internalSSOId = authenicationStorage.getInternalSSOSessionWithSSOID(ssoid); if(MiscUtil.isNotEmpty(internalSSOId)) { ISLOInformationContainer sloInfoContainer = authManager.performSingleLogOut(req, resp, null, internalSSOId); Logger.debug("Starting technical SLO process ... "); sloBuilder.toTechnicalLogout(sloInfoContainer, req, resp, authURL); return; } } } catch (Exception e) { handleErrorNoRedirect(e, req, resp, false); } } else if (restartProcessObj != null && restartProcessObj instanceof String) { String restartProcess = (String) restartProcessObj; if (MiscUtil.isNotEmpty(restartProcess)) { Logger.info("Restart Single LogOut process after timeout ... "); try { SLOInformationContainer sloContainer = transactionStorage.get(restartProcess, SLOInformationContainer.class); if (sloContainer == null) { Logger.info("No Single LogOut processing information with ID: " + restartProcess); handleErrorNoRedirect(new MOAIDException("slo.03", null), req, resp, false); return; } if (sloContainer.hasFrontChannelOA()) sloContainer.putFailedOA("differntent OAs"); String redirectURL = null; IRequest sloReq = sloContainer.getSloRequest(); if (sloReq != null && sloReq instanceof PVPSProfilePendingRequest) { //send SLO response to SLO request issuer SingleLogoutService sloService = sloBuilder.getResponseSLODescriptor((PVPSProfilePendingRequest)sloContainer.getSloRequest()); LogoutResponse message = sloBuilder.buildSLOResponseMessage(sloService, (PVPSProfilePendingRequest)sloContainer.getSloRequest(), sloContainer.getSloFailedOAs()); redirectURL = sloBuilder.getFrontChannelSLOMessageURL(sloService, message, req, resp, ((PVPSProfilePendingRequest)sloContainer.getSloRequest()).getRequest().getRelayState()); } else { //print SLO information directly redirectURL = HTTPUtils.extractAuthURLFromRequest(req) + "/idpSingleLogout"; String artifact = Random.nextRandom(); String statusCode = null; if (sloContainer.getSloFailedOAs() == null || sloContainer.getSloFailedOAs().size() == 0) statusCode = MOAIDAuthConstants.SLOSTATUS_SUCCESS; else statusCode = MOAIDAuthConstants.SLOSTATUS_ERROR; transactionStorage.put(artifact, statusCode, -1); redirectURL = HTTPUtils.addURLParameter(redirectURL, MOAIDAuthConstants.PARAM_SLOSTATUS, artifact); } //redirect to Redirect Servlet String url = authURL + "/RedirectServlet"; url = HTTPUtils.addURLParameter(url, RedirectServlet.REDIRCT_PARAM_URL, URLEncoder.encode(redirectURL, "UTF-8")); url = resp.encodeRedirectURL(url); resp.setContentType("text/html"); resp.setStatus(302); resp.addHeader("Location", url); return; } catch (MOADatabaseException e) { Logger.info("Find no SLO information with processingID " + restartProcess); } catch (NoMetadataInformationException e) { Logger.warn("Build SLO respone FAILED.", e); } catch (NOSLOServiceDescriptorException e) { Logger.warn("Build SLO respone FAILED.", e); } catch (MOAIDException e) { Logger.warn("Build SLO respone FAILED.", e); } catch (EAAFException e) { Logger.warn("Build SLO respone FAILED.", e); } try { DefaultGUIFormBuilderConfiguration config = new DefaultGUIFormBuilderConfiguration( authURL, DefaultGUIFormBuilderConfiguration.VIEW_SINGLELOGOUT, null); config.putCustomParameterWithOutEscaption("errorMsg", MOAIDMessageProvider.getInstance().getMessage("slo.01", null)); guiBuilder.build(resp, config, "Single-LogOut GUI"); } catch (GUIBuildException e) { e.printStackTrace(); } return; } } try { DefaultGUIFormBuilderConfiguration config = new DefaultGUIFormBuilderConfiguration( authURL, DefaultGUIFormBuilderConfiguration.VIEW_SINGLELOGOUT, null); config.putCustomParameter("successMsg", MOAIDMessageProvider.getInstance().getMessage("slo.02", null)); guiBuilder.build(resp, config, "Single-LogOut GUI"); } catch (GUIBuildException e) { e.printStackTrace(); } } }