diff options
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_idp/src')
18 files changed, 1706 insertions, 0 deletions
| diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/META-INF/MANIFEST.MF b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 00000000..254272e1 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path:  + diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java new file mode 100644 index 00000000..7a9ac92b --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java @@ -0,0 +1,30 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import at.gv.egiz.components.spring.api.SpringResourceProvider; + +public class PVP2SProfileIDPSpringResourceProvider implements SpringResourceProvider { + +	@Override +	public String getName() { +		return "EAAF PVP2 S-Profile IDP SpringResourceProvider"; +	} + +	@Override +	public String[] getPackagesToScan() { +		// TODO Auto-generated method stub +		return null; +	} + +	@Override +	public Resource[] getResourcesToLoad() { +		ClassPathResource sl20AuthConfig = new ClassPathResource("/eaaf_pvp_idp.beans.xml", PVP2SProfileIDPSpringResourceProvider.class);					 +		 +		return new Resource[] {sl20AuthConfig}; +	} + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java new file mode 100644 index 00000000..ac999ffc --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java @@ -0,0 +1,21 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.api.builder; + +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +public interface ISubjectNameIdGenerator { + +	/** +	 * Generates a SAML2 subjectNameId from authentication data +	 *  +	 * @param authData Authentication data for the current pending request +	 * @param spConfig Service provider configuration +	 * @return Pair of subjectNameId and NameIdFormat +	 * @throws PVP2Exception +	 */ +	public Pair<String, String> generateSubjectNameId(IAuthData authData, ISPConfiguration spConfig) throws PVP2Exception; +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java new file mode 100644 index 00000000..d9ffa2f2 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java @@ -0,0 +1,30 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.exception; + +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +public class InvalidAssertionConsumerServiceException extends PVP2Exception { + +	public InvalidAssertionConsumerServiceException(int idx) { +		super("pvp2.00", new Object[]{idx}); +		this.statusCodeValue = StatusCode.REQUESTER_URI; +	} + +	/** +	 *   +	 */ +	public InvalidAssertionConsumerServiceException(String wrongURL) { +		super("pvp2.23", new Object[]{wrongURL}); +		this.statusCodeValue = StatusCode.REQUESTER_URI; +		 +	} + +	/** +	 *  +	 */ +	private static final long serialVersionUID = 7861790149343943091L; + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java new file mode 100644 index 00000000..d0b6feb9 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java @@ -0,0 +1,18 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.exception; + +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +public class InvalidAssertionEncryptionException extends PVP2Exception { + +	private static final long serialVersionUID = 6513388841485355549L; + +	public InvalidAssertionEncryptionException() { +		super("pvp2.16", new Object[]{}); +		this.statusCodeValue = StatusCode.RESPONDER_URI; +	} + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java new file mode 100644 index 00000000..5abd6dbe --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java @@ -0,0 +1,21 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.exception; + +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +public class RequestDeniedException extends PVP2Exception { + +	public RequestDeniedException() { +		super("pvp2.14", null); +		this.statusCodeValue = StatusCode.REQUEST_DENIED_URI; +	} + +	/** +	 *  +	 */ +	private static final long serialVersionUID = 4415896615794730553L; + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java new file mode 100644 index 00000000..f7145458 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java @@ -0,0 +1,26 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.exception; + +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +public class ResponderErrorException extends PVP2Exception { + +	/** +	 *  +	 */ +	private static final long serialVersionUID = -425416760138285446L; + +	public ResponderErrorException(String messageId, Object[] parameters, +			Throwable wrapped) { +		super(messageId, parameters, wrapped); +		this.statusCodeValue = StatusCode.RESPONDER_URI; +	} +	 +	public ResponderErrorException(String messageId, Object[] parameters) { +		super(messageId, parameters); +		this.statusCodeValue = StatusCode.RESPONDER_URI; +	} +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java new file mode 100644 index 00000000..364fdbf0 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java @@ -0,0 +1,26 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.exception; + +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +public class SAMLRequestNotSignedException extends PVP2Exception { + +	public SAMLRequestNotSignedException() { +		super("pvp2.07", null); +		this.statusCodeValue = StatusCode.REQUESTER_URI; +	} +	 +	public SAMLRequestNotSignedException(Throwable e) { +		super("pvp2.07", null, e); +		this.statusCodeValue = StatusCode.REQUESTER_URI; +	} + +	/** +	 *  +	 */ +	private static final long serialVersionUID = 1L; + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java new file mode 100644 index 00000000..b370a7be --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java @@ -0,0 +1,22 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.exception; + +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + + +public class SAMLRequestNotSupported extends PVP2Exception { + +	public SAMLRequestNotSupported() { +		super("pvp2.09", null); +		this.statusCodeValue = StatusCode.REQUEST_UNSUPPORTED_URI; +	} + +	/** +	 *  +	 */ +	private static final long serialVersionUID = 1244883178458802767L; + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java new file mode 100644 index 00000000..5dea922c --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java @@ -0,0 +1,19 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.exception; + +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +public class UnprovideableAttributeException extends PVP2Exception { +	/** +	 *  +	 */ +	private static final long serialVersionUID = 3972197758163647157L; + +	public UnprovideableAttributeException(String attributeName) { +		super("pvp2.10", new Object[] {attributeName}); +		this.statusCodeValue = StatusCode.UNKNOWN_ATTR_PROFILE_URI; +	} +} 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 new file mode 100644 index 00000000..93ffa789 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java @@ -0,0 +1,537 @@ +/******************************************************************************* + *******************************************************************************/ +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.core.impl.AuthnRequestImpl; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.AttributeConsumingService; +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.idp.ISPConfiguration; +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.AbstractAuthProtocolModulController; +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.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.AuthnRequestValidator; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SAMLVerificationEngine; +  +public abstract class AbstractPVP2XProtocol extends AbstractAuthProtocolModulController 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; +	 +	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[] {}, e.getMessage()); +			 +		} 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()}, 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.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[] {}, e.getMessage()); +			 +		} 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()}, 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.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[] {}, "EntityId is null or empty"); +				 +			} +			 +			if(!msg.isVerified()) { +				samlVerificationEngine.verify(msg,  +						TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); +				msg.setVerified(true); +								 +			} +				 +			 +			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"); +				throw new InvalidPVPRequestException("Unsupported PVP21 message", new Object[] {}); +			} +							 +			revisionsLogger.logEvent(pendingReq, IRevisionLogger.AUTHPROTOCOL_TYPE, getAuthProtocolIdentifier()); +			 +			//switch to session authentication +			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("Unsupported request: No IssueInstant Attribute found.", 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("Unsupported request: No IssueInstant DateTime is not valid anymore.", 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); +				 +			}			 +		} +		 +		 +		//select AttributeConsumingService from request +		AttributeConsumingService attributeConsumer = null;		 +		Integer aIdx = authnRequest.getAttributeConsumingServiceIndex(); +		int attributeIdx = 0; +	 +		if(aIdx != null) { +			attributeIdx = aIdx.intValue(); +		} +		 +		if (spSSODescriptor.getAttributeConsumingServices() != null  &&  +				spSSODescriptor.getAttributeConsumingServices().size() > 0) { +			attributeConsumer  = spSSODescriptor.getAttributeConsumingServices().get(attributeIdx); +		}  +		 +		//validate AuthnRequest +		AuthnRequestImpl authReq = (AuthnRequestImpl) samlReq; +		AuthnRequestValidator.validate(authReq); +		 +//		String useMandate = request.getParameter(PARAM_USEMANDATE); +//		if(useMandate != null) { +//			if(useMandate.equals("true") && attributeConsumer != null) { +//				if(!CheckMandateAttributes.canHandleMandate(attributeConsumer)) { +//					throw new MandateAttributesNotHandleAbleException(); +//				} +//			} +//		} +						 +		String oaURL = moaRequest.getEntityMetadata(metadataProvider).getEntityID(); +		oaURL = StringEscapeUtils.escapeHtml(oaURL); +		ISPConfiguration oa = authConfig.getServiceProviderConfiguration(oaURL); +		 +		log.info("Dispatch PVP2 AuthnRequest: OAURL=" + oaURL + " Binding=" + consumerService.getBinding());		 + +		pendingReq.setSPEntityId(oaURL); +		pendingReq.setOnlineApplicationConfiguration(oa); +		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()); +		 +		//write revisionslog entry +		revisionsLogger.logEvent(pendingReq, PVPEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST); +		 +	} +	 +	@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/AuthenticationAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java new file mode 100644 index 00000000..adcff465 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java @@ -0,0 +1,154 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.impl; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.joda.time.DateTime; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.xml.security.SecurityException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; + +import at.gv.egiz.eaaf.core.api.IRequest; +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.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface; +import at.gv.egiz.eaaf.core.exceptions.EAAFException; +import at.gv.egiz.eaaf.core.impl.data.SLOInformationImpl; +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.exception.BindingNotSupportedException; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException; +import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.AuthResponseBuilder; +import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.PVP2AssertionBuilder; +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.message.PVPSProfileRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; + +@Service("PVPAuthenticationRequestAction") +public class AuthenticationAction implements IAction { +	private static final Logger log = LoggerFactory.getLogger(AuthenticationAction.class); +	 +	private static final String CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION = "protocols.pvp2.assertion.encryption.active"; +	 +	@Autowired(required=true) private IPVPMetadataProvider metadataProvider; +	@Autowired(required=true) ApplicationContext springContext; +	@Autowired(required=true) IConfiguration authConfig; +	@Autowired(required=true) PVP2AssertionBuilder assertionBuilder; +	@Autowired(required=true) IPVP2BasicConfiguration pvpBasicConfiguration; +	 +	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 SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, +			HttpServletResponse httpResp, IAuthData authData) throws ResponderErrorException {		 +		PVPSProfilePendingRequest pvpRequest = (PVPSProfilePendingRequest) req; +		try { +			//get basic information  +			PVPSProfileRequest moaRequest = (PVPSProfileRequest) pvpRequest.getRequest(); +			AuthnRequest authnRequest = (AuthnRequest) moaRequest.getSamlRequest(); +			EntityDescriptor peerEntity = moaRequest.getEntityMetadata(metadataProvider);		 +		 +			AssertionConsumerService consumerService =  +					SAML2Utils.createSAMLObject(AssertionConsumerService.class); +			consumerService.setBinding(pvpRequest.getBinding()); +			consumerService.setLocation(pvpRequest.getConsumerURL()); +				 +			DateTime date = new DateTime();		  +			SLOInformationImpl sloInformation = new SLOInformationImpl(); +			String issuerEntityID = pvpBasicConfiguration.getIDPEntityId(pvpRequest.getAuthURL()); +		 +			//build Assertion +			Assertion assertion = assertionBuilder.buildAssertion(issuerEntityID, pvpRequest, authnRequest, authData,  +					peerEntity, date, consumerService, sloInformation); +		 +			Response authResponse = AuthResponseBuilder.buildResponse( +					metadataProvider, issuerEntityID, authnRequest,  +					date, assertion, authConfig.getBasicMOAIDConfigurationBoolean( +							CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION, true)); +							 +			IEncoder binding = null; + +			if (consumerService.getBinding().equals( +					SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { +				binding = springContext.getBean("PVPRedirectBinding", RedirectBinding.class); +						 +			} else if (consumerService.getBinding().equals( +					SAMLConstants.SAML2_POST_BINDING_URI)) { +				binding = springContext.getBean("PVPPOSTBinding", PostBinding.class); +			 +			} + +			if (binding == null) { +				throw new BindingNotSupportedException(consumerService.getBinding()); +			} +				 +			binding.encodeRespone(httpReq, httpResp, authResponse,  +					consumerService.getLocation(), moaRequest.getRelayState(), +					pvpIDPCredentials.getIDPAssertionSigningCredential(), req); + +			//set protocol type +			sloInformation.setProtocolType(req.requestedModule()); +			sloInformation.setSpEntityID(req.getServiceProviderConfiguration().getUniqueIdentifier()); +			return sloInformation; +			 +		} catch (MessageEncodingException e) { +			 log.error("Message Encoding exception", e); +			throw new ResponderErrorException("pvp2.01", null, e); +			 +		} catch (SecurityException e) { +			 log.error("Security exception", e); +			throw new ResponderErrorException("pvp2.01", null, e); +			 +		} catch (EAAFException e) { +			 log.error("Response generation error", e); +			throw new ResponderErrorException("pvp2.01", null, e); +			 +		} +		 +	} + +	public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, +			HttpServletResponse httpResp) { +		return true; +	} + +	public String getDefaultActionName() { +		return "PVPAuthenticationRequestAction"; +		 +	} +	 +	@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/MetadataAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java new file mode 100644 index 00000000..fa871597 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java @@ -0,0 +1,99 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.impl; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; + +import at.gv.egiz.eaaf.core.api.IRequest; +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.slo.SLOInformationInterface; +import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; +import at.gv.egiz.eaaf.modules.pvp2.PVPEventConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataBuilderConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataConfigurationFactory; +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPMetadataBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; + +@Service("pvpMetadataService") +public class MetadataAction implements IAction { + +	private static final Logger log = LoggerFactory.getLogger(MetadataAction.class); + +	@Autowired private IRevisionLogger revisionsLogger;  +	@Autowired private PVPMetadataBuilder metadatabuilder; +	@Autowired private IPVPMetadataConfigurationFactory configFactory; +	 +	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 SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, +			HttpServletResponse httpResp, IAuthData authData) throws PVP2MetadataException { +		try { +			revisionsLogger.logEvent(req, PVPEventConstants.AUTHPROTOCOL_PVP_METADATA); +			 +			//build metadata +			IPVPMetadataBuilderConfiguration metadataConfig =  +					configFactory.generateMetadataBuilderConfiguration( +							req.getAuthURLWithOutSlash(),  +							pvpIDPCredentials); +								 +			; +			 +			String metadataXML = metadatabuilder.buildPVPMetadata(metadataConfig);			 +			log.debug("METADATA: " + metadataXML); +					 +			byte[] content = metadataXML.getBytes("UTF-8"); +			httpResp.setStatus(HttpServletResponse.SC_OK); +			httpResp.setContentLength(content.length); +			httpResp.setContentType(MediaType.APPLICATION_XML_VALUE); +			httpResp.getOutputStream().write(content);			 +			return null; +			 +		} catch (Exception e) { +			log.error("Failed to generate metadata", e); +			throw new PVP2MetadataException("pvp2.13", null); +		}  +	} + +	public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, +			HttpServletResponse httpResp) { +		return false; +	} + +	/* (non-Javadoc) +	 * @see at.gv.egovernment.moa.id.moduls.IAction#getDefaultActionName() +	 */ +	@Override +	public String getDefaultActionName() { +		return "IDP - PVP Metadata action"; +	} +	 +	@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/PVPSProfilePendingRequest.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PVPSProfilePendingRequest.java new file mode 100644 index 00000000..06c64b84 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PVPSProfilePendingRequest.java @@ -0,0 +1,103 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.impl; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; + +@Component("PVPSProfilePendingRequest") +@Scope(value = BeanDefinition.SCOPE_PROTOTYPE) +public class PVPSProfilePendingRequest extends RequestImpl { 	 +	private static final long serialVersionUID = 4889919265919638188L; +	 +	InboundMessage request; +	String binding; +	String consumerURL; +		 +	public InboundMessage getRequest() {  +		return request; +	} + +	public void setRequest(InboundMessage request) { +		this.request = request; +	} + +	public String getBinding() { +		return binding; +	} + +	public void setBinding(String binding) { +		this.binding = binding; +	} + +	public String getConsumerURL() { +		return consumerURL; +	} + +	public void setConsumerURL(String consumerURL) { +		this.consumerURL = consumerURL; +		 +	} + +//	/* (non-Javadoc) +//	 * @see at.gv.egovernment.moa.id.moduls.RequestImpl#getRequestedAttributes() +//	 */ +//	@Override +//	public Collection<String> getRequestedAttributes(MetadataProvider metadataProvider) { +// +//		Map<String, String> reqAttr = new HashMap<String, String>(); +//		for (String el : PVP2XProtocol.DEFAULTREQUESTEDATTRFORINTERFEDERATION) +//			reqAttr.put(el, ""); +//						 +//		try {			 +//			SPSSODescriptor spSSODescriptor = getRequest().getEntityMetadata(metadataProvider).getSPSSODescriptor(SAMLConstants.SAML20P_NS); +//			if (spSSODescriptor.getAttributeConsumingServices() != null &&  +//					spSSODescriptor.getAttributeConsumingServices().size() > 0) { +//							 +//				Integer aIdx = null; +//				if (getRequest() instanceof MOARequest &&  +//						((MOARequest)getRequest()).getSamlRequest() instanceof AuthnRequestImpl) {					 +//					AuthnRequestImpl authnRequest = (AuthnRequestImpl)((MOARequest)getRequest()).getSamlRequest();					 +//					aIdx = authnRequest.getAttributeConsumingServiceIndex(); +//					 +//				} else { +//					Logger.error("MOARequest is NOT of type AuthnRequest"); +//				} +//				 +//				int idx = 0; +// +//				AttributeConsumingService attributeConsumingService = null; +//				 +//				if (aIdx != null) { +//					idx = aIdx.intValue(); +//					attributeConsumingService = spSSODescriptor +//							.getAttributeConsumingServices().get(idx); +//					 +//				} else { +//					List<AttributeConsumingService> attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices(); +//					for (AttributeConsumingService el : attrConsumingServiceList) { +//						if (el.isDefault()) +//							attributeConsumingService = el; +//					}				 +//				} +//				 +//				for ( RequestedAttribute attr : attributeConsumingService.getRequestAttributes()) +//					reqAttr.put(attr.getName(), ""); +//			} +//			 +//			//return attributQueryBuilder.buildSAML2AttributeList(this.getOnlineApplicationConfiguration(), reqAttr.keySet().iterator()); +//			return reqAttr.keySet(); +//			 +//		} catch (NoMetadataInformationException e) { +//			Logger.warn("NO metadata found for Entity " + getRequest().getEntityID()); +//			return null; +//					 +//		} +//		 +//	} + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java new file mode 100644 index 00000000..34a28f72 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java @@ -0,0 +1,129 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder; + +import java.util.ArrayList; +import java.util.List; + +import org.joda.time.DateTime; +import org.opensaml.Configuration; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.EncryptedAssertion; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.RequestAbstractType; +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.encryption.Encrypter; +import org.opensaml.saml2.encryption.Encrypter.KeyPlacement; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml2.metadata.provider.MetadataProvider; +import org.opensaml.security.MetadataCredentialResolver; +import org.opensaml.security.MetadataCriteria; +import org.opensaml.xml.encryption.EncryptionException; +import org.opensaml.xml.encryption.EncryptionParameters; +import org.opensaml.xml.encryption.KeyEncryptionParameters; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.criteria.EntityIDCriteria; +import org.opensaml.xml.security.criteria.UsageCriteria; +import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorFactory; +import org.opensaml.xml.security.x509.X509Credential; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.eaaf.modules.pvp2.PVPConstants; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; + +/** + * @author tlenz + * + */ +public class AuthResponseBuilder { + +	private static final Logger log = LoggerFactory.getLogger(AuthResponseBuilder.class); +	 +	public static Response buildResponse(MetadataProvider metadataProvider, String issuerEntityID, RequestAbstractType req, DateTime date, Assertion assertion, boolean enableEncryption) throws InvalidAssertionEncryptionException { +		Response authResponse = SAML2Utils.createSAMLObject(Response.class); +  +		Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); +		 +		nissuer.setValue(issuerEntityID); +		nissuer.setFormat(NameID.ENTITY); +		authResponse.setIssuer(nissuer); +		authResponse.setInResponseTo(req.getID()); + +		//set responseID +		String remoteSessionID = SAML2Utils.getSecureIdentifier(); +		authResponse.setID(remoteSessionID); +		 +		 +		//SAML2 response required IssueInstant +		authResponse.setIssueInstant(date); +		 +		authResponse.setStatus(SAML2Utils.getSuccessStatus()); +				 +		//check, if metadata includes an encryption key				 +		MetadataCredentialResolver mdCredResolver =  +				new MetadataCredentialResolver(metadataProvider); +	 +		CriteriaSet criteriaSet = new CriteriaSet(); +		criteriaSet.add( new EntityIDCriteria(req.getIssuer().getValue()) ); +		criteriaSet.add( new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) ); +		criteriaSet.add( new UsageCriteria(UsageType.ENCRYPTION) ); +	 +		X509Credential encryptionCredentials = null; +		try { +			encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); +				 +		} catch (SecurityException e2) { +			log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); +			throw new InvalidAssertionEncryptionException(); +			 +		} +			 +		if (encryptionCredentials != null && enableEncryption) { +			//encrypt SAML2 assertion +				 +			try { +				 +				EncryptionParameters dataEncParams = new EncryptionParameters(); +				dataEncParams.setAlgorithm(PVPConstants.DEFAULT_SYM_ENCRYPTION_METHODE); +								 +				List<KeyEncryptionParameters> keyEncParamList = new ArrayList<KeyEncryptionParameters>(); +				KeyEncryptionParameters  keyEncParam = new KeyEncryptionParameters(); +			 +				keyEncParam.setEncryptionCredential(encryptionCredentials); +				keyEncParam.setAlgorithm(PVPConstants.DEFAULT_ASYM_ENCRYPTION_METHODE); +				KeyInfoGeneratorFactory kigf = Configuration.getGlobalSecurityConfiguration() +						.getKeyInfoGeneratorManager().getDefaultManager() +						.getFactory(encryptionCredentials); +				keyEncParam.setKeyInfoGenerator(kigf.newInstance()); +				keyEncParamList.add(keyEncParam); +											 +				Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList);  +				//samlEncrypter.setKeyPlacement(KeyPlacement.INLINE); +				samlEncrypter.setKeyPlacement(KeyPlacement.PEER); +				 +				EncryptedAssertion encryptAssertion = null; +				 +				encryptAssertion = samlEncrypter.encrypt(assertion); +				 +				authResponse.getEncryptedAssertions().add(encryptAssertion); +				 +			} catch (EncryptionException e1) { +				log.warn("Can not encrypt the PVP2 assertion", e1); +				throw new InvalidAssertionEncryptionException(); +					 +			}  + +		} else { +			authResponse.getAssertions().add(assertion); +				 +		} +		 +		return authResponse; +	} +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java new file mode 100644 index 00000000..7369da15 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java @@ -0,0 +1,448 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder; + +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.core.AttributeQuery; +import org.opensaml.saml2.core.AttributeStatement; +import org.opensaml.saml2.core.Audience; +import org.opensaml.saml2.core.AudienceRestriction; +import org.opensaml.saml2.core.AuthnContext; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.AuthnStatement; +import org.opensaml.saml2.core.Conditions; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.RequestedAuthnContext; +import org.opensaml.saml2.core.Subject; +import org.opensaml.saml2.core.SubjectConfirmation; +import org.opensaml.saml2.core.SubjectConfirmationData; +import org.opensaml.saml2.core.impl.AuthnRequestImpl; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.AttributeConsumingService; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.NameIDFormat; +import org.opensaml.saml2.metadata.RequestedAttribute; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Base64Utils; + +import at.gv.egiz.eaaf.core.api.data.EAAFConstants; +import at.gv.egiz.eaaf.core.api.data.ILoALevelMapper; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; +import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface; +import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.modules.pvp2.PVPConstants; +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.QAANotSupportedException; +import at.gv.egiz.eaaf.modules.pvp2.idp.api.builder.ISubjectNameIdGenerator; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.UnprovideableAttributeException; +import at.gv.egiz.eaaf.modules.pvp2.idp.impl.PVPSProfilePendingRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPAttributeBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.QAALevelVerifier; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; + +@Service("PVP2AssertionBuilder") +public class PVP2AssertionBuilder implements PVPConstants { +	 +	private static final Logger log = LoggerFactory.getLogger(PVP2AssertionBuilder.class); +	@Autowired private ILoALevelMapper loaLevelMapper; +	@Autowired private ISubjectNameIdGenerator subjectNameIdGenerator; +	 +	 +	/** +	 * Build a PVP assertion as response for a SAML2 AttributeQuery request +	 *  +	 * @param issuerEntityID EnitiyID, which should be used for this IDP response  +	 * @param attrQuery AttributeQuery request from Service-Provider +	 * @param attrList List of PVP response attributes +	 * @param now Current time  +	 * @param validTo ValidTo time of the assertion +	 * @param qaaLevel QAA level of the authentication +	 * @param sessionIndex SAML2 SessionIndex, which should be included	 *  +	 * @return PVP 2.1 Assertion +	 * @throws PVP2Exception +	 */ +	public Assertion buildAssertion(String issuerEntityID, AttributeQuery attrQuery, +			List<Attribute> attrList, DateTime now, DateTime validTo, String qaaLevel, String sessionIndex) throws PVP2Exception { +			 +		AuthnContextClassRef authnContextClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); +		authnContextClassRef.setAuthnContextClassRef(qaaLevel); +		 +		NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class); +		subjectNameID.setFormat(attrQuery.getSubject().getNameID().getFormat()); +		subjectNameID.setValue(attrQuery.getSubject().getNameID().getValue()); +		 +		SubjectConfirmationData subjectConfirmationData = null; +		 +		return buildGenericAssertion(issuerEntityID, attrQuery.getIssuer().getValue(), now,  +				authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, +				validTo); +	} +	 +	 +	/** +	 * Build a PVP 2.1 assertion as response of a SAML2 AuthnRequest +	 *  +	 * @param issuerEntityID EnitiyID, which should be used for this IDP response  +	 * @param pendingReq Current processed pendingRequest DAO +	 * @param authnRequest Current processed PVP AuthnRequest +	 * @param authData AuthenticationData of the user, which is already authenticated +	 * @param peerEntity SAML2 EntityDescriptor of the service-provider, which receives the response +	 * @param date TimeStamp +	 * @param assertionConsumerService SAML2 endpoint of the service-provider, which should be used +	 * @param sloInformation Single LogOut information DAO +	 * @return +	 * @throws PVP2Exception +	 */ +	public Assertion buildAssertion(String issuerEntityID, PVPSProfilePendingRequest pendingReq, AuthnRequest authnRequest, +			IAuthData authData, EntityDescriptor peerEntity, DateTime date,  +			AssertionConsumerService assertionConsumerService, SLOInformationInterface sloInformation) +			throws PVP2Exception { + +		RequestedAuthnContext reqAuthnContext = authnRequest +				.getRequestedAuthnContext(); + +		AuthnContextClassRef authnContextClassRef = SAML2Utils +				.createSAMLObject(AuthnContextClassRef.class); +		 +		ISPConfiguration oaParam = pendingReq.getServiceProviderConfiguration(); +		 +		if (reqAuthnContext == null) { +			 authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel()); +			 +		} else { +  +			boolean eIDAS_qaa_found = false; +	 +			List<AuthnContextClassRef> reqAuthnContextClassRefIt = reqAuthnContext +					.getAuthnContextClassRefs(); +		 +			if (reqAuthnContextClassRefIt.size() == 0) {			  +				QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(), EAAFConstants.EIDAS_QAA_HIGH); +			 +				eIDAS_qaa_found = true; +				authnContextClassRef.setAuthnContextClassRef(EAAFConstants.EIDAS_QAA_HIGH); +			  +			} else { +				for (AuthnContextClassRef authnClassRef : reqAuthnContextClassRefIt) { +					String qaa_uri = authnClassRef.getAuthnContextClassRef(); +										 +					if (!qaa_uri.trim().startsWith(EAAFConstants.EIDAS_QAA_PREFIX)) { +						if (loaLevelMapper != null) { +							log.debug("Find no eIDAS LoA. Start mapping process ... " ); +							qaa_uri = loaLevelMapper.mapToeIDASLoA(qaa_uri.trim()); +							 +						} else +							log.debug("AuthnRequest contains no eIDAS LoA. NO LoA mapper FOUND, ignore " +									+ "'" +  qaa_uri.trim() + "'"); +											 +					} +					 +					if (qaa_uri.trim().equals(EAAFConstants.EIDAS_QAA_HIGH) +							|| qaa_uri.trim().equals(EAAFConstants.EIDAS_QAA_SUBSTANTIAL) +							|| qaa_uri.trim().equals(EAAFConstants.EIDAS_QAA_LOW)) { +					 +						 if (authData.isForeigner()) { +							 QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(), oaParam.getMinimumLevelOfAssurence()); +							  +							 eIDAS_qaa_found = true; +							 authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel()); +							  +						 } else { +							  +							 QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(),  +									 qaa_uri.trim()); +							  +							 eIDAS_qaa_found = true; +							 authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel()); +							 							  +						 } +						 break; +					 } +				 } +			 } +	 +			if (!eIDAS_qaa_found) +				throw new QAANotSupportedException(EAAFConstants.EIDAS_QAA_HIGH); +				 +		} +		 + + +		SPSSODescriptor spSSODescriptor = peerEntity +				.getSPSSODescriptor(SAMLConstants.SAML20P_NS); +				 +		//add Attributes to Assertion +		List<Attribute> attrList = new ArrayList<Attribute>(); +		if (spSSODescriptor.getAttributeConsumingServices() != null &&  +				spSSODescriptor.getAttributeConsumingServices().size() > 0) { +		 +			Integer aIdx = authnRequest.getAttributeConsumingServiceIndex(); +			int idx = 0; + +			AttributeConsumingService attributeConsumingService = null;						 +			if (aIdx != null) { +				idx = aIdx.intValue(); +				attributeConsumingService = spSSODescriptor +						.getAttributeConsumingServices().get(idx); +				 +			} else { +				List<AttributeConsumingService> attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices(); +				for (AttributeConsumingService el : attrConsumingServiceList) { +					if (el.isDefault()) +						attributeConsumingService = el; +				}				 +			} +			 +			/*  +			 * TODO: maybe use first AttributeConsumingService if no is selected  +			 * in request or on service is marked as default +			 *  +			 */ +			if (attributeConsumingService == null ) { +				List<AttributeConsumingService> attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices(); +				if (attrConsumingServiceList != null && !attrConsumingServiceList.isEmpty()) +					attributeConsumingService = attrConsumingServiceList.get(0); +								 +			} +			 +			 +			if (attributeConsumingService != null) {						 +				Iterator<RequestedAttribute> it = attributeConsumingService +						.getRequestAttributes().iterator(); +				while (it.hasNext()) { +					RequestedAttribute reqAttribut = it.next(); +					try { +						Attribute attr = PVPAttributeBuilder.buildAttribute( +								reqAttribut.getName(), oaParam, authData); +						if (attr == null) { +							if (reqAttribut.isRequired()) { +								throw new UnprovideableAttributeException( +										reqAttribut.getName()); +							} +						} else { +							attrList.add(attr); +						} +					 +					} catch (UnavailableAttributeException e) { +						log.info( +								"Attribute generation for " +										+ reqAttribut.getFriendlyName() + " not possible."); +						if (reqAttribut.isRequired()) { +							throw new UnprovideableAttributeException( +									reqAttribut.getName()); +						} +						 +					 +					} catch (PVP2Exception e) { +						log.info( +								"Attribute generation failed! for " +										+ reqAttribut.getFriendlyName()); +						if (reqAttribut.isRequired()) { +							throw new UnprovideableAttributeException( +									reqAttribut.getName()); +						} +						 +					} catch (Exception e) { +						log.warn( +								"General Attribute generation failed! for " +										+ reqAttribut.getFriendlyName(), e); +						if (reqAttribut.isRequired()) { +							throw new UnprovideableAttributeException( +									reqAttribut.getName()); +						} +						 +					}  +				} +			} +		} + +		//generate subjectNameId +		NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class); +		Pair<String, String> subjectNameIdPair = subjectNameIdGenerator.generateSubjectNameId(authData, oaParam); +		subjectNameID.setValue(subjectNameIdPair.getFirst()); +		subjectNameID.setNameQualifier(subjectNameIdPair.getSecond()); +						 +		//get NameIDFormat from request +		String nameIDFormat = NameID.TRANSIENT; +		AuthnRequest authnReq = (AuthnRequestImpl) authnRequest; +		if (authnReq.getNameIDPolicy() != null &&  +				StringUtils.isNotEmpty(authnReq.getNameIDPolicy().getFormat())) { +			nameIDFormat = authnReq.getNameIDPolicy().getFormat(); +			 +		} else { +			//get NameIDFormat from metadata +			List<NameIDFormat> metadataNameIDFormats = spSSODescriptor.getNameIDFormats(); +			 +			if (metadataNameIDFormats != null) { +				 +				for (NameIDFormat el : metadataNameIDFormats) { +					if (NameID.PERSISTENT.equals(el.getFormat())) { +						nameIDFormat = NameID.PERSISTENT; +						break; +						 +					} else if (NameID.TRANSIENT.equals(el.getFormat()) || +							NameID.UNSPECIFIED.equals(el.getFormat())) +						break; +					 +				}				 +			} +		} +	 +		if (NameID.TRANSIENT.equals(nameIDFormat) || NameID.UNSPECIFIED.equals(nameIDFormat)) { +			String random = Random.nextHexRandom32(); +			String nameID = subjectNameID.getValue(); +			 +			try { +				MessageDigest md = MessageDigest.getInstance("SHA-1"); +				byte[] hash = md.digest((nameID + random).getBytes("ISO-8859-1"));			 +				subjectNameID.setValue(Base64Utils.encodeToString(hash)); +				subjectNameID.setNameQualifier(null); +				subjectNameID.setFormat(NameID.TRANSIENT); +				 +			} catch (Exception e) { +				log.warn("PVP2 subjectNameID error", e); +				throw new ResponderErrorException("pvp2.13", null, e); +			} +			 +		} else  +			subjectNameID.setFormat(nameIDFormat); +			 + +		String sessionIndex = null; +					 +		//if request is a reauthentication and NameIDFormat match reuse old session information +		if (StringUtils.isNotEmpty(authData.getNameID()) &&  +				StringUtils.isNotEmpty(authData.getNameIDFormat()) &&  +				nameIDFormat.equals(authData.getNameIDFormat())) { +			subjectNameID.setValue(authData.getNameID()); +			sessionIndex = authData.getSessionIndex(); +			 +		} +		 +		// +		if (StringUtils.isEmpty(sessionIndex)) +			sessionIndex = SAML2Utils.getSecureIdentifier(); +									 +		SubjectConfirmationData subjectConfirmationData = SAML2Utils +				.createSAMLObject(SubjectConfirmationData.class); +		subjectConfirmationData.setInResponseTo(authnRequest.getID()); +		subjectConfirmationData.setNotOnOrAfter(new DateTime(authData.getSsoSessionValidTo().getTime())); +//		subjectConfirmationData.setNotBefore(date); +		 +		//set 'recipient' attribute in subjectConformationData  +		subjectConfirmationData.setRecipient(assertionConsumerService.getLocation()); +		 +		//set IP address of the user machine as 'Address' attribute in subjectConformationData  +		String usersIPAddress = pendingReq.getGenericData( +				RequestImpl.DATAID_REQUESTER_IP_ADDRESS, String.class); +		if (StringUtils.isNotEmpty(usersIPAddress)) +			subjectConfirmationData.setAddress(usersIPAddress); +		 +		//set SLO information +		sloInformation.setUserNameIdentifier(subjectNameID.getValue()); +		sloInformation.setNameIDFormat(subjectNameID.getFormat()); +		sloInformation.setSessionIndex(sessionIndex); +		 +		return buildGenericAssertion(issuerEntityID, peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, subjectConfirmationData.getNotOnOrAfter()); +	} +	 +	/** +	 *  +	 * @param issuer IDP EntityID +	 * @param entityID Service Provider EntityID +	 * @param date  +	 * @param authnContextClassRef +	 * @param attrList +	 * @param subjectNameID +	 * @param subjectConfirmationData +	 * @param sessionIndex +	 * @param isValidTo +	 * @return +	 * @throws ConfigurationException +	 */ +	 +	public Assertion buildGenericAssertion(String issuer, String entityID, DateTime date,  +			AuthnContextClassRef authnContextClassRef, List<Attribute> attrList,  +			NameID subjectNameID, SubjectConfirmationData subjectConfirmationData,  +			String sessionIndex, DateTime isValidTo) throws ResponderErrorException { +		Assertion assertion = SAML2Utils.createSAMLObject(Assertion.class); +		 +		AuthnContext authnContext = SAML2Utils +				.createSAMLObject(AuthnContext.class); +		authnContext.setAuthnContextClassRef(authnContextClassRef); + +		AuthnStatement authnStatement = SAML2Utils +				.createSAMLObject(AuthnStatement.class); +		 +		authnStatement.setAuthnInstant(date); +		authnStatement.setSessionIndex(sessionIndex); +		authnStatement.setAuthnContext(authnContext); + +		assertion.getAuthnStatements().add(authnStatement); +		 +		AttributeStatement attributeStatement = SAML2Utils +				.createSAMLObject(AttributeStatement.class);		 +		attributeStatement.getAttributes().addAll(attrList);		 +		if (attributeStatement.getAttributes().size() > 0) { +			assertion.getAttributeStatements().add(attributeStatement); +		} +		 +		Subject subject = SAML2Utils.createSAMLObject(Subject.class); +		subject.setNameID(subjectNameID); +		 +		SubjectConfirmation subjectConfirmation = SAML2Utils +				.createSAMLObject(SubjectConfirmation.class); +		subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER); +		subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData); + +		subject.getSubjectConfirmations().add(subjectConfirmation); + +		Conditions conditions = SAML2Utils.createSAMLObject(Conditions.class); +		AudienceRestriction audienceRestriction = SAML2Utils +				.createSAMLObject(AudienceRestriction.class); +		Audience audience = SAML2Utils.createSAMLObject(Audience.class); +		 +		audience.setAudienceURI(entityID); +		audienceRestriction.getAudiences().add(audience); +		conditions.setNotBefore(date);		 +		conditions.setNotOnOrAfter(isValidTo); +				 +		conditions.getAudienceRestrictions().add(audienceRestriction); + +		assertion.setConditions(conditions); + +		Issuer issuerObj = SAML2Utils.createSAMLObject(Issuer.class); +				 +		if (issuer.endsWith("/")) +			issuer = issuer.substring(0, issuer.length()-1); +		issuerObj.setValue(issuer); +		issuerObj.setFormat(NameID.ENTITY); +		 +		assertion.setIssuer(issuerObj); +		assertion.setSubject(subject); +		assertion.setID(SAML2Utils.getSecureIdentifier()); +		assertion.setIssueInstant(date); +		 +		return assertion;		 +	} +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider new file mode 100644 index 00000000..cda12a62 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider @@ -0,0 +1 @@ +at.gv.egiz.eaaf.modules.pvp2.idp.PVP2SProfileIDPSpringResourceProvider
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml new file mode 100644 index 00000000..a54482e9 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" +	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +	xmlns:context="http://www.springframework.org/schema/context" +	xmlns:tx="http://www.springframework.org/schema/tx" +	xmlns:aop="http://www.springframework.org/schema/aop" +	xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd +		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd +		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd +		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> +		 +	<bean id="PVP2AssertionBuilder" +			class="at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.PVP2AssertionBuilder" /> +																				 +	<bean 	id="PVPSProfilePendingRequest"  +			class="at.gv.egiz.eaaf.modules.pvp2.idp.impl.PVPSProfilePendingRequest" +			scope="prototype"/> +			 +</beans>
\ No newline at end of file | 
