/* * 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.protocols; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; import at.gv.egovernment.moa.id.auth.builder.AuthenticationDataBuilder; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; import at.gv.egovernment.moa.id.auth.servlet.AbstractController; import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; import at.gv.egovernment.moa.id.commons.api.IRequest; import at.gv.egovernment.moa.id.commons.api.data.IAuthenticationSession; import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.data.SLOInformationInterface; import at.gv.egovernment.moa.id.moduls.AuthenticationManager; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.moduls.IModulInfo; import at.gv.egovernment.moa.id.moduls.RequestImpl; import at.gv.egovernment.moa.id.moduls.SSOManager; import at.gv.egovernment.moa.id.storage.IAuthenticationSessionStoreage; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; /** * @author tlenz * */ public abstract class AbstractAuthProtocolModulController extends AbstractController implements IModulInfo { public static final String FINALIZEPROTOCOL_ENDPOINT = "finalizeAuthProtocol"; @Autowired protected ApplicationContext applicationContext; @Autowired private SSOManager ssomanager; @Autowired protected AuthenticationManager authmanager; @Autowired protected IAuthenticationSessionStoreage authenticatedSessionStorage; @Autowired private AuthenticationDataBuilder authDataBuilder; /** * Initialize an authentication process for this protocol request * * @param httpReq HttpServletRequest * @param httpResp HttpServletResponse * @param protocolRequest Authentication request which is actually in process * @throws IOException */ protected void performAuthentication(HttpServletRequest req, HttpServletResponse resp, RequestImpl pendingReq) throws IOException { try { if (pendingReq.isNeedAuthentication()) { //request needs authentication --> start authentication process ... //load Parameters from OnlineApplicationConfiguration IOAAuthParameters oaParam = pendingReq.getOnlineApplicationConfiguration(); if (oaParam == null) { throw new AuthenticationException("auth.00", new Object[] { pendingReq.getOAURL() }); } AuthenticationSession ssoMoaSession = authmanager.doAuthentication(req, resp, pendingReq); if (ssoMoaSession != null) { //authenticated MOASession already exists --> protocol-specific postProcessing can start directly finalizeAuthenticationProcess(req, resp, pendingReq, ssoMoaSession); //transaction is finished, log transaction finished event revisionsLogger.logEvent(MOAIDEventConstants.TRANSACTION_DESTROYED, pendingReq.getUniqueTransactionIdentifier()); } } else { executeProtocolSpecificAction(req, resp, pendingReq, null); } } catch (Exception e) { buildProtocolSpecificErrorResponse(e, req, resp, pendingReq); removeUserSession(pendingReq, req, resp); } } protected String createNewSSOSessionCookie(HttpServletRequest req, HttpServletResponse resp, IRequest pendingReq, IAuthenticationSession moaSession) { Logger.debug("Add SSO information to MOASession."); //Store SSO information into database String newSSOSessionId = ssomanager.createSSOSessionInformations(moaSession.getSessionID(), pendingReq.getOAURL()); //set SSO cookie to response if (MiscUtil.isNotEmpty(newSSOSessionId)) { ssomanager.setSSOSessionID(req, resp, newSSOSessionId); } else { ssomanager.deleteSSOSessionID(req, resp); } return newSSOSessionId; } /** * Finalize the requested protocol operation * * @param httpReq HttpServletRequest * @param httpResp HttpServletResponse * @param protocolRequest Authentication request which is actually in process * @param moaSession MOASession object, which is used to generate the protocol specific authentication information * @throws Exception */ protected void finalizeAuthenticationProcess(HttpServletRequest req, HttpServletResponse resp, IRequest pendingReq, IAuthenticationSession moaSession) throws Exception { String newSSOSessionId = null; //if Single Sign-On functionality is enabled for this request if (pendingReq.needSingleSignOnFunctionality()) { newSSOSessionId = createNewSSOSessionCookie(req, resp, pendingReq, moaSession); } //build authenticationdata from session information and OA configuration IAuthData authData = authDataBuilder.buildAuthenticationData(pendingReq, moaSession); //execute the protocol-specific action SLOInformationInterface sloInformation = executeProtocolSpecificAction(req, resp, pendingReq, authData); //check if SSO boolean isSSOCookieSetted = MiscUtil.isNotEmpty(newSSOSessionId); //Store OA specific SSO session information if an SSO cookie is set if (isSSOCookieSetted) { try { AuthenticationSession internalDBSSOSession = null; //create new SSO session, if actually no SSO session exists if (MiscUtil.isEmpty(pendingReq.getInternalSSOSessionIdentifier())) { internalDBSSOSession = authenticatedSessionStorage.createInternalSSOSession(pendingReq); authenticatedSessionStorage.addSSOInformation(internalDBSSOSession.getSessionID(), newSSOSessionId, sloInformation, pendingReq); //MOA SSO-session already exists only update is required } else if (MiscUtil.isNotEmpty(pendingReq.getInternalSSOSessionIdentifier()) && moaSession instanceof AuthenticationSession) { authenticatedSessionStorage.addSSOInformation(moaSession.getSessionID(), newSSOSessionId, sloInformation, pendingReq); } else { Logger.fatal("MOA-Session data object has a suspect or unsupported type:" + moaSession.getClass().getName() + " pendingReq_internalSsoId:" + pendingReq.getInternalSSOSessionIdentifier()); throw new AuthenticationException("1299", null); } } catch (AuthenticationException e) { Logger.warn("SSO Session information can not be stored -> SSO is not enabled!"); authmanager.performOnlyIDPLogOut(req, resp, moaSession.getSessionID()); } } else { //remove MOASession from database authmanager.performOnlyIDPLogOut(req, resp, moaSession.getSessionID()); } //Advanced statistic logging statisticLogger.logSuccessOperation(pendingReq, authData, isSSOCookieSetted); } /** * Executes the requested protocol action * * @param httpReq HttpServletRequest * @param httpResp HttpServletResponse * @param protocolRequest Authentication request which is actually in process * @param authData Service-provider specific authentication data * * @return Return Single LogOut information or null if protocol supports no SSO * * @throws Exception */ private SLOInformationInterface executeProtocolSpecificAction(HttpServletRequest httpReq, HttpServletResponse httpResp, IRequest pendingReq, IAuthData authData) throws Exception { try { // request needs no authentication --> start request processing Class clazz = Class.forName(pendingReq.requestedAction()); if (clazz == null || !IAction.class.isAssignableFrom(clazz)) { Logger.fatal("Requested protocol-action processing Class is NULL or does not implement the IAction interface."); throw new Exception("Requested protocol-action processing Class is NULL or does not implement the IAction interface."); } IAction protocolAction = (IAction) applicationContext.getBean(clazz); return protocolAction.processRequest(pendingReq, httpReq, httpResp, authData); } catch (ClassNotFoundException e) { Logger.fatal("Requested Auth. protocol processing Class is NULL or does not implement the IAction interface."); throw new Exception("Requested Auth. protocol processing Class is NULL or does not implement the IAction interface."); } } protected void removeUserSession(IRequest pendingReq, HttpServletRequest req, HttpServletResponse resp) { authmanager.performOnlyIDPLogOut(req, resp, pendingReq.getInternalSSOSessionIdentifier()); } protected void buildProtocolSpecificErrorResponse(Throwable throwable, HttpServletRequest req, HttpServletResponse resp, IRequest protocolRequest) throws IOException { try { Class clazz = Class.forName(protocolRequest.requestedModule()); if (clazz == null || !IModulInfo.class.isAssignableFrom(clazz)) { Logger.fatal("Requested protocol module Class is NULL or does not implement the IModulInfo interface."); throw new Exception("Requested protocol module Class is NULL or does not implement the IModulInfo interface."); } IModulInfo handlingModule = (IModulInfo) applicationContext.getBean(clazz); if (handlingModule.generateErrorMessage( throwable, req, resp, protocolRequest)) { //log Error to technical log logExceptionToTechnicalLog(throwable); //log Error Message statisticLogger.logErrorOperation(throwable, protocolRequest); return; } else { handleErrorNoRedirect(throwable, req, resp, true); } } catch (Throwable e) { Logger.error(e); handleErrorNoRedirect(throwable, req, resp, true); } } /* (non-Javadoc) * @see at.gv.egovernment.moa.id.moduls.IModulInfo#getName() */ @Override public abstract String getName(); /* (non-Javadoc) * @see at.gv.egovernment.moa.id.moduls.IModulInfo#getPath() */ @Override public abstract String getPath(); /* (non-Javadoc) * @see at.gv.egovernment.moa.id.moduls.IModulInfo#generateErrorMessage(java.lang.Throwable, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.moduls.IRequest) */ @Override public abstract boolean generateErrorMessage(Throwable e, HttpServletRequest request, HttpServletResponse response, IRequest protocolRequest) throws Throwable; /* (non-Javadoc) * @see at.gv.egovernment.moa.id.moduls.IModulInfo#validate(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.moduls.IRequest) */ @Override public abstract boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending); }