package org.apereo.cas.support.saml.web.idp.profile.builders.response; import com.google.common.base.Throwables; import org.apereo.cas.support.saml.OpenSamlConfigBean; import org.apereo.cas.support.saml.SamlException; import org.apereo.cas.support.saml.SamlIdPUtils; import org.apereo.cas.support.saml.SamlUtils; import org.apereo.cas.support.saml.services.SamlRegisteredService; import org.apereo.cas.support.saml.services.idp.metadata.SamlRegisteredServiceServiceProviderMetadataFacade; import org.apereo.cas.support.saml.web.idp.profile.builders.SamlProfileObjectBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.enc.BaseSamlObjectSigner; import org.apereo.cas.support.saml.web.idp.profile.builders.enc.SamlObjectEncrypter; import org.opensaml.messaging.context.MessageContext; import org.opensaml.saml.common.SAMLObject; import org.opensaml.saml.common.SAMLVersion; import org.opensaml.saml.common.binding.SAMLBindingSupport; import org.opensaml.saml.saml2.binding.encoding.impl.HTTPPostEncoder; import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.AuthnRequest; import org.opensaml.saml.saml2.core.EncryptedAssertion; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.Response; import org.opensaml.saml.saml2.core.Status; import org.opensaml.saml.saml2.core.StatusCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ui.velocity.VelocityEngineFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.security.SecureRandom; import java.time.ZoneOffset; import java.time.ZonedDateTime; /** * This is {@link SamlProfileSaml2ResponseBuilder}. * * @author Misagh Moayyed * @since 5.1.0 */ public class SamlProfileSaml2ResponseBuilder extends BaseSamlProfileSamlResponseBuilder<Response> { private static final long serialVersionUID = 1488837627964481272L; private static final Logger LOGGER = LoggerFactory.getLogger(SamlProfileSaml2ResponseBuilder.class); public SamlProfileSaml2ResponseBuilder(final OpenSamlConfigBean openSamlConfigBean, final BaseSamlObjectSigner samlObjectSigner, final VelocityEngineFactory velocityEngineFactory, final SamlProfileObjectBuilder<Assertion> samlProfileSamlAssertionBuilder, final SamlObjectEncrypter samlObjectEncrypter) { super(openSamlConfigBean, samlObjectSigner, velocityEngineFactory, samlProfileSamlAssertionBuilder, samlObjectEncrypter); } @Override protected Response buildResponse(final Assertion assertion, final org.jasig.cas.client.validation.Assertion casAssertion, final AuthnRequest authnRequest, final SamlRegisteredService service, final SamlRegisteredServiceServiceProviderMetadataFacade adaptor, final HttpServletRequest request, final HttpServletResponse response, final String binding) throws SamlException { final String id = '_' + String.valueOf(Math.abs(new SecureRandom().nextLong())); Response samlResponse = newResponse(id, ZonedDateTime.now(ZoneOffset.UTC), authnRequest.getID(), null); samlResponse.setVersion(SAMLVersion.VERSION_20); samlResponse.setIssuer(buildEntityIssuer()); samlResponse.setConsent(RequestAbstractType.UNSPECIFIED_CONSENT); final SAMLObject finalAssertion = encryptAssertion(assertion, request, response, service, adaptor); if (finalAssertion instanceof EncryptedAssertion) { LOGGER.debug("Built assertion is encrypted, so the response will add it to the encrypted assertions collection"); samlResponse.getEncryptedAssertions().add(EncryptedAssertion.class.cast(finalAssertion)); } else { LOGGER.debug("Built assertion is not encrypted, so the response will add it to the assertions collection"); samlResponse.getAssertions().add(Assertion.class.cast(finalAssertion)); } final Status status = newStatus(StatusCode.SUCCESS, StatusCode.SUCCESS); samlResponse.setStatus(status); SamlUtils.logSamlObject(this.configBean, samlResponse); if (service.isSignResponses()) { LOGGER.debug("SAML entity id [{}] indicates that SAML responses should be signed", adaptor.getEntityId()); samlResponse = this.samlObjectSigner.encode(samlResponse, service, adaptor, response, request, binding); } return samlResponse; } @Override protected Response encode(final SamlRegisteredService service, final Response samlResponse, final HttpServletResponse httpResponse, final SamlRegisteredServiceServiceProviderMetadataFacade adaptor, final String relayState, final String binding) throws SamlException { try { if (httpResponse != null) { final HTTPPostEncoder encoder = new HTTPPostEncoder(); encoder.setHttpServletResponse(httpResponse); encoder.setVelocityEngine(this.velocityEngineFactory.createVelocityEngine()); final MessageContext outboundMessageContext = new MessageContext<>(); outboundMessageContext.setMessage(samlResponse); SAMLBindingSupport.setRelayState(outboundMessageContext, relayState); SamlIdPUtils.preparePeerEntitySamlEndpointContext(outboundMessageContext, adaptor, binding); encoder.setMessageContext(outboundMessageContext); encoder.initialize(); encoder.encode(); } return samlResponse; } catch (final Exception e) { throw Throwables.propagate(e); } } }