/*
* 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.josso.main.producers;
import org.apache.camel.Endpoint;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.atricore.idbus.capabilities.josso.main.*;
import org.atricore.idbus.capabilities.josso.main.binding.JossoBinding;
import org.atricore.idbus.capabilities.sso.support.binding.SSOBinding;
import org.atricore.idbus.capabilities.sso.support.metadata.SSOService;
import org.atricore.idbus.common.sso._1_0.protocol.RequestAttributeType;
import org.atricore.idbus.common.sso._1_0.protocol.SPInitiatedLogoutRequestType;
import org.atricore.idbus.common.sso._1_0.protocol.SSOResponseType;
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.IdentityMediationException;
import org.atricore.idbus.kernel.main.mediation.MediationMessageImpl;
import org.atricore.idbus.kernel.main.mediation.binding.BindingChannel;
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.endpoint.IdentityMediationEndpoint;
import org.atricore.idbus.kernel.main.util.UUIDGenerator;
/**
* @author <a href="mailto:sgonzalez@atricore.org">Sebastian Gonzalez Oyuela</a>
* @version $Id$
*/
public class SingleLogoutProducer extends AbstractJossoProducer {
private static final Log logger = LogFactory.getLog(SingleLogoutProducer.class);
private UUIDGenerator uuidGenerator = new UUIDGenerator();
public SingleLogoutProducer(Endpoint endpoint) {
super(endpoint);
}
protected void doProcess(CamelMediationExchange exchange) throws Exception {
CamelMediationMessage in = (CamelMediationMessage) exchange.getIn();
if (in.getMessage().getContent() instanceof SSOResponseType) {
SSOResponseType res = (SSOResponseType) in.getMessage().getContent();
if (logger.isDebugEnabled())
logger.debug("Processing SLO Response " + res.getID());
doProcessSloResponse(exchange, (SSOResponseType) in.getMessage().getContent());
} else {
if (logger.isDebugEnabled())
logger.debug("Processing JOSSO SLO Request ");
doProcessJossoSloRequest(exchange);
}
}
// TODO : SSOResponse shoulnd't be named sloResponse ?!?!?!?
protected void doProcessSloResponse(CamelMediationExchange exchange, SSOResponseType sloResponse ) {
CamelMediationMessage in = (CamelMediationMessage) exchange.getIn();
// TODO : Validate destination, inReplyTo, etc
String appId = sloResponse.getIssuer().toLowerCase(); // App-id is case-insensitive;
// Process response
PartnerAppMapping mapping = resolveAppMapping((BindingChannel) channel, appId);
String backTo = mapping.getPartnerAppSLO();
if (logger.isDebugEnabled())
logger.debug("Using backTo URL:" + backTo + " received backTo URL ignored");
EndpointDescriptor ed = new EndpointDescriptorImpl(
"SSOLogoutRequest",
"SSOLogoutRequest",
JossoBinding.JOSSO_REDIRECT.getValue(),
backTo,
null);
CamelMediationMessage out = (CamelMediationMessage) exchange.getOut();
out.setMessage(new MediationMessageImpl(null,
null,
"AuthenticationAssertion",
null,
ed,
in.getMessage().getState()));
exchange.setOut(out);
in.getMessage().getState().removeLocalVariable("urn:org:atricore:idbus:capabilities:josso:authnCtx:" + appId);
}
protected void doProcessJossoSloRequest(CamelMediationExchange exchange) throws IdentityMediationException, JossoException {
CamelMediationMessage in = (CamelMediationMessage) exchange.getIn();
BindingChannel bChannel = (BindingChannel) channel;
String appId = in.getMessage().getState().getTransientVariable(JossoConstants.JOSSO_APPID_VAR).toLowerCase(); // App-id is case-insensitive
String backTo = in.getMessage().getState().getTransientVariable(JossoConstants.JOSSO_BACK_TO_VAR);
// This producer just redirects the user to the configured target IDP.
BindingChannel spBinding = resolveSpBindingChannel(bChannel, appId);
EndpointDescriptor destination = resolveSPInitiatedSSOEndpointDescriptor(exchange, spBinding);
// Create SP AuthnRequest
// TODO : Support on_error ?
SPInitiatedLogoutRequestType request = buildSLORequest(exchange);
// Store state
JossoAuthnContext authnCtx = (JossoAuthnContext) in.getMessage().getState().getLocalVariable("urn:org:atricore:idbus:capabilities:josso:authnCtx:" + appId);
if (authnCtx == null) {
// Logout already done or session expired, send the user back to the application:
PartnerAppMapping mapping = resolveAppMapping((BindingChannel) channel, appId);
backTo = mapping.getPartnerAppSLO();
if (logger.isDebugEnabled())
logger.debug("Using backTo URL:" + backTo + " received backTo URL ignored");
EndpointDescriptor ed = new EndpointDescriptorImpl(
"SSOLogoutRequest",
"SSOLogoutRequest",
JossoBinding.JOSSO_REDIRECT.getValue(),
backTo,
null);
CamelMediationMessage out = (CamelMediationMessage) exchange.getOut();
out.setMessage(new MediationMessageImpl(null,
null,
"AuthenticationAssertion",
null,
ed,
in.getMessage().getState()));
exchange.setOut(out);
in.getMessage().getState().removeLocalVariable("urn:org:atricore:idbus:capabilities:josso:authnCtx:" + appId);
return;
}
authnCtx.setSloBackTo(backTo);
authnCtx.setSloRequest(request);
authnCtx.setAppId(appId);
CamelMediationMessage out = (CamelMediationMessage) exchange.getOut();
out.setMessage(new MediationMessageImpl(request.getID(),
request,
"SSOLogoutRequest",
null,
destination,
in.getMessage().getState()));
exchange.setOut(out);
in.getMessage().getState().setLocalVariable("urn:org:atricore:idbus:capabilities:josso:authnCtx:" + appId, authnCtx);
}
protected EndpointDescriptor resolveSPInitiatedSSOEndpointDescriptor(CamelMediationExchange exchange, BindingChannel idP) throws JossoException {
try {
logger.debug("Looking for " + SSOService.SPInitiatedSingleLogoutService.toString());
for (IdentityMediationEndpoint endpoint : idP.getEndpoints()) {
logger.debug("Processing endpoint : " + endpoint.getType() + "["+endpoint.getBinding()+"]");
if (endpoint.getType().equals(SSOService.SPInitiatedSingleLogoutService.toString())) {
if (endpoint.getBinding().equals(SSOBinding.SSO_ARTIFACT.getValue())) {
// This is the endpoint we're looking for
return idP.getIdentityMediator().resolveEndpoint(idP, endpoint);
}
}
}
} catch (IdentityMediationException e) {
throw new JossoException(e);
}
throw new JossoException("No SP endpoint found for SP Initiated SLO using JOSSO Artifact binding");
}
protected SPInitiatedLogoutRequestType buildSLORequest(CamelMediationExchange exchange) throws IdentityMediationException {
SPInitiatedLogoutRequestType req = new SPInitiatedLogoutRequestType();
req.setID(uuidGenerator.generateId());
JossoMediator mediator = ((JossoMediator)(channel).getIdentityMediator());
for (IdentityMediationEndpoint endpoint : channel.getEndpoints()) {
if (endpoint.getType().equals(JossoService.SingleLogoutService.toString())) {
if (endpoint.getBinding().equals(JossoBinding.SSO_ARTIFACT.getValue())) {
EndpointDescriptor ed = mediator.resolveEndpoint(channel, endpoint);
req.setReplyTo(ed.getResponseLocation() != null ? ed.getResponseLocation() : ed.getLocation());
if (logger.isDebugEnabled())
logger.debug("SLORequest.Reply-To:" + req.getReplyTo());
}
}
}
CamelMediationMessage in = (CamelMediationMessage) exchange.getIn();
// Send all transient vars to SP
for (String tvarName : in.getMessage().getState().getTransientVarNames()) {
RequestAttributeType a = new RequestAttributeType ();
a.setName(tvarName);
a.setValue(in.getMessage().getState().getTransientVariable(tvarName));
req.getRequestAttribute().add(a);
}
return req;
}
}