/* * Atricore IDBus * * Copyright (c) 2009, Atricore Inc. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.atricore.idbus.capabilities.sso.main.binding; import oasis.names.tc.saml._2_0.protocol.RequestAbstractType; import oasis.names.tc.saml._2_0.wsdl.SAMLRequestPortType; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.cxf.message.MessageContentsList; import org.atricore.idbus.capabilities.sso.support.SAMLR2MessagingConstants; import org.atricore.idbus.capabilities.sso.support.binding.SSOBinding; import org.atricore.idbus.kernel.main.federation.metadata.EndpointDescriptor; import org.atricore.idbus.kernel.main.mediation.*; import org.atricore.idbus.kernel.main.mediation.camel.component.binding.AbstractMediationSoapBinding; 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.state.LocalState; import org.atricore.idbus.kernel.main.mediation.state.ProviderStateContext; import javax.xml.ws.Service; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; /** * This endpoint can only consume, producing to this endpoint is unsupported. * * @author <a href="mailto:sgonzalez@atricore.org">Sebastian Gonzalez Oyuela</a> * @version $Id$ */ public class SamlR2SoapBinding extends AbstractMediationSoapBinding { private static final Log logger = LogFactory.getLog(SamlR2SoapBinding.class); public SamlR2SoapBinding(Channel channel) { super(SSOBinding.SAMLR2_SOAP.getValue(), channel); } public MediationMessage createMessage(CamelMediationMessage message) { // Get HTTP Exchange from SAML Exchange CamelMediationExchange samlR2exchange = message.getExchange(); Exchange exchange = samlR2exchange.getExchange(); logger.debug("Create Message Body from exchange " + exchange.getClass().getName()); // Converting from CXF Message to SAMLR2 Message // Is this a CXF message? Message in = exchange.getIn(); if (in.getBody() instanceof MessageContentsList) { MessageContentsList mclIn = (MessageContentsList) in.getBody() ; logger.debug("Using CXF Message Content : " + mclIn.get(0)); MediationMessage body; LocalState lState = null; MediationState state = null; if (mclIn.get(0) instanceof RequestAbstractType) { // Process Saml Request in SOAP Channel // Try to restore provider state based on sessionIndex RequestAbstractType samlReq = (RequestAbstractType) mclIn.get(0); try { Method getSessionIndex = samlReq.getClass().getMethod("getSessionIndex"); List<String> sessionIndexes = (List<String>) getSessionIndex.invoke(samlReq); if (sessionIndexes != null) { if (sessionIndexes.size() > 0) { String sessionIndex = sessionIndexes.get(0); ProviderStateContext ctx = createProviderStateContext(); // Add retries just in case we're in a cluster (they are disabled in non HA setups) int retryCount = getRetryCount(); if (retryCount > 0) { lState = ctx.retrieve("idpSsoSessionId", sessionIndex, retryCount, getRetryDelay()); } else { lState = ctx.retrieve("idpSsoSessionId", sessionIndex); } if (logger.isDebugEnabled()) logger.debug("Local state was" + (lState == null ? " NOT" : "") + " retrieved for ssoSessionId " + sessionIndex); } } } catch (NoSuchMethodException e) { // Ignore this ... if (logger.isTraceEnabled()) logger.trace("SAML Request does not have session index : " + e.getMessage()); } catch (InvocationTargetException e) { logger.error("Cannot recover local state : " + e.getMessage(), e); } catch (IllegalAccessException e) { logger.error("Cannot recover local state : " + e.getMessage(), e); } } if (lState == null) { // Create a new local state instance ? state = createMediationState(exchange); } else { state = new MediationStateImpl(lState); } // Process Saml Response in SOAP Channel body = new MediationMessageImpl( in.getMessageId(), mclIn.get(0), null, null, null, state); return body; } else { throw new IllegalArgumentException("Unknown message type " + in.getBody()); } } @Override public Object sendMessage(MediationMessage message) throws IdentityMediationException { if (logger.isTraceEnabled()) logger.trace("Sending new SAML 2.0 message using SOAP Binding"); EndpointDescriptor endpoint = message.getDestination(); String soapEndpoint = endpoint.getLocation(); // --------------------------------------------------------- // Setup CXF Client // --------------------------------------------------------- Service service = Service.create(SAMLR2MessagingConstants.SERVICE_NAME); service.addPort(SAMLR2MessagingConstants.PORT_NAME, javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING, endpoint.getLocation()); Object content = message.getContent(); if (!(content instanceof RequestAbstractType )) { throw new IdentityMediationException("Unsupported content " + content); } String soapMethodName = content.getClass().getSimpleName(); soapMethodName = "saml" + soapMethodName.substring(0, soapMethodName.length() - 4); // Remove Type if (logger.isTraceEnabled()) logger.trace("Using soap method ["+soapMethodName+"]"); SAMLRequestPortType port = service.getPort(SAMLR2MessagingConstants.PORT_NAME, SAMLRequestPortType.class); if (logger.isTraceEnabled()) logger.trace("Sending SSO SOAP Request: " + content); try { Method soapMethod = port.getClass().getMethod(soapMethodName, content.getClass()); Object o = soapMethod.invoke(port, content); if (logger.isTraceEnabled()) logger.trace("Received SSO SOAP Response: " + o); return o; } catch (NoSuchMethodException e) { throw new IdentityMediationException("SOAP Method not impelmented " + soapMethodName + ": " + e.getMessage(), e); } catch (Exception e) { throw new IdentityMediationException("SOAP error: " + e.getMessage(), e); } } }