package org.atricore.idbus.capabilities.sso.main.binding.producers; import oasis.names.tc.saml._1_0.protocol.RequestType; import oasis.names.tc.saml._1_0.protocol.ResponseType; import oasis.names.tc.saml._2_0.protocol.ArtifactResolveType; import oasis.names.tc.saml._2_0.protocol.ArtifactResponseType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.atricore.idbus.capabilities.sso.main.SSOException; import org.atricore.idbus.capabilities.sso.main.binding.*; import org.atricore.idbus.capabilities.sso.main.binding.plans.SamlR2ArtifactResolveToSamlR2ArtifactResponsePlan; import org.atricore.idbus.capabilities.sso.main.common.AbstractSSOMediator; import org.atricore.idbus.capabilities.sso.main.common.producers.SSOProducer; import org.atricore.idbus.capabilities.sso.support.SAMLR11Constants; import org.atricore.idbus.capabilities.sso.support.SAMLR2Constants; import org.atricore.idbus.capabilities.sso.support.binding.SSOBinding; import org.atricore.idbus.capabilities.sso.support.core.StatusCode; import org.atricore.idbus.capabilities.sso.support.core.StatusDetails; import org.atricore.idbus.kernel.main.federation.metadata.EndpointDescriptor; import org.atricore.idbus.kernel.main.federation.metadata.EndpointDescriptorImpl; import org.atricore.idbus.kernel.main.mediation.ArtifactImpl; import org.atricore.idbus.kernel.main.mediation.IdentityMediationFault; import org.atricore.idbus.kernel.main.mediation.MediationMessageImpl; import org.atricore.idbus.kernel.main.mediation.MessageQueueManager; import org.atricore.idbus.kernel.main.mediation.camel.AbstractCamelEndpoint; import org.atricore.idbus.kernel.main.mediation.camel.component.binding.CamelMediationExchange; import org.atricore.idbus.kernel.main.mediation.camel.component.binding.CamelMediationMessage; import org.atricore.idbus.kernel.main.mediation.channel.FederationChannel; import org.atricore.idbus.kernel.main.util.UUIDGenerator; import org.atricore.idbus.kernel.planning.*; import javax.xml.namespace.QName; /** * This producer can resolve SAML 1.1 and SAML 2.0 artifacts, the artifact must resolve to a SAML message * using the same request version. * * @author <a href="mailto:sgonzalez@atricore.org">Sebastian Gonzalez Oyuela</a> * @version $Id$ */ public class ArtifactResolutionProducer extends SSOProducer { private static final Log logger = LogFactory.getLog( ArtifactResolutionProducer.class ); private UUIDGenerator uuidGenerator = new UUIDGenerator(); public ArtifactResolutionProducer( AbstractCamelEndpoint<CamelMediationExchange> endpoint ) throws Exception { super( endpoint ); } @Override protected void doProcess(CamelMediationExchange exchange) throws Exception { CamelMediationMessage in = (CamelMediationMessage) exchange.getIn(); Object content = in.getMessage().getContent(); // Get artifact from AQM and send it in response. if (content instanceof RequestType) { doProcessSaml11ArtifactResolve(exchange, (RequestType) content); return; } else if (content instanceof ArtifactResolveType) { doProcessSaml2ArtifactResolve(exchange, (ArtifactResolveType) content); return; } throw new IdentityMediationFault(StatusCode.TOP_RESPONDER.getValue(), null, StatusDetails.UNKNOWN_REQUEST.getValue(), content.getClass().getName(), null); } protected void doProcessSaml2ArtifactResolve(CamelMediationExchange exchange, ArtifactResolveType request ) throws Exception { if (logger.isTraceEnabled()) logger.trace("Received ArtifactResolve request " + request.getID()); String samlArtEnc = request.getArtifact(); // Get encoder from configured HTTP Artifact binding SamlArtifactEncoder encoder = getSaml2ArtifactEncoder(); SamlArtifact samlArt = encoder.decode(samlArtEnc); // Recover original SAML Msg MessageQueueManager aqm = getArtifactQueueManager(); SamlMessageWrapper wrapper = (SamlMessageWrapper) aqm.pullMessage(new ArtifactImpl(samlArt.getMessageHandle())); Object samlMsg = wrapper.getMsg(); String samlType = wrapper.getType(); if (logger.isTraceEnabled()) logger.trace("Resolved SAML Artifact " + samlArt + " to " + samlMsg); // We're on a back-channel service, there's no actual destination endpoint EndpointDescriptor ed = new EndpointDescriptorImpl(endpoint.getName(), endpoint.getType(), endpoint.getBinding(), endpoint.getLocation(), endpoint.getResponseLocation()); ArtifactResponseType response = buildSaml2ArtifactResponse(exchange, ed, samlMsg, samlType); // -------------------------------------------------------------------- // Send Response to requester (this is SOAP or LOCAL) // -------------------------------------------------------------------- CamelMediationMessage out = (CamelMediationMessage) exchange.getOut(); out.setMessage(new MediationMessageImpl(response.getID(), response, "Response", null, ed, null)); exchange.setOut(out); return; } protected void doProcessSaml11ArtifactResolve(CamelMediationExchange exchange, RequestType request ) throws Exception { if (logger.isTraceEnabled()) logger.trace("Received ArtifactResolve request " + request.getRequestID()); String samlArtEnc = null; for (String s : request.getAssertionArtifact()) { samlArtEnc = s; } // Get encoder from configured HTTP Artifact binding SamlArtifactEncoder encoder = getSaml11ArtifactEncoder(); SamlArtifact samlArt = encoder.decode(samlArtEnc); // Recover original SAML Msg MessageQueueManager aqm = getArtifactQueueManager(); Object samlMsg = aqm.pullMessage(new ArtifactImpl(samlArt.getMessageHandle())); if (logger.isTraceEnabled()) logger.trace("Resolved SAML Artifact " + samlArt + " to " + samlMsg); // We're on a back-channel service, there's no actual destination endpoint EndpointDescriptor ed = new EndpointDescriptorImpl(endpoint.getName(), endpoint.getType(), endpoint.getBinding(), endpoint.getLocation(), endpoint.getResponseLocation()); ResponseType response = buildSaml11ArtifactResponse(exchange, ed, samlMsg); // -------------------------------------------------------------------- // Send Response to requester (this is SOAP or LOCAL) // -------------------------------------------------------------------- CamelMediationMessage out = (CamelMediationMessage) exchange.getOut(); out.setMessage(new MediationMessageImpl(response.toString(), response, "Response", null, ed, null)); exchange.setOut(out); return; } protected ResponseType buildSaml11ArtifactResponse( CamelMediationExchange exchange, EndpointDescriptor ed, java.lang.Object samlMsg) throws IdentityPlanningException, SSOException { // Let's do it simple for now ... /* RequestType request = (RequestType) ((CamelMediationMessage)exchange.getIn()).getMessage().getContent(); ResponseType response = new ResponseType(); // ID's response.setInResponseTo(request.getRequestID()); response.setResponseID(uuidGenerator.generateId()); response.setMajorVersion(BigInteger.valueOf(1)); response.setMinorVersion(BigInteger.valueOf(0)); // Issue instant // Content (not signed!) // Status StatusCodeType statusCode = new StatusCodeType(); statusCode.setValue(StatusCode11.TOP_SUCCESS.getQName()); StatusType status = new StatusType(); status.setStatusCode(statusCode); response.setStatus(status); return response; */ RequestType request = (RequestType) ((CamelMediationMessage)exchange.getIn()).getMessage().getContent(); ResponseType response = (ResponseType) samlMsg; response.setInResponseTo(request.getRequestID()); return response; } protected ArtifactResponseType buildSaml2ArtifactResponse( CamelMediationExchange exchange, EndpointDescriptor ed, java.lang.Object samlMsg, String samlType) throws IdentityPlanningException, SSOException { IdentityPlan identityPlan = findIdentityPlanOfType(SamlR2ArtifactResolveToSamlR2ArtifactResponsePlan.class); IdentityPlanExecutionExchange idPlanExchange = createIdentityPlanExecutionExchange(); FederationChannel fChannel = (FederationChannel) channel; // Publish IdP Metadata //idPlanExchange.setProperty(VAR_DESTINATION_COT_MEMBER, idp); idPlanExchange.setProperty(VAR_DESTINATION_ENDPOINT_DESCRIPTOR, ed); idPlanExchange.setProperty(VAR_COT_MEMBER, fChannel.getMember()); idPlanExchange.setProperty(VAR_SAMLR2_ARTIFACT, samlMsg); idPlanExchange.setProperty(VAR_SAMLR2_ARTIFACT_TYPE, samlType); // Get SPInitiated authn request, if any! ArtifactResolveType request = (ArtifactResolveType) ((CamelMediationMessage)exchange.getIn()).getMessage().getContent(); // Create in/out artifacts IdentityArtifact in = new IdentityArtifactImpl(new QName(SAMLR11Constants.SAML_PROTOCOL_NS, "ArtifactResolve"), request ); idPlanExchange.setIn(in); IdentityArtifact<ArtifactResponseType> out = new IdentityArtifactImpl<ArtifactResponseType>(new QName(SAMLR2Constants.SAML_PROTOCOL_NS, "ArtifactResponse"), new ArtifactResponseType()); idPlanExchange.setOut(out); // Prepare execution identityPlan.prepare(idPlanExchange); // Perform execution identityPlan.perform(idPlanExchange); if (!idPlanExchange.getStatus().equals(IdentityPlanExecutionStatus.SUCCESS)) { throw new SSOException("Identity plan returned : " + idPlanExchange.getStatus()); } if (idPlanExchange.getOut() == null) throw new SSOException("Plan Exchange OUT must not be null!"); return (ArtifactResponseType) idPlanExchange.getOut().getContent(); } protected MessageQueueManager getArtifactQueueManager() { AbstractSSOMediator mediator = (AbstractSSOMediator) channel.getIdentityMediator(); return mediator.getArtifactQueueManager(); } protected SamlArtifactEncoder getSaml2ArtifactEncoder() { AbstractSSOMediator mediator = (AbstractSSOMediator) channel.getIdentityMediator(); SamlR2HttpArtifactBinding b = (SamlR2HttpArtifactBinding) mediator.getBindingFactory().createBinding(SSOBinding.SAMLR2_ARTIFACT.getValue(), channel); return b.getArtifactEncoder(); } protected SamlArtifactEncoder getSaml11ArtifactEncoder() { AbstractSSOMediator mediator = (AbstractSSOMediator) channel.getIdentityMediator(); SamlR11HttpArtifactBinding b = (SamlR11HttpArtifactBinding) mediator.getBindingFactory().createBinding(SSOBinding.SAMLR11_ARTIFACT.getValue(), channel); return b.getArtifactEncoder(); } }