From 759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 4 Dec 2019 19:43:32 +0100 Subject: common EGIZ code-style refactoring --- .../services/ProtocolAuthenticationService.java | 992 +++++++++++---------- 1 file changed, 504 insertions(+), 488 deletions(-) (limited to 'eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/ProtocolAuthenticationService.java') diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/ProtocolAuthenticationService.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/ProtocolAuthenticationService.java index 2edf8a75..a5030851 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/ProtocolAuthenticationService.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/ProtocolAuthenticationService.java @@ -1,25 +1,22 @@ -/******************************************************************************* - * Copyright 2019 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2019 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ + * 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.egiz.eaaf.core.impl.idp.auth.services; import java.io.IOException; @@ -27,499 +24,518 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; import java.util.List; - import javax.naming.ConfigurationException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.text.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; -import org.springframework.stereotype.Service; - import at.gv.egiz.components.eventlog.api.EventConstants; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.IRequestStorage; import at.gv.egiz.eaaf.core.api.IStatusMessenger; import at.gv.egiz.eaaf.core.api.data.EAAFConstants; -import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfiguration; -import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfigurationFactory; -import at.gv.egiz.eaaf.core.api.gui.IGUIFormBuilder; +import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfigurationFactory; +import at.gv.egiz.eaaf.core.api.gui.IGuiFormBuilder; import at.gv.egiz.eaaf.core.api.gui.ModifyableGuiBuilderConfiguration; import at.gv.egiz.eaaf.core.api.idp.IAction; import at.gv.egiz.eaaf.core.api.idp.IAuthData; import at.gv.egiz.eaaf.core.api.idp.IAuthenticationDataBuilder; import at.gv.egiz.eaaf.core.api.idp.IModulInfo; -import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IspConfiguration; import at.gv.egiz.eaaf.core.api.idp.auth.IAuthenticationManager; -import at.gv.egiz.eaaf.core.api.idp.auth.ISSOManager; +import at.gv.egiz.eaaf.core.api.idp.auth.ISsoManager; import at.gv.egiz.eaaf.core.api.idp.auth.services.IProtocolAuthenticationService; -import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface; +import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; import at.gv.egiz.eaaf.core.api.logging.IStatisticLogger; import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException; -import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; -import at.gv.egiz.eaaf.core.exceptions.EAAFSSOException; -import at.gv.egiz.eaaf.core.exceptions.GUIBuildException; +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafSsoException; +import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException; import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException; import at.gv.egiz.eaaf.core.exceptions.ProtocolNotActiveException; -import at.gv.egiz.eaaf.core.impl.gui.AbstractGUIFormBuilderConfiguration; +import at.gv.egiz.eaaf.core.impl.gui.AbstractGuiFormBuilderConfiguration; import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; -import at.gv.egiz.eaaf.core.impl.utils.HTTPUtils; +import at.gv.egiz.eaaf.core.impl.utils.HttpUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Service; @Service public class ProtocolAuthenticationService implements IProtocolAuthenticationService { - private static final Logger log = LoggerFactory.getLogger(ProtocolAuthenticationService.class); - - private static final List ERROR_LOGGER_ON_INFO_LEVEL = - Arrays.asList( - IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_USERSTOP - ); - - @Autowired(required=true) private ApplicationContext applicationContext; - @Autowired(required=true) private IAuthenticationManager authmanager; - @Autowired(required=true) private IAuthenticationDataBuilder authDataBuilder; - @Autowired(required=true) private IGUIBuilderConfigurationFactory guiConfigFactory; - @Autowired(required=true) private IStatusMessenger statusMessager; - @Autowired(required=true) private IRequestStorage requestStorage; - @Autowired(required=true) IPendingRequestIdGenerationStrategy pendingReqIdGenerationStrategy; - - @Autowired(required=false) private ISSOManager ssoManager; - @Autowired private IStatisticLogger statisticLogger; - @Autowired private IRevisionLogger revisionsLogger; - - - private IGUIFormBuilder guiBuilder; - - /* (non-Javadoc) - * @see at.gv.egiz.eaaf.core.impl.idp.auth.services.IProtocolAuthenticationService#performAuthentication(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egiz.eaaf.core.api.IRequest) - */ - @Override - public void performAuthentication(final HttpServletRequest req, final HttpServletResponse resp, - final IRequest pendingReq) throws IOException, EAAFException { - try { - if (pendingReq.isNeedAuthentication()) { - //request needs authentication --> start authentication process ... - - //set pendingRequestId to support asynchrony message-processing - ((RequestImpl)pendingReq).setPendingRequestId(pendingReqIdGenerationStrategy.generateExternalPendingRequestId()); - - //load Parameters from OnlineApplicationConfiguration - final ISPConfiguration oaParam = pendingReq.getServiceProviderConfiguration(); - - if (oaParam == null) - throw new EAAFAuthenticationException( - IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOSPCONFIG, - new Object[] { pendingReq.getSPEntityId() }); - - if (authmanager.doAuthentication(req, resp, pendingReq)) { - //pending request is already authenticated --> protocol-specific postProcessing can start directly - finalizeAuthentication(req, resp, pendingReq); - - //transaction is finished, log transaction finished event - revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, pendingReq.getUniqueTransactionIdentifier()); - - } - - } else { - executeProtocolSpecificAction(req, resp, pendingReq, null); - - } - - } catch (final Exception e) { - buildProtocolSpecificErrorResponse(e, req, resp, pendingReq); - authmanager.performOnlyIDPLogOut(req, resp, pendingReq); - - } - } - - /* (non-Javadoc) - * @see at.gv.egiz.eaaf.core.impl.idp.auth.services.IProtocolAuthenticationService#finalizeAuthentication(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egiz.eaaf.core.api.IRequest) - */ - @Override - public void finalizeAuthentication(final HttpServletRequest req, final HttpServletResponse resp, final IRequest pendingReq) throws EAAFException, IOException{ - log.debug("Finalize PendingRequest with ID " + pendingReq.getPendingRequestId()); - try { - - //check if pending-request has 'abortedByUser' flag set - if (pendingReq.isAbortedByUser()) { - //send authentication aborted error to Service Provider - buildProtocolSpecificErrorResponse( - new EAAFAuthenticationException( - IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_USERSTOP, - new Object[] {}), - req, resp, pendingReq); - - //do not remove the full active SSO-Session - // in case of only one Service-Provider authentication request is aborted - if ( !pendingReq.needSingleSignOnFunctionality()) { - requestStorage.removePendingRequest(pendingReq.getPendingRequestId()); - - } - - //check if pending-request are authenticated - } else if (pendingReq.isAuthenticated() && !pendingReq.isNeedUserConsent()) { - internalFinalizeAuthenticationProcess(req, resp, pendingReq); - - } else { - //suspect state: pending-request is not aborted but also are not authenticated - log.warn("PendingRequest flag for 'authenticated':{} and 'needConsent':{}", pendingReq.isAuthenticated(), pendingReq.isNeedUserConsent()); - if (pendingReq.isNeedUserConsent()) { - log.error("PendingRequest NEEDS user-consent. Can NOT fininalize authentication --> Abort authentication process!"); - - } else { - log.error("PendingRequest is NOT authenticated --> Abort authentication process!"); - - } - - handleErrorNoRedirect( - new EAAFException( - "auth.20", - null), req, resp, true); - - } - - } catch (final Exception e) { - log.error("Finalize authentication protocol FAILED." , e); - buildProtocolSpecificErrorResponse(e, req, resp, pendingReq); - - } - - //remove pending-request - if (pendingReq != null) { - requestStorage.removePendingRequest(pendingReq.getPendingRequestId()); - revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, pendingReq.getUniqueTransactionIdentifier()); - - } - } - - - @Override - public void buildProtocolSpecificErrorResponse(final Throwable throwable, final HttpServletRequest req, - final HttpServletResponse resp, final IRequest protocolRequest) throws EAAFException, IOException { - try { - - final Class clazz = Class.forName(protocolRequest.requestedModule()); - - if (clazz == null || - !IModulInfo.class.isAssignableFrom(clazz)) { - log.error("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."); - - } - - final 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); - - //write revision log entries - revisionsLogger.logEvent(protocolRequest, EventConstants.TRANSACTION_ERROR, protocolRequest.getUniqueTransactionIdentifier()); - - return; - - } else { - handleErrorNoRedirect(throwable, req, resp, true); - - } - - } catch (final Throwable e) { - handleErrorNoRedirect(throwable, req, resp, true); - - } - - } - - @Override - public void handleErrorNoRedirect(final Throwable throwable, final HttpServletRequest req, - final HttpServletResponse resp, final boolean writeExceptionToStatisticLog) throws IOException, EAAFException { - - //log Exception into statistic database - if (writeExceptionToStatisticLog) - statisticLogger.logErrorOperation(throwable); - - //write errror to console - logExceptionToTechnicalLog(throwable); - - //return error to Web browser - if (throwable instanceof EAAFException || throwable instanceof ProcessExecutionException) - internalMOAIDExceptionHandler(req, resp, (Exception)throwable, false); - - else { - //write generic message for general exceptions - final String msg = statusMessager.getMessage(IStatusMessenger.CODES_INTERNAL_ERROR_GENERIC, null); - writeHTMLErrorResponse(req, resp, msg, "9199", null, (Exception) throwable); - - } - - } - - - public void setGuiBuilder(IGUIFormBuilder guiBuilder) { - this.guiBuilder = guiBuilder; - } - - /** - * 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 internalFinalizeAuthenticationProcess(final HttpServletRequest req, final HttpServletResponse resp, - final IRequest pendingReq) throws Exception { - - String newSSOSessionId = null; - - //if Single Sign-On functionality is enabled for this request - if (pendingReq.needSingleSignOnFunctionality()) { - if (ssoManager != null) { - newSSOSessionId = ssoManager.createNewSSOSessionCookie(req, resp, pendingReq); - if (StringUtils.isEmpty(pendingReq.getInternalSSOSessionIdentifier())) - ssoManager.createNewSSOSession(pendingReq, newSSOSessionId); - - } else - log.warn("SSO is requested but there is not SSO Session-Manager available"); - - } - - //build authenticationdata from session information and OA configuration - final IAuthData authData = authDataBuilder.buildAuthenticationData(pendingReq); - - //execute the protocol-specific action - final SLOInformationInterface sloInformation = executeProtocolSpecificAction(req, resp, pendingReq, authData); - - //Store OA specific SSO session information if an SSO cookie is set - if (StringUtils.isNotEmpty(newSSOSessionId)) { - try { - ssoManager.updateSSOSession(pendingReq, newSSOSessionId, sloInformation); - - } catch (final EAAFSSOException e) { - log.warn("SSO Session information can not be stored -> SSO is not enabled!"); - authmanager.performOnlyIDPLogOut(req, resp, pendingReq); - - } - - } else { - //remove MOASession from database - authmanager.performOnlyIDPLogOut(req, resp, pendingReq); - - } - - //Advanced statistic logging - statisticLogger.logSuccessOperation(pendingReq, authData, StringUtils.isNotEmpty(newSSOSessionId)); - - } - - /** - * 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(final HttpServletRequest httpReq, final HttpServletResponse httpResp, - final IRequest pendingReq, final IAuthData authData) throws Exception { - try { - // request needs no authentication --> start request processing - final Class clazz = Class.forName(pendingReq.requestedAction()); - if (clazz == null || - !IAction.class.isAssignableFrom(clazz)) { - log.error("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."); - - } - - final IAction protocolAction = (IAction) applicationContext.getBean(clazz); - return protocolAction.processRequest(pendingReq, httpReq, httpResp, authData); - - } catch (final ClassNotFoundException e) { - log.error("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."); - } - - } - - /** - * Write a Exception to the MOA-ID-Auth internal technical log - * - * @param loggedException Exception to log - */ - protected void logExceptionToTechnicalLog(final Throwable loggedException) { - if (!( loggedException instanceof EAAFException - || loggedException instanceof ProcessExecutionException )) { - log.error("Receive an internal error: Message=" + loggedException.getMessage(), loggedException); - - } else { - if (loggedException instanceof EAAFAuthenticationException && - ERROR_LOGGER_ON_INFO_LEVEL.contains( - ((EAAFAuthenticationException) loggedException).getErrorId())) { - if (log.isDebugEnabled() || log.isTraceEnabled()) { - log.info(loggedException.getMessage(), loggedException); - - } else { - log.info(loggedException.getMessage()); - - } - - } else { - if (log.isDebugEnabled() || log.isTraceEnabled()) { - log.warn(loggedException.getMessage(), loggedException); - - } else { - log.warn(loggedException.getMessage()); - - } - } - } - } - - private void writeHTMLErrorResponse(@NonNull final HttpServletRequest httpReq, @NonNull final HttpServletResponse httpResp, - @NonNull final String msg, @NonNull final String errorCode, @Nullable final Object[] params, @NonNull final Exception error) throws IOException, EAAFException { - - try { - final IGUIBuilderConfiguration config - = guiConfigFactory.getDefaultErrorGUI(HTTPUtils.extractAuthURLFromRequest(httpReq)); - - - String[] errorCodeParams = null; - if (params == null) - errorCodeParams = new String[] {}; - else { - errorCodeParams = new String[params.length]; - for (int i=0; i ERROR_LOGGER_ON_INFO_LEVEL = + Arrays.asList(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_USERSTOP); + + @Autowired(required = true) + private ApplicationContext applicationContext; + @Autowired(required = true) + private IAuthenticationManager authmanager; + @Autowired(required = true) + private IAuthenticationDataBuilder authDataBuilder; + @Autowired(required = true) + private IGuiBuilderConfigurationFactory guiConfigFactory; + @Autowired(required = true) + private IStatusMessenger statusMessager; + @Autowired(required = true) + private IRequestStorage requestStorage; + @Autowired(required = true) + IPendingRequestIdGenerationStrategy pendingReqIdGenerationStrategy; + + @Autowired(required = false) + private ISsoManager ssoManager; + @Autowired + private IStatisticLogger statisticLogger; + @Autowired + private IRevisionLogger revisionsLogger; + + + private IGuiFormBuilder guiBuilder; + + /* + * (non-Javadoc) + * + * @see at.gv.egiz.eaaf.core.impl.idp.auth.services.IProtocolAuthenticationService# + * performAuthentication(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse, at.gv.egiz.eaaf.core.api.IRequest) + */ + @Override + public void performAuthentication(final HttpServletRequest req, final HttpServletResponse resp, + final IRequest pendingReq) throws IOException, EaafException { + try { + if (pendingReq.isNeedAuthentication()) { + // request needs authentication --> start authentication process ... + + // set pendingRequestId to support asynchrony message-processing + ((RequestImpl) pendingReq) + .setPendingRequestId(pendingReqIdGenerationStrategy.generateExternalPendingRequestId()); + + // load Parameters from OnlineApplicationConfiguration + final IspConfiguration oaParam = pendingReq.getServiceProviderConfiguration(); + + if (oaParam == null) { + throw new EaafAuthenticationException( + IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOSPCONFIG, + new Object[] {pendingReq.getSpEntityId()}); + } + + if (authmanager.doAuthentication(req, resp, pendingReq)) { + // pending request is already authenticated --> protocol-specific postProcessing can start + // directly + finalizeAuthentication(req, resp, pendingReq); + + // transaction is finished, log transaction finished event + revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, + pendingReq.getUniqueTransactionIdentifier()); + + } + + } else { + executeProtocolSpecificAction(req, resp, pendingReq, null); + + } + + } catch (final Exception e) { + buildProtocolSpecificErrorResponse(e, req, resp, pendingReq); + authmanager.performOnlyIdpLogOut(req, resp, pendingReq); + + } + } + + /* + * (non-Javadoc) + * + * @see at.gv.egiz.eaaf.core.impl.idp.auth.services.IProtocolAuthenticationService# + * finalizeAuthentication(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse, at.gv.egiz.eaaf.core.api.IRequest) + */ + @Override + public void finalizeAuthentication(final HttpServletRequest req, final HttpServletResponse resp, + final IRequest pendingReq) throws EaafException, IOException { + log.debug("Finalize PendingRequest with ID " + pendingReq.getPendingRequestId()); + try { + + // check if pending-request has 'abortedByUser' flag set + if (pendingReq.isAbortedByUser()) { + // send authentication aborted error to Service Provider + buildProtocolSpecificErrorResponse( + new EaafAuthenticationException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_USERSTOP, + new Object[] {}), + req, resp, pendingReq); + + // do not remove the full active SSO-Session + // in case of only one Service-Provider authentication request is aborted + if (!pendingReq.needSingleSignOnFunctionality()) { + requestStorage.removePendingRequest(pendingReq.getPendingRequestId()); + + } + + // check if pending-request are authenticated + } else if (pendingReq.isAuthenticated() && !pendingReq.isNeedUserConsent()) { + internalFinalizeAuthenticationProcess(req, resp, pendingReq); + + } else { + // suspect state: pending-request is not aborted but also are not authenticated + log.warn("PendingRequest flag for 'authenticated':{} and 'needConsent':{}", + pendingReq.isAuthenticated(), pendingReq.isNeedUserConsent()); + if (pendingReq.isNeedUserConsent()) { + log.error( + "PendingRequest NEEDS user-consent. Can NOT fininalize authentication --> Abort authentication process!"); + + } else { + log.error("PendingRequest is NOT authenticated --> Abort authentication process!"); + + } + + handleErrorNoRedirect(new EaafException("auth.20", null), req, resp, true); + + } + + } catch (final Exception e) { + log.error("Finalize authentication protocol FAILED.", e); + buildProtocolSpecificErrorResponse(e, req, resp, pendingReq); + + } + + // remove pending-request + requestStorage.removePendingRequest(pendingReq.getPendingRequestId()); + revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, + pendingReq.getUniqueTransactionIdentifier()); + + } + + + @Override + public void buildProtocolSpecificErrorResponse(final Throwable throwable, + final HttpServletRequest req, final HttpServletResponse resp, final IRequest protocolRequest) + throws EaafException, IOException { + try { + + final Class clazz = Class.forName(protocolRequest.requestedModule()); + + if (clazz == null || !IModulInfo.class.isAssignableFrom(clazz)) { + log.error( + "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."); + + } + + final 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); + + // write revision log entries + revisionsLogger.logEvent(protocolRequest, EventConstants.TRANSACTION_ERROR, + protocolRequest.getUniqueTransactionIdentifier()); + + return; + + } else { + handleErrorNoRedirect(throwable, req, resp, true); + + } + + } catch (final Throwable e) { + handleErrorNoRedirect(throwable, req, resp, true); + + } + + } + + @Override + public void handleErrorNoRedirect(final Throwable throwable, final HttpServletRequest req, + final HttpServletResponse resp, final boolean writeExceptionToStatisticLog) + throws IOException, EaafException { + + // log Exception into statistic database + if (writeExceptionToStatisticLog) { + statisticLogger.logErrorOperation(throwable); + } + + // write errror to console + logExceptionToTechnicalLog(throwable); + + // return error to Web browser + if (throwable instanceof EaafException || throwable instanceof ProcessExecutionException) { + internalMoaidExceptionHandler(req, resp, (Exception) throwable, false); + } else { + // write generic message for general exceptions + final String msg = + statusMessager.getMessage(IStatusMessenger.CODES_INTERNAL_ERROR_GENERIC, null); + writeHtmlErrorResponse(req, resp, msg, "9199", null, (Exception) throwable); + + } + + } + + + public void setGuiBuilder(final IGuiFormBuilder guiBuilder) { + this.guiBuilder = guiBuilder; + } + + /** + * 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 In case of an error + */ + protected void internalFinalizeAuthenticationProcess(final HttpServletRequest req, + final HttpServletResponse resp, final IRequest pendingReq) throws Exception { + + String newSsoSessionId = null; + + // if Single Sign-On functionality is enabled for this request + if (pendingReq.needSingleSignOnFunctionality()) { + if (ssoManager != null) { + newSsoSessionId = ssoManager.createNewSsoSessionCookie(req, resp, pendingReq); + if (StringUtils.isEmpty(pendingReq.getInternalSsoSessionIdentifier())) { + ssoManager.createNewSsoSession(pendingReq, newSsoSessionId); + } + + } else { + log.warn("SSO is requested but there is not SSO Session-Manager available"); + } + + } + + // build authenticationdata from session information and OA configuration + final IAuthData authData = authDataBuilder.buildAuthenticationData(pendingReq); + + // execute the protocol-specific action + final SloInformationInterface sloInformation = + executeProtocolSpecificAction(req, resp, pendingReq, authData); + + // Store OA specific SSO session information if an SSO cookie is set + if (StringUtils.isNotEmpty(newSsoSessionId)) { + try { + ssoManager.updateSsoSession(pendingReq, newSsoSessionId, sloInformation); + + } catch (final EaafSsoException e) { + log.warn("SSO Session information can not be stored -> SSO is not enabled!"); + authmanager.performOnlyIdpLogOut(req, resp, pendingReq); + + } + + } else { + // remove MOASession from database + authmanager.performOnlyIdpLogOut(req, resp, pendingReq); + + } + + // Advanced statistic logging + statisticLogger.logSuccessOperation(pendingReq, authData, + StringUtils.isNotEmpty(newSsoSessionId)); + + } + + /** + * 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 in case of an error + */ + private SloInformationInterface executeProtocolSpecificAction(final HttpServletRequest httpReq, + final HttpServletResponse httpResp, final IRequest pendingReq, final IAuthData authData) + throws Exception { + try { + // request needs no authentication --> start request processing + final Class clazz = Class.forName(pendingReq.requestedAction()); + if (clazz == null || !IAction.class.isAssignableFrom(clazz)) { + log.error( + "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."); + + } + + final IAction protocolAction = (IAction) applicationContext.getBean(clazz); + return protocolAction.processRequest(pendingReq, httpReq, httpResp, authData); + + } catch (final ClassNotFoundException e) { + log.error( + "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."); + } + + } + + /** + * Write a Exception to the MOA-ID-Auth internal technical log. + * + * @param loggedException Exception to log + */ + protected void logExceptionToTechnicalLog(final Throwable loggedException) { + if (!(loggedException instanceof EaafException + || loggedException instanceof ProcessExecutionException)) { + log.error("Receive an internal error: Message=" + loggedException.getMessage(), + loggedException); + + } else { + if (loggedException instanceof EaafAuthenticationException && ERROR_LOGGER_ON_INFO_LEVEL + .contains(((EaafAuthenticationException) loggedException).getErrorId())) { + if (log.isDebugEnabled() || log.isTraceEnabled()) { + log.info(loggedException.getMessage(), loggedException); + + } else { + log.info(loggedException.getMessage()); + + } + + } else { + if (log.isDebugEnabled() || log.isTraceEnabled()) { + log.warn(loggedException.getMessage(), loggedException); + + } else { + log.warn(loggedException.getMessage()); + + } + } + } + } + + private void writeHtmlErrorResponse(@NonNull final HttpServletRequest httpReq, + @NonNull final HttpServletResponse httpResp, @NonNull final String msg, + @NonNull final String errorCode, @Nullable final Object[] params, + @NonNull final Exception error) throws IOException, EaafException { + + try { + final IGuiBuilderConfiguration config = + guiConfigFactory.getDefaultErrorGui(HttpUtils.extractAuthUrlFromRequest(httpReq)); + + + String[] errorCodeParams = null; + if (params == null) { + errorCodeParams = new String[] {}; + } else { + errorCodeParams = new String[params.length]; + for (int i = 0; i < params.length; i++) { + if (params[i] != null) { + errorCodeParams[i] = params[i].toString(); + } else { + errorCodeParams[i] = "null"; + } + + } + } + + + + // add errorcode and errormessage + if (config instanceof ModifyableGuiBuilderConfiguration) { + ((ModifyableGuiBuilderConfiguration) config).putCustomParameter( + AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERROMSG, msg); + ((ModifyableGuiBuilderConfiguration) config).putCustomParameter( + AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERRORCODE, errorCode); + ((ModifyableGuiBuilderConfiguration) config).putCustomParameterWithOutEscaption( + AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERRORCODEPARAMS, + ArrayUtils.toString(errorCodeParams)); + + // add stacktrace if debug is enabled + if (log.isTraceEnabled()) { + ((ModifyableGuiBuilderConfiguration) config).putCustomParameter( + AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERRORSTACKTRACE, + getStacktraceFromException(error)); + + } + + } else { + log.info( + "Can not ADD error message, because 'GUIBuilderConfiguration' is not modifieable "); + } + + + + guiBuilder.build(httpReq, httpResp, config, "Error-Message"); + + } catch (final GuiBuildException e) { + log.warn("Can not build error-message GUI.", e); + throw new EaafException("9199", null, e); + + + } + + } + + private String getStacktraceFromException(final Exception ex) { + final StringWriter errors = new StringWriter(); + ex.printStackTrace(new PrintWriter(errors)); + return errors.toString(); + + } + + private void internalMoaidExceptionHandler(final HttpServletRequest req, + final HttpServletResponse resp, final Exception e, final boolean writeExceptionToStatisicLog) + throws IOException, EaafException { + if (e instanceof ProtocolNotActiveException) { + resp.getWriter().write(e.getMessage()); + resp.setContentType(EAAFConstants.CONTENTTYPE_HTML_UTF8); + resp.sendError(HttpServletResponse.SC_FORBIDDEN, + StringEscapeUtils.escapeHtml4(StringEscapeUtils.escapeEcmaScript(e.getMessage()))); + + } else if (e instanceof AuthnRequestValidatorException) { + final AuthnRequestValidatorException ex = (AuthnRequestValidatorException) e; + // log Error Message + if (writeExceptionToStatisicLog) { + statisticLogger.logErrorOperation(ex, ex.getErrorRequest()); + } + + // write error message + // writeBadRequestErrorResponse(req, resp, (EAAFException) e); + writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), + null, e); + + } else if (e instanceof InvalidProtocolRequestException) { + // send error response + // writeBadRequestErrorResponse(req, resp, (EAAFException) e); + writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), + null, e); + + } else if (e instanceof ConfigurationException) { + // send HTML formated error message + writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), + null, e); + + } else if (e instanceof EaafException) { + // send HTML formated error message + writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), + ((EaafException) e).getParams(), e); + + } else if (e instanceof ProcessExecutionException) { + // send HTML formated error message + writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), + null, e); + + } + + } + + } -- cgit v1.2.3