/******************************************************************************* *******************************************************************************/ package at.gv.egiz.eaaf.modules.pvp2.sp.impl; import java.security.NoSuchAlgorithmException; import java.util.List; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.opensaml.common.impl.SecureRandomIdentifierGenerator; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.common.Extensions; import org.opensaml.saml2.core.AuthnContextClassRef; import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.Issuer; import org.opensaml.saml2.core.NameID; import org.opensaml.saml2.core.NameIDPolicy; import org.opensaml.saml2.core.NameIDType; import org.opensaml.saml2.core.RequestedAuthnContext; import org.opensaml.saml2.core.RequesterID; import org.opensaml.saml2.core.Scoping; import org.opensaml.saml2.core.Subject; import org.opensaml.saml2.core.SubjectConfirmation; import org.opensaml.saml2.core.SubjectConfirmationData; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.SingleSignOnService; 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.modules.pvp2.api.binding.IEncoder; import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EAAFRequestedAttribute; import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EAAFRequestedAttributes; import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; 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.builder.reqattr.EAAFRequestExtensionBuilder; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; import at.gv.egiz.eaaf.modules.pvp2.sp.api.IPVPAuthnRequestBuilderConfiguruation; import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnRequestBuildException; /** * @author tlenz * */ @Service("pvpAuthnRequestBuilder") public class PVPAuthnRequestBuilder { private static final Logger log = LoggerFactory.getLogger(PVPAuthnRequestBuilder.class); @Autowired(required=true) ApplicationContext springContext; /** * Build a PVP2.x specific authentication request * * @param pendingReq Currently processed pendingRequest * @param config AuthnRequest builder configuration, never null * @param idpEntity SAML2 EntityDescriptor of the IDP, which receive this AuthnRequest, never null * @param httpResp * @throws NoSuchAlgorithmException * @throws SecurityException * @throws PVP2Exception * @throws MessageEncodingException */ public void buildAuthnRequest(IRequest pendingReq, IPVPAuthnRequestBuilderConfiguruation config, HttpServletResponse httpResp) throws NoSuchAlgorithmException, MessageEncodingException, PVP2Exception, SecurityException { //get IDP Entity element from config EntityDescriptor idpEntity = config.getIDPEntityDescriptor(); AuthnRequest authReq = SAML2Utils .createSAMLObject(AuthnRequest.class); //select SingleSignOn Service endpoint from IDP metadata SingleSignOnService endpoint = null; for (SingleSignOnService sss : idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleSignOnServices()) { // use POST binding as default if it exists if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { endpoint = sss; } else if ( sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) && endpoint == null ) endpoint = sss; } if (endpoint == null) { log.warn("Building AuthnRequest FAILED: > Requested IDP " + idpEntity.getEntityID() + " does not support POST or Redirect Binding."); throw new AuthnRequestBuildException("sp.pvp2.00", new Object[]{config.getSPNameForLogging(), idpEntity.getEntityID()}); } else authReq.setDestination(endpoint.getLocation()); //set basic AuthnRequest information String reqID = config.getRequestID(); if (StringUtils.isNotEmpty(reqID)) authReq.setID(reqID); else { SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); authReq.setID(gen.generateIdentifier()); } authReq.setIssueInstant(new DateTime()); //set isPassive flag if (config.isPassivRequest() == null) authReq.setIsPassive(false); else authReq.setIsPassive(config.isPassivRequest()); //set EntityID of the service provider Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); issuer.setFormat(NameIDType.ENTITY); issuer.setValue(config.getSPEntityID()); authReq.setIssuer(issuer); //set AssertionConsumerService ID if (config.getAssertionConsumerServiceId() != null) authReq.setAssertionConsumerServiceIndex(config.getAssertionConsumerServiceId()); //set NameIDPolicy if (config.getNameIDPolicyFormat() != null) { NameIDPolicy policy = SAML2Utils.createSAMLObject(NameIDPolicy.class); policy.setAllowCreate(config.getNameIDPolicyAllowCreation()); policy.setFormat(config.getNameIDPolicyFormat()); authReq.setNameIDPolicy(policy); } //set requested QAA level if (config.getAuthnContextClassRef() != null) { RequestedAuthnContext reqAuthContext = SAML2Utils.createSAMLObject(RequestedAuthnContext.class); AuthnContextClassRef authnClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); authnClassRef.setAuthnContextClassRef(config.getAuthnContextClassRef()); if (config.getAuthnContextComparison() == null) reqAuthContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM); else reqAuthContext.setComparison(config.getAuthnContextComparison()); reqAuthContext.getAuthnContextClassRefs().add(authnClassRef); authReq.setRequestedAuthnContext(reqAuthContext); } //set request Subject element if (StringUtils.isNotEmpty(config.getSubjectNameID())) { Subject reqSubject = SAML2Utils.createSAMLObject(Subject.class); NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class); subjectNameID.setValue(config.getSubjectNameID()); if (StringUtils.isNotEmpty(config.getSubjectNameIDQualifier())) subjectNameID.setNameQualifier(config.getSubjectNameIDQualifier()); if (StringUtils.isNotEmpty(config.getSubjectNameIDFormat())) subjectNameID.setFormat(config.getSubjectNameIDFormat()); else subjectNameID.setFormat(NameID.TRANSIENT); reqSubject.setNameID(subjectNameID); if (config.getSubjectConformationDate() != null) { SubjectConfirmation subjectConformation = SAML2Utils.createSAMLObject(SubjectConfirmation.class); SubjectConfirmationData subjectConformDate = SAML2Utils.createSAMLObject(SubjectConfirmationData.class); subjectConformation.setSubjectConfirmationData(subjectConformDate); reqSubject.getSubjectConfirmations().add(subjectConformation ); if (config.getSubjectConformationMethode() != null) subjectConformation.setMethod(config.getSubjectConformationMethode()); subjectConformDate.setDOM(config.getSubjectConformationDate()); } authReq.setSubject(reqSubject ); } //set ProviderName if (StringUtils.isNotEmpty(config.getProviderName())) authReq.setProviderName(config.getProviderName()); //set RequesterId in case of proxy mode if (StringUtils.isNotEmpty(config.getScopeRequesterId())) { Scoping scope = SAML2Utils.createSAMLObject(Scoping.class); RequesterID requesterId = SAML2Utils.createSAMLObject(RequesterID.class); requesterId.setRequesterID(config.getScopeRequesterId()); scope.getRequesterIDs().add(requesterId ); authReq.setScoping(scope ); } //add optional requested attributes if (config.getRequestedAttributes() != null) { List reqAttr = config.getRequestedAttributes(); Extensions extenstions = new EAAFRequestExtensionBuilder().buildObject(); EAAFRequestedAttributes reqAttributs = SAML2Utils.createSAMLObject(EAAFRequestedAttributes.class); reqAttributs.getAttributes().addAll(reqAttr); extenstions.getUnknownXMLObjects().add(reqAttributs); authReq.setExtensions(extenstions ); } //select message encoder IEncoder binding = null; if (endpoint.getBinding().equals( SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { binding = springContext.getBean("PVPRedirectBinding", RedirectBinding.class); } else if (endpoint.getBinding().equals( SAMLConstants.SAML2_POST_BINDING_URI)) { binding = springContext.getBean("PVPPOSTBinding", PostBinding.class); } //encode message binding.encodeRequest(null, httpResp, authReq, endpoint.getLocation(), pendingReq.getPendingRequestId(), config.getAuthnRequestSigningCredential(), pendingReq); } }