diff options
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_idp')
2 files changed, 528 insertions, 1062 deletions
| diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java deleted file mode 100644 index 597d3c22..00000000 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java +++ /dev/null @@ -1,549 +0,0 @@ -/******************************************************************************* - * Copyright 2017 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: - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eaaf.modules.pvp2.idp.impl; - -import java.util.List; - -import javax.annotation.PostConstruct; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; -import org.joda.time.DateTime; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; -import org.opensaml.saml2.core.Response; -import org.opensaml.saml2.core.Status; -import org.opensaml.saml2.core.StatusCode; -import org.opensaml.saml2.core.StatusMessage; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.ws.security.SecurityPolicyException; -import org.opensaml.xml.security.x509.X509Credential; -import org.opensaml.xml.signature.SignableXMLObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import at.gv.egiz.components.eventlog.api.EventConstants; -import at.gv.egiz.eaaf.core.api.IRequest; -import at.gv.egiz.eaaf.core.api.data.EAAFConstants; -import at.gv.egiz.eaaf.core.api.idp.IModulInfo; -import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; -import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; -import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException; -import at.gv.egiz.eaaf.core.exceptions.NoPassivAuthenticationException; -import at.gv.egiz.eaaf.core.exceptions.SLOException; -import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; -import at.gv.egiz.eaaf.modules.pvp2.PVPEventConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.IPVP2BasicConfiguration; -import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.api.validation.IAuthnRequestPostProcessor; -import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPVPRequestException; -import at.gv.egiz.eaaf.modules.pvp2.exception.NameIDFormatNotSupportedException; -import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionConsumerServiceException; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.SoapBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; -import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EAAFURICompare; -import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; -import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SAMLVerificationEngine; -  -public abstract class AbstractPVP2XProtocol extends AbstractController implements IModulInfo { -	private static final Logger log = LoggerFactory.getLogger(AbstractPVP2XProtocol.class); -	 -	@Autowired(required=true) protected IPVP2BasicConfiguration pvpBasicConfiguration; -	@Autowired(required=true) protected IPVPMetadataProvider metadataProvider; -	@Autowired(required=true) protected SAMLVerificationEngine samlVerificationEngine; -	@Autowired(required=false) protected List<IAuthnRequestPostProcessor> authRequestPostProcessors; -	 -	private AbstractCredentialProvider pvpIDPCredentials; - -	 -		 -	/** -	 * Sets a specific credential provider for PVP S-Profile IDP component. -	 * @param pvpIDPCredentials credential provider -	 */ -	public void setPvpIDPCredentials(AbstractCredentialProvider pvpIDPCredentials) { -		this.pvpIDPCredentials = pvpIDPCredentials; -		 -	} -	 -	public boolean generateErrorMessage(Throwable e, -			HttpServletRequest request, HttpServletResponse response, -			IRequest protocolRequest) throws Throwable { -		 -		if(protocolRequest == null) { -			throw e; -		} -		 -		if(!(protocolRequest instanceof PVPSProfilePendingRequest) ) { -			throw e; -		} -		PVPSProfilePendingRequest pvpRequest = (PVPSProfilePendingRequest)protocolRequest; -		 -		Response samlResponse =  -				SAML2Utils.createSAMLObject(Response.class); -		Status status = SAML2Utils.createSAMLObject(Status.class); -		StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class); -		StatusMessage statusMessage = SAML2Utils.createSAMLObject(StatusMessage.class); -		 -		String moaError = null; -		 -		if(e instanceof NoPassivAuthenticationException) { -			statusCode.setValue(StatusCode.NO_PASSIVE_URI); -			statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage()));	 -			 -		} else if (e instanceof NameIDFormatNotSupportedException) { -			statusCode.setValue(StatusCode.INVALID_NAMEID_POLICY_URI); -			statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); -  -		} else if (e instanceof SLOException) { -			//SLOExecpetions only occurs if session information is lost -			return false; -			 -		} else if(e instanceof PVP2Exception) { -			PVP2Exception ex = (PVP2Exception) e; -			statusCode.setValue(ex.getStatusCodeValue()); -			String statusMessageValue = ex.getStatusMessageValue(); -			if(statusMessageValue != null) { -				statusMessage.setMessage(StringEscapeUtils.escapeXml(statusMessageValue)); -			}						 -			moaError = statusMessager.mapInternalErrorToExternalError(ex.getErrorId()); -			 -		} else { -			statusCode.setValue(StatusCode.RESPONDER_URI); -			statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); -			moaError = statusMessager.getResponseErrorCode(e); -		} -		 -		 -		if (StringUtils.isNotEmpty(moaError)) { -			StatusCode moaStatusCode = SAML2Utils.createSAMLObject(StatusCode.class); -			moaStatusCode.setValue(moaError); -			statusCode.setStatusCode(moaStatusCode); -		} -		 -		status.setStatusCode(statusCode); -		if(statusMessage.getMessage() != null) { -			status.setStatusMessage(statusMessage); -		} -		samlResponse.setStatus(status); -		String remoteSessionID = SAML2Utils.getSecureIdentifier(); -		samlResponse.setID(remoteSessionID); - -		samlResponse.setIssueInstant(new DateTime()); -		Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); -		nissuer.setValue(pvpBasicConfiguration.getIDPEntityId(pvpRequest.getAuthURL())); -		nissuer.setFormat(NameID.ENTITY); -		samlResponse.setIssuer(nissuer); -		 -		IEncoder encoder = null; -		 -		if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {			 -			encoder = applicationContext.getBean("PVPRedirectBinding", RedirectBinding.class); -						 -		} else if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI))  { -			encoder = applicationContext.getBean("PVPPOSTBinding", PostBinding.class); -			 -		} else if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI))  { -			encoder = applicationContext.getBean("PVPSOAPBinding", SoapBinding.class); -		} - -		if(encoder == null) { -			// default to redirect binding -			encoder = new RedirectBinding(); -		} - -		String relayState = null; -		if (pvpRequest.getRequest() != null) -			relayState = pvpRequest.getRequest().getRelayState(); -		 -		X509Credential signCred = pvpIDPCredentials.getIDPAssertionSigningCredential(); -		 -		encoder.encodeRespone(request, response, samlResponse, pvpRequest.getConsumerURL(),  -				relayState, signCred, protocolRequest); -		return true; -	} - -	public boolean validate(HttpServletRequest request, -			HttpServletResponse response, IRequest pending) { -		 -		return true; -	} -		 -	protected void pvpMetadataRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException {		 -		//create pendingRequest object -		PVPSProfilePendingRequest pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class); -		pendingReq.initialize(req, authConfig); -		pendingReq.setModule(getName()); -		 -		revisionsLogger.logEvent( -				pendingReq.getUniqueSessionIdentifier(),  -				pendingReq.getUniqueTransactionIdentifier(),  -				EventConstants.TRANSACTION_IP,  -				req.getRemoteAddr()); -				 -		MetadataAction metadataAction = applicationContext.getBean(MetadataAction.class); -		metadataAction.processRequest(pendingReq,  -				req, resp, null); -		 -	} -	 -	protected void PVPIDPPostRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException {		 -		PVPSProfilePendingRequest pendingReq = null; -		 -		try { -			//create pendingRequest object -			pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class); -			pendingReq.initialize(req, authConfig); -			pendingReq.setModule(getName()); -			 -			revisionsLogger.logEvent(EventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier()); -			revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier());						 -			revisionsLogger.logEvent( -					pendingReq.getUniqueSessionIdentifier(),  -					pendingReq.getUniqueTransactionIdentifier(),  -					EventConstants.TRANSACTION_IP,  -					req.getRemoteAddr()); -			 -			//get POST-Binding decoder implementation -			InboundMessage msg = (InboundMessage) new PostBinding().decode( -					req, resp, metadataProvider, false, -					new EAAFURICompare(pvpBasicConfiguration.getIDPSSOPostService(pendingReq.getAuthURL()))); -			pendingReq.setRequest(msg); -						 -			//preProcess Message -			preProcess(req, resp, pendingReq); -						 -		} catch (SecurityPolicyException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); -			 -		} catch (SecurityException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); -		 -		} catch (EAAFException e) { -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw e; -			 -		} catch (Throwable e) {			 -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); - -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new EAAFException("pvp2.24", new Object[] {e.getMessage()}, e); -		}					 -	} -	 -	protected void PVPIDPRedirecttRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException { -		PVPSProfilePendingRequest pendingReq = null; -		try { -			//create pendingRequest object -			pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class); -			pendingReq.initialize(req, authConfig); -			pendingReq.setModule(getName()); -			 -			revisionsLogger.logEvent(EventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier()); -			revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier());						 -			revisionsLogger.logEvent( -					pendingReq.getUniqueSessionIdentifier(),  -					pendingReq.getUniqueTransactionIdentifier(),  -					EventConstants.TRANSACTION_IP,  -					req.getRemoteAddr()); -			 -			//get POST-Binding decoder implementation -			InboundMessage msg = (InboundMessage) new RedirectBinding().decode( -					req, resp, metadataProvider, false, -					new EAAFURICompare(pvpBasicConfiguration.getIDPSSORedirectService(pendingReq.getAuthURL()))); -			pendingReq.setRequest(msg); -			 -			//preProcess Message -			preProcess(req, resp, pendingReq); -						 -		} catch (SecurityPolicyException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); -			 -		} catch (SecurityException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); -			 -		} catch (EAAFException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.info("Receive INVALID protocol request: " + samlRequest); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw e; -						 -		} catch (Throwable e) {			 -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -						 -			throw new EAAFException("pvp2.24", new Object[] {e.getMessage()}, e); -		}					 -	} -	 -	 -	 -	/** -	 *  -	 *  -	 * @param request -	 * @param response -	 * @param msg -	 * @return true if preprocess can handle this request type, otherwise false -	 * @throws Throwable -	 */ -	abstract protected boolean childPreProcess(HttpServletRequest request, -			HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable; -	 -	protected void preProcess(HttpServletRequest request, -			HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable { -			 -			InboundMessage msg = pendingReq.getRequest(); -		 -			if (StringUtils.isEmpty(msg.getEntityID())) { -				throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}); -				 -			} -			 -			if(!msg.isVerified()) { -				samlVerificationEngine.verify(msg,  -						TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); -				msg.setVerified(true); -								 -			} -			 -			revisionsLogger.logEvent(pendingReq, IRevisionLogger.AUTHPROTOCOL_TYPE, getAuthProtocolIdentifier()); -			 -			if (msg instanceof PVPSProfileRequest &&  -					((PVPSProfileRequest)msg).getSamlRequest() instanceof AuthnRequest) -				preProcessAuthRequest(request, response, pendingReq); - -			else if (childPreProcess(request, response, pendingReq)) -				log.debug("Find protocol handler in child implementation"); -				 -			else { -				log.error("Receive unsupported PVP21 message of type: " + ((PVPSProfileRequest)msg).getSamlRequest().getClass().getName()); -				throw new InvalidPVPRequestException("pvp2.09",  -						new Object[] {((PVPSProfileRequest)msg).getSamlRequest().getClass().getName()}); -			} -							 -			 -			 -			//switch to session authentication -			protAuthService.performAuthentication(request, response, pendingReq);								 -	} - -	 -	/** -	 * PreProcess Authn request -	 * @param request -	 * @param response -	 * @param pendingReq -	 * @throws Throwable -	 */ -	private void preProcessAuthRequest(HttpServletRequest request, -			HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable { - -		PVPSProfileRequest moaRequest = ((PVPSProfileRequest)pendingReq.getRequest());		 -		SignableXMLObject samlReq =  moaRequest.getSamlRequest(); - -		if(!(samlReq instanceof AuthnRequest)) { -			throw new InvalidPVPRequestException("Unsupported request", new Object[] {}); -		} -				 -		EntityDescriptor metadata = moaRequest.getEntityMetadata(metadataProvider); -		if(metadata == null) { -			throw new NoMetadataInformationException(); -		} -		SPSSODescriptor spSSODescriptor = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); -		 -		AuthnRequest authnRequest = (AuthnRequest)samlReq; -		 -		if (authnRequest.getIssueInstant() == null) { -			log.warn("Unsupported request: No IssueInstant Attribute found."); -			throw new AuthnRequestValidatorException("pvp2.22",  -					new Object[] {"Unsupported request: No IssueInstant Attribute found"},  -					pendingReq); -			 -		} -		 -		if (authnRequest.getIssueInstant().minusMinutes(EAAFConstants.ALLOWED_TIME_JITTER).isAfterNow()) { -			log.warn("Unsupported request: No IssueInstant DateTime is not valid anymore."); -			throw new AuthnRequestValidatorException("pvp2.22",  -					new Object[] {"Unsupported request: No IssueInstant DateTime is not valid anymore."}, -					pendingReq); -			 -		} -			 -		//parse AssertionConsumerService -		AssertionConsumerService consumerService = null; -		if (StringUtils.isNotEmpty(authnRequest.getAssertionConsumerServiceURL()) &&  -				StringUtils.isNotEmpty(authnRequest.getProtocolBinding())) { -			//use AssertionConsumerServiceURL from request - -			//check requested AssertionConsumingService URL against metadata -			List<AssertionConsumerService> metadataAssertionServiceList = spSSODescriptor.getAssertionConsumerServices(); -			for (AssertionConsumerService service : metadataAssertionServiceList) { -				if (authnRequest.getProtocolBinding().equals(service.getBinding()) -						&& authnRequest.getAssertionConsumerServiceURL().equals(service.getLocation())) { -					consumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class); -					consumerService.setBinding(authnRequest.getProtocolBinding()); -					consumerService.setLocation(authnRequest.getAssertionConsumerServiceURL());					 -					log.debug("Requested AssertionConsumerServiceURL is valid."); -				}				 -			} -			 -			if (consumerService == null) {				 -				throw new InvalidAssertionConsumerServiceException(authnRequest.getAssertionConsumerServiceURL()); -				 -			} - - -		} else { -			//use AssertionConsumerServiceIndex and select consumerService from metadata -			Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); -			int assertionidx = 0; -		 -			if(aIdx != null) { -				assertionidx = aIdx.intValue(); -			 -			} else {				 -				assertionidx = SAML2Utils.getDefaultAssertionConsumerServiceIndex(spSSODescriptor); -				 -			}		 -			consumerService  = spSSODescriptor.getAssertionConsumerServices().get(assertionidx); -			 -			if (consumerService == null) {			 -				throw new InvalidAssertionConsumerServiceException(aIdx); -				 -			}			 -		} -		 -				 -		//validate AuthnRequest -		AuthnRequest authReq = (AuthnRequest) samlReq; -		String oaURL = moaRequest.getEntityMetadata(metadataProvider).getEntityID(); -		log.info("Dispatch PVP2 AuthnRequest: OAURL=" + oaURL + " Binding=" + consumerService.getBinding()); -								 -		pendingReq.setSPEntityId(StringEscapeUtils.escapeHtml(oaURL)); -		pendingReq.setOnlineApplicationConfiguration(authConfig.getServiceProviderConfiguration(pendingReq.getSPEntityId())); -		pendingReq.setBinding(consumerService.getBinding()); -		pendingReq.setRequest(moaRequest); -		pendingReq.setConsumerURL(consumerService.getLocation()); -		 -		//parse AuthRequest -		pendingReq.setPassiv(authReq.isPassive()); -		pendingReq.setForce(authReq.isForceAuthn()); - -		//AuthnRequest needs authentication -		pendingReq.setNeedAuthentication(true); - -		//set protocol action, which should be executed after authentication -		pendingReq.setAction(AuthenticationAction.class.getName()); -		 -		 // do post-processing if required -    log.trace("Starting extended AuthnRequest validation and processing ... "); -    if (authRequestPostProcessors != null) { -      for (final IAuthnRequestPostProcessor processor : authRequestPostProcessors) { -        log.trace("Post-process AuthnRequest with module: {}", processor.getClass().getSimpleName()); -        processor.process(request, pendingReq, authReq, spSSODescriptor); - -      } -    } -     -		log.debug("Extended AuthnRequest validation and processing finished"); -				 -		//write revisionslog entry -		revisionsLogger.logEvent(pendingReq, PVPEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST, authReq.getID()); -		 -	} -	 -	@PostConstruct -	private void verifyInitialization() { -		if (pvpIDPCredentials == null) { -			log.error("No SAML2 credentialProvider injected!"); -			throw new RuntimeException("No SAML2 credentialProvider injected!"); -			 -		}		 -	} -	 -} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java index 597d3c22..a56c8726 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java @@ -1,29 +1,22 @@ -/******************************************************************************* - * Copyright 2017 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 2017 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.modules.pvp2.idp.impl;  import java.util.List; @@ -32,518 +25,540 @@ import javax.annotation.PostConstruct;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse; -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; -import org.joda.time.DateTime; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; -import org.opensaml.saml2.core.Response; -import org.opensaml.saml2.core.Status; -import org.opensaml.saml2.core.StatusCode; -import org.opensaml.saml2.core.StatusMessage; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.ws.security.SecurityPolicyException; -import org.opensaml.xml.security.x509.X509Credential; -import org.opensaml.xml.signature.SignableXMLObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -  import at.gv.egiz.components.eventlog.api.EventConstants;  import at.gv.egiz.eaaf.core.api.IRequest; -import at.gv.egiz.eaaf.core.api.data.EAAFConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants;  import at.gv.egiz.eaaf.core.api.idp.IModulInfo;  import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger;  import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; +import at.gv.egiz.eaaf.core.exceptions.EaafException;  import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException;  import at.gv.egiz.eaaf.core.exceptions.NoPassivAuthenticationException; -import at.gv.egiz.eaaf.core.exceptions.SLOException; +import at.gv.egiz.eaaf.core.exceptions.SloException;  import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; -import at.gv.egiz.eaaf.modules.pvp2.PVPEventConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.IPVP2BasicConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.PvpEventConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.IPvp2BasicConfiguration;  import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.utils.IPvp2CredentialProvider;  import at.gv.egiz.eaaf.modules.pvp2.api.validation.IAuthnRequestPostProcessor; -import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPVPRequestException; -import at.gv.egiz.eaaf.modules.pvp2.exception.NameIDFormatNotSupportedException; +import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException; +import at.gv.egiz.eaaf.modules.pvp2.exception.NameIdFormatNotSupportedException;  import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException;  import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionConsumerServiceException;  import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding;  import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding;  import at.gv.egiz.eaaf.modules.pvp2.impl.binding.SoapBinding;  import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; -import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EAAFURICompare; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare;  import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; -import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SAMLVerificationEngine; -  -public abstract class AbstractPVP2XProtocol extends AbstractController implements IModulInfo { -	private static final Logger log = LoggerFactory.getLogger(AbstractPVP2XProtocol.class); -	 -	@Autowired(required=true) protected IPVP2BasicConfiguration pvpBasicConfiguration; -	@Autowired(required=true) protected IPVPMetadataProvider metadataProvider; -	@Autowired(required=true) protected SAMLVerificationEngine samlVerificationEngine; -	@Autowired(required=false) protected List<IAuthnRequestPostProcessor> authRequestPostProcessors; -	 -	private AbstractCredentialProvider pvpIDPCredentials; - -	 -		 -	/** -	 * Sets a specific credential provider for PVP S-Profile IDP component. -	 * @param pvpIDPCredentials credential provider -	 */ -	public void setPvpIDPCredentials(AbstractCredentialProvider pvpIDPCredentials) { -		this.pvpIDPCredentials = pvpIDPCredentials; -		 -	} -	 -	public boolean generateErrorMessage(Throwable e, -			HttpServletRequest request, HttpServletResponse response, -			IRequest protocolRequest) throws Throwable { -		 -		if(protocolRequest == null) { -			throw e; -		} -		 -		if(!(protocolRequest instanceof PVPSProfilePendingRequest) ) { -			throw e; -		} -		PVPSProfilePendingRequest pvpRequest = (PVPSProfilePendingRequest)protocolRequest; -		 -		Response samlResponse =  -				SAML2Utils.createSAMLObject(Response.class); -		Status status = SAML2Utils.createSAMLObject(Status.class); -		StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class); -		StatusMessage statusMessage = SAML2Utils.createSAMLObject(StatusMessage.class); -		 -		String moaError = null; -		 -		if(e instanceof NoPassivAuthenticationException) { -			statusCode.setValue(StatusCode.NO_PASSIVE_URI); -			statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage()));	 -			 -		} else if (e instanceof NameIDFormatNotSupportedException) { -			statusCode.setValue(StatusCode.INVALID_NAMEID_POLICY_URI); -			statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); -  -		} else if (e instanceof SLOException) { -			//SLOExecpetions only occurs if session information is lost -			return false; -			 -		} else if(e instanceof PVP2Exception) { -			PVP2Exception ex = (PVP2Exception) e; -			statusCode.setValue(ex.getStatusCodeValue()); -			String statusMessageValue = ex.getStatusMessageValue(); -			if(statusMessageValue != null) { -				statusMessage.setMessage(StringEscapeUtils.escapeXml(statusMessageValue)); -			}						 -			moaError = statusMessager.mapInternalErrorToExternalError(ex.getErrorId()); -			 -		} else { -			statusCode.setValue(StatusCode.RESPONDER_URI); -			statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); -			moaError = statusMessager.getResponseErrorCode(e); -		} -		 -		 -		if (StringUtils.isNotEmpty(moaError)) { -			StatusCode moaStatusCode = SAML2Utils.createSAMLObject(StatusCode.class); -			moaStatusCode.setValue(moaError); -			statusCode.setStatusCode(moaStatusCode); -		} -		 -		status.setStatusCode(statusCode); -		if(statusMessage.getMessage() != null) { -			status.setStatusMessage(statusMessage); -		} -		samlResponse.setStatus(status); -		String remoteSessionID = SAML2Utils.getSecureIdentifier(); -		samlResponse.setID(remoteSessionID); - -		samlResponse.setIssueInstant(new DateTime()); -		Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); -		nissuer.setValue(pvpBasicConfiguration.getIDPEntityId(pvpRequest.getAuthURL())); -		nissuer.setFormat(NameID.ENTITY); -		samlResponse.setIssuer(nissuer); -		 -		IEncoder encoder = null; -		 -		if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {			 -			encoder = applicationContext.getBean("PVPRedirectBinding", RedirectBinding.class); -						 -		} else if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI))  { -			encoder = applicationContext.getBean("PVPPOSTBinding", PostBinding.class); -			 -		} else if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI))  { -			encoder = applicationContext.getBean("PVPSOAPBinding", SoapBinding.class); -		} - -		if(encoder == null) { -			// default to redirect binding -			encoder = new RedirectBinding(); -		} - -		String relayState = null; -		if (pvpRequest.getRequest() != null) -			relayState = pvpRequest.getRequest().getRelayState(); -		 -		X509Credential signCred = pvpIDPCredentials.getIDPAssertionSigningCredential(); -		 -		encoder.encodeRespone(request, response, samlResponse, pvpRequest.getConsumerURL(),  -				relayState, signCred, protocolRequest); -		return true; -	} - -	public boolean validate(HttpServletRequest request, -			HttpServletResponse response, IRequest pending) { -		 -		return true; -	} -		 -	protected void pvpMetadataRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException {		 -		//create pendingRequest object -		PVPSProfilePendingRequest pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class); -		pendingReq.initialize(req, authConfig); -		pendingReq.setModule(getName()); -		 -		revisionsLogger.logEvent( -				pendingReq.getUniqueSessionIdentifier(),  -				pendingReq.getUniqueTransactionIdentifier(),  -				EventConstants.TRANSACTION_IP,  -				req.getRemoteAddr()); -				 -		MetadataAction metadataAction = applicationContext.getBean(MetadataAction.class); -		metadataAction.processRequest(pendingReq,  -				req, resp, null); -		 -	} -	 -	protected void PVPIDPPostRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException {		 -		PVPSProfilePendingRequest pendingReq = null; -		 -		try { -			//create pendingRequest object -			pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class); -			pendingReq.initialize(req, authConfig); -			pendingReq.setModule(getName()); -			 -			revisionsLogger.logEvent(EventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier()); -			revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier());						 -			revisionsLogger.logEvent( -					pendingReq.getUniqueSessionIdentifier(),  -					pendingReq.getUniqueTransactionIdentifier(),  -					EventConstants.TRANSACTION_IP,  -					req.getRemoteAddr()); -			 -			//get POST-Binding decoder implementation -			InboundMessage msg = (InboundMessage) new PostBinding().decode( -					req, resp, metadataProvider, false, -					new EAAFURICompare(pvpBasicConfiguration.getIDPSSOPostService(pendingReq.getAuthURL()))); -			pendingReq.setRequest(msg); -						 -			//preProcess Message -			preProcess(req, resp, pendingReq); -						 -		} catch (SecurityPolicyException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); -			 -		} catch (SecurityException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); -		 -		} catch (EAAFException e) { -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw e; -			 -		} catch (Throwable e) {			 -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); - -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new EAAFException("pvp2.24", new Object[] {e.getMessage()}, e); -		}					 -	} -	 -	protected void PVPIDPRedirecttRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException { -		PVPSProfilePendingRequest pendingReq = null; -		try { -			//create pendingRequest object -			pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class); -			pendingReq.initialize(req, authConfig); -			pendingReq.setModule(getName()); -			 -			revisionsLogger.logEvent(EventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier()); -			revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier());						 -			revisionsLogger.logEvent( -					pendingReq.getUniqueSessionIdentifier(),  -					pendingReq.getUniqueTransactionIdentifier(),  -					EventConstants.TRANSACTION_IP,  -					req.getRemoteAddr()); -			 -			//get POST-Binding decoder implementation -			InboundMessage msg = (InboundMessage) new RedirectBinding().decode( -					req, resp, metadataProvider, false, -					new EAAFURICompare(pvpBasicConfiguration.getIDPSSORedirectService(pendingReq.getAuthURL()))); -			pendingReq.setRequest(msg); -			 -			//preProcess Message -			preProcess(req, resp, pendingReq); -						 -		} catch (SecurityPolicyException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); -			 -		} catch (SecurityException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); -			 -		} catch (EAAFException e) { -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.info("Receive INVALID protocol request: " + samlRequest); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -			 -			throw e; -						 -		} catch (Throwable e) {			 -			String samlRequest = req.getParameter("SAMLRequest");			 -			log.warn("Receive INVALID protocol request: " + samlRequest, e); -			 -			//write revision log entries -			if (pendingReq != null) -				revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); -						 -			throw new EAAFException("pvp2.24", new Object[] {e.getMessage()}, e); -		}					 -	} -	 -	 -	 -	/** -	 *  -	 *  -	 * @param request -	 * @param response -	 * @param msg -	 * @return true if preprocess can handle this request type, otherwise false -	 * @throws Throwable -	 */ -	abstract protected boolean childPreProcess(HttpServletRequest request, -			HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable; -	 -	protected void preProcess(HttpServletRequest request, -			HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable { -			 -			InboundMessage msg = pendingReq.getRequest(); -		 -			if (StringUtils.isEmpty(msg.getEntityID())) { -				throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}); -				 -			} -			 -			if(!msg.isVerified()) { -				samlVerificationEngine.verify(msg,  -						TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); -				msg.setVerified(true); -								 -			} -			 -			revisionsLogger.logEvent(pendingReq, IRevisionLogger.AUTHPROTOCOL_TYPE, getAuthProtocolIdentifier()); -			 -			if (msg instanceof PVPSProfileRequest &&  -					((PVPSProfileRequest)msg).getSamlRequest() instanceof AuthnRequest) -				preProcessAuthRequest(request, response, pendingReq); - -			else if (childPreProcess(request, response, pendingReq)) -				log.debug("Find protocol handler in child implementation"); -				 -			else { -				log.error("Receive unsupported PVP21 message of type: " + ((PVPSProfileRequest)msg).getSamlRequest().getClass().getName()); -				throw new InvalidPVPRequestException("pvp2.09",  -						new Object[] {((PVPSProfileRequest)msg).getSamlRequest().getClass().getName()}); -			} -							 -			 -			 -			//switch to session authentication -			protAuthService.performAuthentication(request, response, pendingReq);								 -	} - -	 -	/** -	 * PreProcess Authn request -	 * @param request -	 * @param response -	 * @param pendingReq -	 * @throws Throwable -	 */ -	private void preProcessAuthRequest(HttpServletRequest request, -			HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable { - -		PVPSProfileRequest moaRequest = ((PVPSProfileRequest)pendingReq.getRequest());		 -		SignableXMLObject samlReq =  moaRequest.getSamlRequest(); - -		if(!(samlReq instanceof AuthnRequest)) { -			throw new InvalidPVPRequestException("Unsupported request", new Object[] {}); -		} -				 -		EntityDescriptor metadata = moaRequest.getEntityMetadata(metadataProvider); -		if(metadata == null) { -			throw new NoMetadataInformationException(); -		} -		SPSSODescriptor spSSODescriptor = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); -		 -		AuthnRequest authnRequest = (AuthnRequest)samlReq; -		 -		if (authnRequest.getIssueInstant() == null) { -			log.warn("Unsupported request: No IssueInstant Attribute found."); -			throw new AuthnRequestValidatorException("pvp2.22",  -					new Object[] {"Unsupported request: No IssueInstant Attribute found"},  -					pendingReq); -			 -		} -		 -		if (authnRequest.getIssueInstant().minusMinutes(EAAFConstants.ALLOWED_TIME_JITTER).isAfterNow()) { -			log.warn("Unsupported request: No IssueInstant DateTime is not valid anymore."); -			throw new AuthnRequestValidatorException("pvp2.22",  -					new Object[] {"Unsupported request: No IssueInstant DateTime is not valid anymore."}, -					pendingReq); -			 -		} -			 -		//parse AssertionConsumerService -		AssertionConsumerService consumerService = null; -		if (StringUtils.isNotEmpty(authnRequest.getAssertionConsumerServiceURL()) &&  -				StringUtils.isNotEmpty(authnRequest.getProtocolBinding())) { -			//use AssertionConsumerServiceURL from request - -			//check requested AssertionConsumingService URL against metadata -			List<AssertionConsumerService> metadataAssertionServiceList = spSSODescriptor.getAssertionConsumerServices(); -			for (AssertionConsumerService service : metadataAssertionServiceList) { -				if (authnRequest.getProtocolBinding().equals(service.getBinding()) -						&& authnRequest.getAssertionConsumerServiceURL().equals(service.getLocation())) { -					consumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class); -					consumerService.setBinding(authnRequest.getProtocolBinding()); -					consumerService.setLocation(authnRequest.getAssertionConsumerServiceURL());					 -					log.debug("Requested AssertionConsumerServiceURL is valid."); -				}				 -			} -			 -			if (consumerService == null) {				 -				throw new InvalidAssertionConsumerServiceException(authnRequest.getAssertionConsumerServiceURL()); -				 -			} - - -		} else { -			//use AssertionConsumerServiceIndex and select consumerService from metadata -			Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); -			int assertionidx = 0; -		 -			if(aIdx != null) { -				assertionidx = aIdx.intValue(); -			 -			} else {				 -				assertionidx = SAML2Utils.getDefaultAssertionConsumerServiceIndex(spSSODescriptor); -				 -			}		 -			consumerService  = spSSODescriptor.getAssertionConsumerServices().get(assertionidx); -			 -			if (consumerService == null) {			 -				throw new InvalidAssertionConsumerServiceException(aIdx); -				 -			}			 -		} -		 -				 -		//validate AuthnRequest -		AuthnRequest authReq = (AuthnRequest) samlReq; -		String oaURL = moaRequest.getEntityMetadata(metadataProvider).getEntityID(); -		log.info("Dispatch PVP2 AuthnRequest: OAURL=" + oaURL + " Binding=" + consumerService.getBinding()); -								 -		pendingReq.setSPEntityId(StringEscapeUtils.escapeHtml(oaURL)); -		pendingReq.setOnlineApplicationConfiguration(authConfig.getServiceProviderConfiguration(pendingReq.getSPEntityId())); -		pendingReq.setBinding(consumerService.getBinding()); -		pendingReq.setRequest(moaRequest); -		pendingReq.setConsumerURL(consumerService.getLocation()); -		 -		//parse AuthRequest -		pendingReq.setPassiv(authReq.isPassive()); -		pendingReq.setForce(authReq.isForceAuthn()); - -		//AuthnRequest needs authentication -		pendingReq.setNeedAuthentication(true); - -		//set protocol action, which should be executed after authentication -		pendingReq.setAction(AuthenticationAction.class.getName()); -		 -		 // do post-processing if required +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SamlVerificationEngine; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.Issuer; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.core.Status; +import org.opensaml.saml.saml2.core.StatusCode; +import org.opensaml.saml.saml2.core.StatusMessage; +import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.opensaml.xmlsec.signature.SignableXMLObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class AbstractPvp2XProtocol extends AbstractController implements IModulInfo { +  private static final Logger log = LoggerFactory.getLogger(AbstractPvp2XProtocol.class); + +  private static final String HTTP_PARAM_SAMLREQ = "SAMLRequest"; +  private static final String ERROR_INVALID_REQUEST = "Receive INVALID protocol request: {}"; + +  @Autowired(required = true) +  protected IPvp2BasicConfiguration pvpBasicConfiguration; +  @Autowired(required = true) +  protected IPvp2MetadataProvider metadataProvider; +  @Autowired(required = true) +  protected SamlVerificationEngine samlVerificationEngine; +  @Autowired(required = false) +  protected List<IAuthnRequestPostProcessor> authRequestPostProcessors; + +  private IPvp2CredentialProvider pvpIdpCredentials; + +  /** +   * Sets a specific credential provider for PVP S-Profile IDP component. +   * +   * @param pvpIdpCredentials credential provider +   */ +  public void setPvpIdpCredentials(final IPvp2CredentialProvider pvpIdpCredentials) { +    this.pvpIdpCredentials = pvpIdpCredentials; + +  } + +  @Override +  public boolean generateErrorMessage(final Throwable e, final HttpServletRequest request, +      final HttpServletResponse response, final IRequest protocolRequest) throws Throwable { + +    if (protocolRequest == null) { +      throw e; +    } + +    if (!(protocolRequest instanceof PvpSProfilePendingRequest)) { +      throw e; +    } +    final PvpSProfilePendingRequest pvpRequest = (PvpSProfilePendingRequest) protocolRequest; + +    final Response samlResponse = Saml2Utils.createSamlObject(Response.class); +    final Status status = Saml2Utils.createSamlObject(Status.class); +    final StatusCode statusCode = Saml2Utils.createSamlObject(StatusCode.class); +    final StatusMessage statusMessage = Saml2Utils.createSamlObject(StatusMessage.class); + +    String moaError = null; + +    if (e instanceof NoPassivAuthenticationException) { +      statusCode.setValue(StatusCode.NO_PASSIVE); +      statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); + +    } else if (e instanceof NameIdFormatNotSupportedException) { +      statusCode.setValue(StatusCode.INVALID_NAMEID_POLICY); +      statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); + +    } else if (e instanceof SloException) { +      // SLOExecpetions only occurs if session information is lost +      return false; + +    } else if (e instanceof Pvp2Exception) { +      final Pvp2Exception ex = (Pvp2Exception) e; +      statusCode.setValue(ex.getStatusCodeValue()); +      final String statusMessageValue = ex.getStatusMessageValue(); +      if (statusMessageValue != null) { +        statusMessage.setMessage(StringEscapeUtils.escapeXml(statusMessageValue)); +      } +      moaError = statusMessager.mapInternalErrorToExternalError(ex.getErrorId()); + +    } else { +      statusCode.setValue(StatusCode.RESPONDER); +      statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); +      moaError = statusMessager.getResponseErrorCode(e); +    } + +    if (StringUtils.isNotEmpty(moaError)) { +      final StatusCode moaStatusCode = Saml2Utils.createSamlObject(StatusCode.class); +      moaStatusCode.setValue(moaError); +      statusCode.setStatusCode(moaStatusCode); +    } + +    status.setStatusCode(statusCode); +    if (statusMessage.getMessage() != null) { +      status.setStatusMessage(statusMessage); +    } +    samlResponse.setStatus(status); +    final String remoteSessionID = Saml2Utils.getSecureIdentifier(); +    samlResponse.setID(remoteSessionID); + +    samlResponse.setIssueInstant(new DateTime()); +    final Issuer nissuer = Saml2Utils.createSamlObject(Issuer.class); +    nissuer.setValue(pvpBasicConfiguration.getIdpEntityId(pvpRequest.getAuthUrl())); +    nissuer.setFormat(NameIDType.ENTITY); +    samlResponse.setIssuer(nissuer); + +    IEncoder encoder = null; + +    if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { +      encoder = applicationContext.getBean("PVPRedirectBinding", RedirectBinding.class); + +    } else if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { +      encoder = applicationContext.getBean("PVPPOSTBinding", PostBinding.class); + +    } else if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) { +      encoder = applicationContext.getBean("PVPSOAPBinding", SoapBinding.class); +    } + +    if (encoder == null) { +      // default to redirect binding +      encoder = new RedirectBinding(); +    } + +    String relayState = null; +    if (pvpRequest.getRequest() != null) { +      relayState = pvpRequest.getRequest().getRelayState(); +    } + +    final EaafX509Credential signCred = pvpIdpCredentials.getMessageSigningCredential(); + +    encoder.encodeResponse(request, response, samlResponse, pvpRequest.getConsumerUrl(), relayState, +        signCred, protocolRequest); +    return true; +  } + +  @Override +  public boolean validate(final HttpServletRequest request, final HttpServletResponse response, +      final IRequest pending) { + +    return true; +  } + +  protected void pvpMetadataRequest(final HttpServletRequest req, final HttpServletResponse resp) +      throws EaafException { +    // create pendingRequest object +    final PvpSProfilePendingRequest pendingReq = +        applicationContext.getBean(PvpSProfilePendingRequest.class); +    pendingReq.initialize(req, authConfig); +    pendingReq.setModule(getName()); + +    revisionsLogger.logEvent(pendingReq.getUniqueSessionIdentifier(), +        pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP, +        req.getRemoteAddr()); + +    final MetadataAction metadataAction = applicationContext.getBean(MetadataAction.class); +    metadataAction.processRequest(pendingReq, req, resp, null); + +  } + +  protected void pvpIdpPostRequest(final HttpServletRequest req, final HttpServletResponse resp) +      throws EaafException { +    PvpSProfilePendingRequest pendingReq = null; + +    try { +      // create pendingRequest object +      pendingReq = applicationContext.getBean(PvpSProfilePendingRequest.class); +      pendingReq.initialize(req, authConfig); +      pendingReq.setModule(getName()); + +      revisionsLogger.logEvent(EventConstants.SESSION_CREATED, +          pendingReq.getUniqueSessionIdentifier()); +      revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, +          pendingReq.getUniqueTransactionIdentifier()); +      revisionsLogger.logEvent(pendingReq.getUniqueSessionIdentifier(), +          pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP, +          req.getRemoteAddr()); + +      // get POST-Binding decoder implementation +      final InboundMessage msg = (InboundMessage) new PostBinding().decode(req, resp, +          metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, +          new EaafUriCompare(pvpBasicConfiguration.getIdpSsoPostService(pendingReq.getAuthUrl()))); +      pendingReq.setRequest(msg); + +      // preProcess Message +      preProcess(req, resp, pendingReq); + +    } catch (final SamlSigningException e) { +      final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); +      log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); + +      // write revision log entries +      if (pendingReq != null) { +        revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, +            pendingReq.getUniqueTransactionIdentifier()); +      } + +      throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + +    } catch (final Pvp2Exception e) { +      final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); +      log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); + +      // write revision log entries +      if (pendingReq != null) { +        revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, +            pendingReq.getUniqueTransactionIdentifier()); +      } + +      throw new InvalidProtocolRequestException("pvp2.22", new Object[] { e.getMessage() }); + +    } catch (final EaafException e) { + +      // write revision log entries +      if (pendingReq != null) { +        revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, +            pendingReq.getUniqueTransactionIdentifier()); +      } + +      throw e; + +    } catch (final Throwable e) { +      final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); +      log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); + +      // write revision log entries +      if (pendingReq != null) { +        revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, +            pendingReq.getUniqueTransactionIdentifier()); +      } + +      throw new EaafException("pvp2.24", new Object[] { e.getMessage() }, e); +    } +  } + +  protected void pvpIdpRedirecttRequest(final HttpServletRequest req, +      final HttpServletResponse resp) throws EaafException { +    PvpSProfilePendingRequest pendingReq = null; +    try { +      // create pendingRequest object +      pendingReq = applicationContext.getBean(PvpSProfilePendingRequest.class); +      pendingReq.initialize(req, authConfig); +      pendingReq.setModule(getName()); + +      revisionsLogger.logEvent(EventConstants.SESSION_CREATED, +          pendingReq.getUniqueSessionIdentifier()); +      revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, +          pendingReq.getUniqueTransactionIdentifier()); +      revisionsLogger.logEvent(pendingReq.getUniqueSessionIdentifier(), +          pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP, +          req.getRemoteAddr()); + +      // get POST-Binding decoder implementation +      final InboundMessage msg = (InboundMessage) new RedirectBinding().decode(req, resp, +          metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, new EaafUriCompare( +              pvpBasicConfiguration.getIdpSsoRedirectService(pendingReq.getAuthUrl()))); +      pendingReq.setRequest(msg); + +      // preProcess Message +      preProcess(req, resp, pendingReq); + +    } catch (final SamlSigningException e) { +      final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); +      log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); + +      // write revision log entries +      if (pendingReq != null) { +        revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, +            pendingReq.getUniqueTransactionIdentifier()); +      } + +      throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + +    } catch (final Pvp2Exception e) { +      final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); +      log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); + +      // write revision log entries +      if (pendingReq != null) { +        revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, +            pendingReq.getUniqueTransactionIdentifier()); +      } + +      throw new InvalidProtocolRequestException("pvp2.22", new Object[] { e.getMessage() }); + +    } catch (final EaafException e) { +      final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); +      log.info(ERROR_INVALID_REQUEST, samlRequest, null, e); + +      // write revision log entries +      if (pendingReq != null) { +        revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, +            pendingReq.getUniqueTransactionIdentifier()); +      } + +      throw e; + +    } catch (final Throwable e) { +      final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); +      log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); + +      // write revision log entries +      if (pendingReq != null) { +        revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, +            pendingReq.getUniqueTransactionIdentifier()); +      } + +      throw new EaafException("pvp2.24", new Object[] { e.getMessage() }, e); +    } +  } + +  /** +   * Authentication request pre-processor. +   * +   * @param request    http request +   * @param response   http response +   * @param pendingReq current pending request +   * @return true if preprocess can handle this request type, otherwise false +   * @throws Throwable In case of an error +   */ +  protected abstract boolean childPreProcess(HttpServletRequest request, +      HttpServletResponse response, PvpSProfilePendingRequest pendingReq) throws Throwable; + +  protected void preProcess(final HttpServletRequest request, final HttpServletResponse response, +      final PvpSProfilePendingRequest pendingReq) throws Throwable { + +    final InboundMessage msg = pendingReq.getRequest(); + +    if (StringUtils.isEmpty(msg.getEntityID())) { +      throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}); + +    } + +    if (!msg.isVerified()) { +      samlVerificationEngine.verify(msg, +          TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); +      msg.setVerified(true); + +    } + +    revisionsLogger.logEvent(pendingReq, IRevisionLogger.AUTHPROTOCOL_TYPE, +        getAuthProtocolIdentifier()); + +    if (msg instanceof PvpSProfileRequest +        && ((PvpSProfileRequest) msg).getSamlRequest() instanceof AuthnRequest) { +      preProcessAuthRequest(request, pendingReq); +    } else if (childPreProcess(request, response, pendingReq)) { +      log.debug("Find protocol handler in child implementation"); +    } else { +      log.error("Receive unsupported PVP21 message of type: " +          + ((PvpSProfileRequest) msg).getSamlRequest().getClass().getName()); +      throw new InvalidPvpRequestException("pvp2.09", +          new Object[] { ((PvpSProfileRequest) msg).getSamlRequest().getClass().getName() }); +    } + +    // switch to session authentication +    protAuthService.performAuthentication(request, response, pendingReq); +  } + +  /** +   * PreProcess Authn request. +   * +   * @param request    http request +   * @param pendingReq current pending request +   * @throws Throwable in case of an error +   */ +  protected void preProcessAuthRequest(final HttpServletRequest request, +      final PvpSProfilePendingRequest pendingReq) +      throws Throwable { + +    final PvpSProfileRequest moaRequest = (PvpSProfileRequest) pendingReq.getRequest(); +    final SignableXMLObject samlReq = moaRequest.getSamlRequest(); + +    if (!(samlReq instanceof AuthnRequest)) { +      throw new InvalidPvpRequestException("Unsupported request", new Object[] {}); +    } + +    final EntityDescriptor metadata = moaRequest.getEntityMetadata(metadataProvider); +    if (metadata == null) { +      throw new NoMetadataInformationException(); +    } +    final SPSSODescriptor spSsoDescriptor = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); + +    final AuthnRequest authnRequest = (AuthnRequest) samlReq; + +    if (authnRequest.getIssueInstant() == null) { +      log.warn("Unsupported request: No IssueInstant Attribute found."); +      throw new AuthnRequestValidatorException("pvp2.22", +          new Object[] { "Unsupported request: No IssueInstant Attribute found" }, pendingReq); + +    } + +    if (authnRequest.getIssueInstant().minusMinutes(EaafConstants.ALLOWED_TIME_JITTER) +        .isAfterNow()) { +      log.warn("Unsupported request: No IssueInstant DateTime is not valid anymore."); +      throw new AuthnRequestValidatorException("pvp2.22", +          new Object[] { "Unsupported request: No IssueInstant DateTime is not valid anymore." }, +          pendingReq); + +    } + +    // parse AssertionConsumerService +    AssertionConsumerService consumerService = null; +    if (StringUtils.isNotEmpty(authnRequest.getAssertionConsumerServiceURL()) +        && StringUtils.isNotEmpty(authnRequest.getProtocolBinding())) { +      // use AssertionConsumerServiceURL from request + +      // check requested AssertionConsumingService URL against metadata +      final List<AssertionConsumerService> metadataAssertionServiceList = +          spSsoDescriptor.getAssertionConsumerServices(); +      for (final AssertionConsumerService service : metadataAssertionServiceList) { +        if (authnRequest.getProtocolBinding().equals(service.getBinding()) +            && authnRequest.getAssertionConsumerServiceURL().equals(service.getLocation())) { +          consumerService = Saml2Utils.createSamlObject(AssertionConsumerService.class); +          consumerService.setBinding(authnRequest.getProtocolBinding()); +          consumerService.setLocation(authnRequest.getAssertionConsumerServiceURL()); +          log.debug("Requested AssertionConsumerServiceURL is valid."); +        } +      } + +      if (consumerService == null) { +        throw new InvalidAssertionConsumerServiceException( +            authnRequest.getAssertionConsumerServiceURL()); + +      } + +    } else { +      // use AssertionConsumerServiceIndex and select consumerService from metadata +      final Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); +      int assertionidx = 0; + +      if (aIdx != null) { +        assertionidx = aIdx; + +      } else { +        assertionidx = Saml2Utils.getDefaultAssertionConsumerServiceIndex(spSsoDescriptor); + +      } +      consumerService = spSsoDescriptor.getAssertionConsumerServices().get(assertionidx); + +      if (consumerService == null) { +        throw new InvalidAssertionConsumerServiceException(aIdx); + +      } +    } + +    // validate AuthnRequest +    final AuthnRequest authReq = (AuthnRequest) samlReq; +    final String oaUrl = moaRequest.getEntityMetadata(metadataProvider).getEntityID(); +    log.info( +        "Dispatch PVP2 AuthnRequest: OAURL=" + oaUrl + " Binding=" + consumerService.getBinding()); + +    pendingReq.setSpEntityId(StringEscapeUtils.escapeHtml(oaUrl)); +    pendingReq.setOnlineApplicationConfiguration( +        authConfig.getServiceProviderConfiguration(pendingReq.getSpEntityId())); +    pendingReq.setBinding(consumerService.getBinding()); +    pendingReq.setRequest(moaRequest); +    pendingReq.setConsumerUrl(consumerService.getLocation()); + +    // parse AuthRequest +    pendingReq.setPassiv(authReq.isPassive()); +    pendingReq.setForce(authReq.isForceAuthn()); + +    // AuthnRequest needs authentication +    pendingReq.setNeedAuthentication(true); + +    // set protocol action, which should be executed after authentication +    pendingReq.setAction(AuthenticationAction.class.getName()); + +    // do post-processing if required      log.trace("Starting extended AuthnRequest validation and processing ... ");      if (authRequestPostProcessors != null) {        for (final IAuthnRequestPostProcessor processor : authRequestPostProcessors) {          log.trace("Post-process AuthnRequest with module: {}", processor.getClass().getSimpleName()); -        processor.process(request, pendingReq, authReq, spSSODescriptor); +        processor.process(request, pendingReq, authReq, spSsoDescriptor);        }      } -     -		log.debug("Extended AuthnRequest validation and processing finished"); -				 -		//write revisionslog entry -		revisionsLogger.logEvent(pendingReq, PVPEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST, authReq.getID()); -		 -	} -	 -	@PostConstruct -	private void verifyInitialization() { -		if (pvpIDPCredentials == null) { -			log.error("No SAML2 credentialProvider injected!"); -			throw new RuntimeException("No SAML2 credentialProvider injected!"); -			 -		}		 -	} -	 + +    log.debug("Extended AuthnRequest validation and processing finished"); + +    // write revisionslog entry +    revisionsLogger.logEvent(pendingReq, PvpEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST, +        authReq.getID()); + +  } + +  @PostConstruct +  private void verifyInitialization() { +    if (pvpIdpCredentials == null) { +      log.error("No SAML2 credentialProvider injected!"); +      throw new RuntimeException("No SAML2 credentialProvider injected!"); + +    } +  } +  } | 
