/*
* 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.sp.producers;
import oasis.names.tc.saml._2_0.metadata.EntityDescriptorType;
import oasis.names.tc.saml._2_0.metadata.IDPSSODescriptorType;
import oasis.names.tc.saml._2_0.metadata.RoleDescriptorType;
import oasis.names.tc.saml._2_0.protocol.LogoutRequestType;
import oasis.names.tc.saml._2_0.protocol.ResponseType;
import oasis.names.tc.saml._2_0.protocol.StatusResponseType;
import org.apache.commons.lang.StringUtils;
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.common.AbstractSSOMediator;
import org.atricore.idbus.capabilities.sso.main.common.producers.SSOProducer;
import org.atricore.idbus.capabilities.sso.main.sp.SPSecurityContext;
import org.atricore.idbus.capabilities.sso.main.sp.SSOSPMediator;
import org.atricore.idbus.capabilities.sso.main.sp.plans.SamlR2SloRequestToSamlR2RespPlan;
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.SSORequestException;
import org.atricore.idbus.capabilities.sso.support.core.SSOResponseException;
import org.atricore.idbus.capabilities.sso.support.core.StatusCode;
import org.atricore.idbus.capabilities.sso.support.core.StatusDetails;
import org.atricore.idbus.capabilities.sso.support.core.encryption.SamlR2Encrypter;
import org.atricore.idbus.capabilities.sso.support.core.signature.SamlR2SignatureException;
import org.atricore.idbus.capabilities.sso.support.core.signature.SamlR2SignatureValidationException;
import org.atricore.idbus.capabilities.sso.support.core.signature.SamlR2Signer;
import org.atricore.idbus.capabilities.sts.main.SecurityTokenEmissionException;
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.auditing.core.ActionOutcome;
import org.atricore.idbus.kernel.main.federation.SubjectNameID;
import org.atricore.idbus.kernel.main.federation.metadata.*;
import org.atricore.idbus.kernel.main.mediation.IdentityMediationException;
import org.atricore.idbus.kernel.main.mediation.MediationMessageImpl;
import org.atricore.idbus.kernel.main.mediation.IdentityMediationFault;
import org.atricore.idbus.kernel.main.mediation.MediationState;
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.mediation.channel.IdPChannel;
import org.atricore.idbus.kernel.main.mediation.provider.FederatedLocalProvider;
import org.atricore.idbus.kernel.main.mediation.provider.FederatedProvider;
import org.atricore.idbus.kernel.main.session.SSOSessionManager;
import org.atricore.idbus.kernel.main.session.exceptions.NoSuchSessionException;
import org.atricore.idbus.kernel.main.util.UUIDGenerator;
import org.atricore.idbus.kernel.planning.*;
import javax.xml.namespace.QName;
import java.util.Properties;
import java.util.Set;
/**
* @author <a href="mailto:sgonzalez@atricore.org">Sebastian Gonzalez Oyuela</a>
* @version $Id: IDPSingleSignOnServiceProducer.java 1246 2009-06-05 20:30:58Z sgonzalez $
*/
public class SingleLogoutProducer extends SSOProducer {
private UUIDGenerator uuidGenerator = new UUIDGenerator();
private static final Log logger = LogFactory.getLog( SingleLogoutProducer.class );
public SingleLogoutProducer( AbstractCamelEndpoint<CamelMediationExchange> endpoint ) throws Exception {
super( endpoint );
}
@Override
protected void doProcess ( CamelMediationExchange exchange) throws Exception {
CamelMediationMessage in = (CamelMediationMessage) exchange.getIn();
logger.debug("Processing SLO Message : " + in.getMessage().getContent());
Object content = in.getMessage().getContent();
// May be used later by HTTP-Redirect binding!
AbstractSSOMediator mediator = (AbstractSSOMediator) channel.getIdentityMediator();
in.getMessage().getState().setAttribute("SAMLR2Signer", mediator.getSigner());
try {
if (content instanceof StatusResponseType) {
// A response to a previous Logout Request
StatusResponseType samlResponse = (StatusResponseType) in.getMessage().getContent();
if (logger.isDebugEnabled())
logger.debug("Received SAML 2.0 SLO Response " + samlResponse.getID());
doProcessStatusResponse(exchange, samlResponse);
} else if (content instanceof LogoutRequestType) {
LogoutRequestType samlSloRequest = (LogoutRequestType) in.getMessage().getContent();
if (logger.isDebugEnabled())
logger.debug("Received SAML 2.0 SLO Request " + samlSloRequest.getID());
doProcessLogoutRequest(exchange, samlSloRequest);
} else {
throw new SSOException("Unsupported message type " + content);
}
} catch (SSORequestException e) {
throw new IdentityMediationFault(
e.getTopLevelStatusCode() != null ? e.getTopLevelStatusCode().getValue() : StatusCode.TOP_RESPONDER.getValue(),
e.getSecondLevelStatusCode() != null ? e.getSecondLevelStatusCode().getValue() : null,
e.getStatusDtails() != null ? e.getStatusDtails().getValue() : StatusDetails.UNKNOWN_REQUEST.getValue(),
e.getErrorDetails() != null ? e.getErrorDetails() : content.getClass().getName(),
e);
} catch (SSOException e) {
throw new IdentityMediationFault(StatusCode.TOP_RESPONDER.getValue(),
null,
StatusDetails.UNKNOWN_REQUEST.getValue(),
content.getClass().getName(),
e);
}
}
protected void doProcessLogoutRequest(CamelMediationExchange exchange, LogoutRequestType sloRequest)
throws Exception {
CamelMediationMessage in = (CamelMediationMessage) exchange.getIn();
SPSecurityContext secCtx =
(SPSecurityContext) in.getMessage().getState().getLocalVariable(getProvider().getName().toUpperCase() + "_SECURITY_CTX");
validateRequest(sloRequest, in.getMessage().getRawContent(), in.getMessage().getState());
CircleOfTrustMemberDescriptor idp = ((FederatedLocalProvider)getProvider()).getCotManager().lookupMemberByAlias(sloRequest.getIssuer().getValue());
if (secCtx == null || !idp.getAlias().equals(secCtx.getIdpAlias())) {
// We're gettingn an SLO from an IDP that is not the one that created the current session, reject the request.
logger.warn("Unexpected SLO Request received from IDP " + sloRequest.getIssuer().getValue());
// TODO : Send status
} else {
Properties auditProps = new Properties();
auditProps.put("idpAlias", secCtx.getIdpAlias());
auditProps.put("idpSession", secCtx.getIdpSsoSession());
Set<SubjectNameID> principals = secCtx.getSubject().getPrincipals(SubjectNameID.class);
SubjectNameID principal = null;
if (principals.size() == 1) {
principal = principals.iterator().next();
}
recordInfoAuditTrail("SP-SLOR", ActionOutcome.SUCCESS, principal != null ? principal.getName() : null, exchange, auditProps);
SSOSessionManager sessionMgr = ((IdPChannel)channel).getSessionManager();
try {
sessionMgr.invalidate(secCtx.getSessionIndex());
} catch (NoSuchSessionException e) {
logger.debug("Session already invalidated " + secCtx.getSessionIndex());
}
secCtx.clear();
in.getMessage().getState().removeLocalVariable(getProvider().getName().toUpperCase() + "_SECURITY_CTX");
}
EndpointDescriptor destination = resolveIdPSloEndpoint(idp.getAlias(),
new SSOBinding[] {SSOBinding.asEnum(endpoint.getBinding()) },
true);
ResponseType samlResponse = buildSamlSloResponse(exchange, sloRequest, idp, destination);
logger.debug("Sending SAML SLO Response to " + destination);
CamelMediationMessage out = (CamelMediationMessage) exchange.getOut();
out.setMessage(new MediationMessageImpl(samlResponse.getID(),
samlResponse, "LogoutResponse", in.getMessage().getRelayState(), destination, in.getMessage().getState()));
exchange.setOut(out);
}
protected ResponseType buildSamlSloResponse(CamelMediationExchange exchange,
LogoutRequestType sloRequest,
CircleOfTrustMemberDescriptor sp, EndpointDescriptor spEndpoint) throws Exception {
// Build sloresponse
IdentityPlan identityPlan = findIdentityPlanOfType(SamlR2SloRequestToSamlR2RespPlan.class);
IdentityPlanExecutionExchange idPlanExchange = createIdentityPlanExecutionExchange();
// Publish SP springmetadata
idPlanExchange.setProperty(VAR_DESTINATION_COT_MEMBER, sp);
idPlanExchange.setProperty(VAR_DESTINATION_ENDPOINT_DESCRIPTOR, spEndpoint);
idPlanExchange.setProperty(VAR_REQUEST, sloRequest);
// Create in/out artifacts
IdentityArtifact<LogoutRequestType> in =
new IdentityArtifactImpl<LogoutRequestType>(new QName(SAMLR2Constants.SAML_PROTOCOL_NS, "LogoutRequest"),
sloRequest);
idPlanExchange.setIn(in);
IdentityArtifact<ResponseType> out =
new IdentityArtifactImpl<ResponseType>(new QName(SAMLR2Constants.SAML_PROTOCOL_NS, "Response"),
new ResponseType());
idPlanExchange.setOut(out);
// Prepare execution
identityPlan.prepare(idPlanExchange);
// Perform execution
identityPlan.perform(idPlanExchange);
if (!idPlanExchange.getStatus().equals(IdentityPlanExecutionStatus.SUCCESS)) {
throw new SecurityTokenEmissionException("Identity plan returned : " + idPlanExchange.getStatus());
}
if (idPlanExchange.getOut() == null)
throw new SecurityTokenEmissionException("Plan Exchange OUT must not be null!");
return (ResponseType) idPlanExchange.getOut().getContent();
}
protected void doProcessStatusResponse(CamelMediationExchange exchange, StatusResponseType samlResponse)
throws Exception {
CamelMediationMessage in = (CamelMediationMessage) exchange.getIn();
// Received SSO request from binding, we're responding to this.
SPInitiatedLogoutRequestType ssoLogoutRequest = (SPInitiatedLogoutRequestType)
in.getMessage().getState().getLocalVariable("urn:org:atricore:idbus:sso:protocol:SPInitiatedLogoutRequest");
in.getMessage().getState().removeLocalVariable("urn:org:atricore:idbus:sso:protocol:SPInitiatedLogoutRequest");
// Security Context
SPSecurityContext secCtx =
(SPSecurityContext) in.getMessage().getState().getLocalVariable(getProvider().getName().toUpperCase() + "_SECURITY_CTX");
in.getMessage().getState().removeLocalVariable(getProvider().getName().toUpperCase() + "_SECURITY_CTX");
LogoutRequestType logoutRequest = (LogoutRequestType)
in.getMessage().getState().getLocalVariable("urn:oasis:names:tc:SAML:2.0:protocol:LogoutRequest");
in.getMessage().getState().removeLocalVariable("urn:oasis:names:tc:SAML:2.0:protocol:LogoutRequest");
// Validate received Response
validateSLOResponse(logoutRequest, (StatusResponseType) in.getMessage().getContent(),
in.getMessage().getRawContent(),
in.getMessage().getState());
// Received SAML2 Response from IdP
// TODO : Use plans ?
SSOResponseType ssoResponse = new SSOResponseType();
ssoResponse.setID(uuidGenerator.generateId());
ssoResponse.setIssuer(getProvider().getName());
String destinationLocation = ((SSOSPMediator) channel.getIdentityMediator()).getSpBindingSLO();
EndpointDescriptor destination =
new EndpointDescriptorImpl("EmbeddedSPAcs",
"SingleLogoutService",
SSOBinding.SSO_ARTIFACT.getValue(),
destinationLocation, null);
if (ssoLogoutRequest != null) {
if (logger.isDebugEnabled())
logger.debug("SLO Response in reply to " + ssoLogoutRequest.getID());
ssoResponse.setInReplayTo(ssoLogoutRequest.getID());
if (ssoLogoutRequest.getReplyTo() != null) {
if (logger.isDebugEnabled())
logger.debug("Using requested reply destination : " + ssoLogoutRequest.getReplyTo());
destination = new EndpointDescriptorImpl("EmbeddedSPAcs",
"SingleLogoutService",
SSOBinding.SSO_ARTIFACT.getValue(),
ssoLogoutRequest.getReplyTo(), null);
}
}
// Only destroy the security context if present
if (secCtx != null)
destroySPSecurityContext(exchange, secCtx);
logger.debug("Sending JOSSO SLO Response to " + destination);
CamelMediationMessage out = (CamelMediationMessage) exchange.getOut();
out.setMessage(new MediationMessageImpl(ssoResponse.getID(),
ssoResponse, "SPLogoutResponse", null, destination, in.getMessage().getState()));
exchange.setOut(out);
}
// TODO : Reuse basic SAML request validations ....
protected void validateRequest(LogoutRequestType request, String originalRequest, MediationState state)
throws SSORequestException, SSOException {
SSOSPMediator mediator = (SSOSPMediator) channel.getIdentityMediator();
SamlR2Signer signer = mediator.getSigner();
SamlR2Encrypter encrypter = mediator.getEncrypter();
// Metadata from the IDP
String idpAlias = null;
IDPSSODescriptorType idpMd = null;
try {
idpAlias = request.getIssuer().getValue();
MetadataEntry md = getCotManager().findEntityMetadata(idpAlias);
EntityDescriptorType saml2Md = (EntityDescriptorType) md.getEntry();
boolean found = false;
for (RoleDescriptorType roleMd : saml2Md.getRoleDescriptorOrIDPSSODescriptorOrSPSSODescriptor()) {
if (roleMd instanceof IDPSSODescriptorType) {
idpMd = (IDPSSODescriptorType) roleMd;
}
}
} catch (CircleOfTrustManagerException e) {
throw new SSORequestException(request,
StatusCode.TOP_RESPONDER,
StatusCode.NO_SUPPORTED_IDP,
null,
request.getIssuer().getValue(),
e);
}
// XML Signature, saml2 core, section 5
if (mediator.isValidateRequestsSignature()) {
if (!endpoint.getBinding().equals(SSOBinding.SAMLR2_REDIRECT.getValue())) {
// If no signature is present, throw an exception!
if (request.getSignature() == null)
throw new SSORequestException(request,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_REQUEST_SIGNATURE);
try {
if (originalRequest != null)
signer.validateDom(idpMd, originalRequest);
else
signer.validate(idpMd, request);
} catch (SamlR2SignatureValidationException e) {
throw new SSORequestException(request,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_RESPONSE_SIGNATURE, e);
} catch (SamlR2SignatureException e) {
//other exceptions like JAXB, xml parser...
throw new SSORequestException(request,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_RESPONSE_SIGNATURE, e);
}
} else {
// HTTP-Redirect binding signature validation !
try {
signer.validateQueryString(idpMd,
state.getTransientVariable("SAMLRequest"),
state.getTransientVariable("RelayState"),
state.getTransientVariable("SigAlg"),
state.getTransientVariable("Signature"),
false);
} catch (SamlR2SignatureValidationException e) {
throw new SSORequestException(request,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_RESPONSE_SIGNATURE, e);
} catch (SamlR2SignatureException e) {
//other exceptions like JAXB, xml parser...
throw new SSORequestException(request,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_RESPONSE_SIGNATURE, e);
}
}
}
}
// TODO : Reuse basic SAML response validations ....
protected StatusResponseType validateSLOResponse(LogoutRequestType request,
StatusResponseType response,
String originalResponse,
MediationState state)
throws SSOResponseException, SSOException {
SSOSPMediator mediator = (SSOSPMediator) channel.getIdentityMediator();
SamlR2Signer signer = mediator.getSigner();
SamlR2Encrypter encrypter = mediator.getEncrypter();
// Metadata from the IDP
String idpAlias = null;
IDPSSODescriptorType idpMd = null;
try {
idpAlias = response.getIssuer().getValue();
MetadataEntry md = getCotManager().findEntityMetadata(idpAlias);
EntityDescriptorType saml2Md = (EntityDescriptorType) md.getEntry();
boolean found = false;
for (RoleDescriptorType roleMd : saml2Md.getRoleDescriptorOrIDPSSODescriptorOrSPSSODescriptor()) {
if (roleMd instanceof IDPSSODescriptorType) {
idpMd = (IDPSSODescriptorType) roleMd;
}
}
} catch (CircleOfTrustManagerException e) {
throw new SSOResponseException(response,
StatusCode.TOP_RESPONDER,
StatusCode.NO_SUPPORTED_IDP,
null,
response.getIssuer().getValue(),
e);
}
// Request can be null for IDP initiated SSO
EndpointDescriptor endpointDesc;
try {
endpointDesc = channel.getIdentityMediator().resolveEndpoint(channel, endpoint);
} catch (IdentityMediationException e1) {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.RESOURCE_NOT_RECOGNIZED,
StatusDetails.INTERNAL_ERROR,
"Cannot resolve endpoint descriptor", e1);
}
// --------------------------------------------------------
// Validate response:
// --------------------------------------------------------
// Destination
//saml2 binding, sections 3.4.5.2 & 3.5.5.2
if(response.getDestination() != null) {
//saml2 core, section 3.2.2
String location = endpointDesc.getResponseLocation();
if (location ==null)
location = endpointDesc.getLocation();
if(!response.getDestination().equals(location)){
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_DESTINATION);
}
} else if(response.getSignature() != null &&
(!endpointDesc.getBinding().equals(SSOBinding.SAMLR2_LOCAL.getValue()) &&
!endpointDesc.getBinding().equals(SSOBinding.SAMLR2_ARTIFACT.getValue()))) {
// Local and Artifact bindings don't require signature
// If message is signed, the destination is mandatory!
//saml2 binding, sections 3.4.5.2 & 3.5.5.2
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.NO_DESTINATION);
}
// IssueInstant
/*
- required
- check that the response time is not before request time (use UTC)
- check that time difference is not bigger than X
*/
if(response.getIssueInstant() == null){
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.INVALID_ATTR_NAME_OR_VALUE,
StatusDetails.NO_ISSUE_INSTANT);
} else if(request != null) {
long responseIssueInstant = response.getIssueInstant().toGregorianCalendar().getTimeInMillis();
long requestIssueInstant = request.getIssueInstant().toGregorianCalendar().getTimeInMillis();
long tolerance = mediator.getTimestampValidationTolerance();
// You can't have a request emitted before 'tolerance' millisenconds
if(responseIssueInstant - requestIssueInstant <= tolerance * -1) {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.INVALID_ATTR_NAME_OR_VALUE,
StatusDetails.INVALID_ISSUE_INSTANT,
response.getIssueInstant().toGregorianCalendar().toString() +
" earlier than request issue instant.");
} else {
long ttl = mediator.getRequestTimeToLive();
long res = response.getIssueInstant().toGregorianCalendar().getTime().getTime();
long req = request.getIssueInstant().toGregorianCalendar().getTime().getTime();
if (logger.isDebugEnabled())
logger.debug("TTL : " + res + " - " + req + " = " + (res - req));
// If 0, response does not expires!
if(ttl > 0 && response.getIssueInstant().toGregorianCalendar().getTime().getTime()
- request.getIssueInstant().toGregorianCalendar().getTime().getTime() > ttl) {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.INVALID_ATTR_NAME_OR_VALUE,
StatusDetails.INVALID_ISSUE_INSTANT,
response.getIssueInstant().toGregorianCalendar().toString() +
" expired after " + ttl + "ms");
}
}
}
// Version, saml2 core, section 3.2.2
if(response.getVersion() == null) {
throw new SSOResponseException(response,
StatusCode.TOP_VERSION_MISSMATCH,
null,
StatusDetails.INVALID_VERSION);
}
if (!response.getVersion().equals(SAML_VERSION)){
throw new SSOResponseException(response,
StatusCode.TOP_VERSION_MISSMATCH,
null, // TODO : Check version!
StatusDetails.UNSUPPORTED_VERSION,
response.getVersion());
}
// InResponseTo, saml2 core, section 3.2.2
// Request can be null for IDP initiated SSO
if(request != null) {
if (response.getInResponseTo() == null) {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
null,
StatusDetails.NO_IN_RESPONSE_TO);
} else if (!request.getID().equals(response.getInResponseTo())) {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
null,
StatusDetails.INVALID_RESPONSE_ID,
request.getID() + "/ " + response.getInResponseTo());
}
if (state.getTransientVariable("RelayState") == null ||
!state.getTransientVariable("RelayState").equals(state.getLocalState().getId())) {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
null,
StatusDetails.INVALID_RELAY_STATE,
state.getLocalState().getId() + "/ " + state.getTransientVariable("RelayState"));
}
}
// Status.StatusDetails
if(response.getStatus() != null) {
if(response.getStatus().getStatusCode() != null) {
if(StringUtils.isEmpty(response.getStatus().getStatusCode().getValue())
|| !isStatusCodeValid(response.getStatus().getStatusCode().getValue())){
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.INVALID_ATTR_NAME_OR_VALUE,
StatusDetails.INVALID_STATUS_CODE,
response.getStatus().getStatusCode().getValue());
}
} else {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.INVALID_ATTR_NAME_OR_VALUE,
StatusDetails.NO_STATUS_CODE);
}
} else {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.INVALID_ATTR_NAME_OR_VALUE,
StatusDetails.NO_STATUS);
}
// XML Signature, saml2 core, section 5 (always validate response signature)
// If no signature is present, throw an exception!
// What to do with artifact and SOAP bindings ?!
if (!endpoint.getBinding().equals(SSOBinding.SAMLR2_REDIRECT.getValue()) &&
!endpoint.getBinding().equals(SSOBinding.SAMLR2_LOCAL.getValue())) {
if (response.getSignature() == null) {
// Disable this for non-saml compliant IdPs
if (mediator.isWantSLOResponseSigned()) {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_RESPONSE_SIGNATURE);
}
} else {
try {
if (originalResponse != null)
signer.validateDom(idpMd, originalResponse);
else
signer.validate(idpMd, response, "LogoutResponse");
} catch (SamlR2SignatureValidationException e) {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_RESPONSE_SIGNATURE, e);
} catch (SamlR2SignatureException e) {
//other exceptions like JAXB, xml parser...
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_RESPONSE_SIGNATURE, e);
}
}
} else {
// HTTP-Redirect binding signature validation !
try {
// Only validate SLO Response signature if required
if (mediator.isWantSLOResponseSigned())
signer.validateQueryString(idpMd,
state.getTransientVariable("SAMLResponse"),
state.getTransientVariable("RelayState"),
state.getTransientVariable("SigAlg"),
state.getTransientVariable("Signature"),
true);
} catch (SamlR2SignatureValidationException e) {
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_RESPONSE_SIGNATURE, e);
} catch (SamlR2SignatureException e) {
//other exceptions like JAXB, xml parser...
throw new SSOResponseException(response,
StatusCode.TOP_REQUESTER,
StatusCode.REQUEST_DENIED,
StatusDetails.INVALID_RESPONSE_SIGNATURE, e);
}
}
return response;
}
protected void destroySPSecurityContext(CamelMediationExchange exchange,
SPSecurityContext secCtx) throws SSOException {
CircleOfTrustMemberDescriptor idp = getCotManager().lookupMemberByAlias(secCtx.getIdpAlias());
IdPChannel idpChannel = (IdPChannel) resolveIdpChannel(idp);
SSOSessionManager ssoSessionManager = idpChannel.getSessionManager();
try {
ssoSessionManager.invalidate(secCtx.getSessionIndex());
secCtx.clear();
CamelMediationMessage in = (CamelMediationMessage) exchange.getIn();
in.getMessage().getState().removeRemoteVariable(getProvider().getName().toUpperCase() + "_SECURITY_CTX");
} catch (NoSuchSessionException e) {
logger.debug("SSO Session already invalidated " + secCtx.getSessionIndex());
} catch (Exception e) {
throw new SSOException(e);
}
}
/**
* @return
*/
protected FederationChannel resolveIdpChannel(CircleOfTrustMemberDescriptor idpDescriptor) {
// Resolve IdP channel, then look for the ACS endpoint
FederatedLocalProvider sp = (FederatedLocalProvider)getProvider();
FederationChannel idpChannel = sp.getChannel();
for (FederationChannel fChannel : sp.getChannels()) {
FederatedProvider idp = fChannel.getTargetProvider();
for (CircleOfTrustMemberDescriptor member : idp.getMembers()) {
if (member.getAlias().equals(idpDescriptor.getAlias())) {
if (logger.isDebugEnabled())
logger.debug("Selected IdP channel " + fChannel.getName() + " for provider " + idp.getName());
idpChannel = fChannel;
break;
}
}
}
return idpChannel;
}
}