};
SAML2Logout::SAML2Logout(const DOMElement* e, const char* appId)
- : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".Logout.SAML2"))
+ : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT ".Logout.SAML2"))
#ifndef SHIBSP_LITE
,m_protocol(samlconstants::SAML20P_NS)
#endif
pair<bool,const char*> outgoing = getString("outgoingBindings", m_configNS.get());
if (outgoing.first) {
dupBindings = outgoing.second;
+ trim(dupBindings);
}
else {
// No override, so we'll install a default binding precedence.
// If we get here, it's an external protocol message to decode.
// Locate policy key.
- pair<bool,const char*> policyId = getString("policyId", m_configNS.get()); // namespace-qualified if inside handler element
+ pair<bool,const char*> policyId = getString("policyId", m_configNS.get()); // may be namespace-qualified inside handler element
+ if (!policyId.first)
+ policyId = getString("policyId"); // try unqualified
if (!policyId.first)
policyId = application.getString("policyId"); // unqualified in Application(s) element
}
// Message from IdP to logout one or more sessions.
-
- // If this is front-channel, we have to have a session_id to use already.
- if (m_decoder->isUserAgentPresent() && session_id.empty()) {
- m_log.error("no active session");
- return sendResponse(
- logout_event.get(),
- logoutRequest->getID(),
- StatusCode::REQUESTER, StatusCode::UNKNOWN_PRINCIPAL, "No active session found in request.",
- relayState.c_str(),
- policy->getIssuerMetadata(),
- application,
- response,
- true
- );
- }
+ // Extract the NameID from the request, decrypting it if needed.
scoped_ptr<XMLObject> decryptedID;
NameID* nameid = logoutRequest->getNameID();
// Suck indexes out of the request for next steps.
set<string> indexes;
- EntityDescriptor* entity = policy->getIssuerMetadata() ? dynamic_cast<EntityDescriptor*>(policy->getIssuerMetadata()->getParent()) : nullptr;
+ EntityDescriptor* entity =
+ policy->getIssuerMetadata() ? dynamic_cast<EntityDescriptor*>(policy->getIssuerMetadata()->getParent()) : nullptr;
const vector<SessionIndex*> sindexes = logoutRequest->getSessionIndexs();
for (indirect_iterator<vector<SessionIndex*>::const_iterator> i = make_indirect_iterator(sindexes.begin());
i != make_indirect_iterator(sindexes.end()); ++i) {
}
// For a front-channel LogoutRequest, we have to match the information in the request
- // against the current session.
+ // against the current session, if one is known/available.
if (!session_id.empty()) {
if (!cache->matches(application, request, entity, *nameid, &indexes)) {
return sendResponse(
true
);
}
-
+ }
+ else if (m_decoder->isUserAgentPresent()) {
+ m_log.info("processing front channel logout request with no active session");
}
// Now we perform "logout" by finding the matching sessions.
}
if (m_decoder->isUserAgentPresent()) {
- // Pass control to the first front channel notification point, if any.
- map<string,string> parammap;
- if (!relayState.empty())
- parammap["RelayState"] = relayState;
- auto_ptr_char entityID(entity ? entity->getEntityID() : nullptr);
- if (entityID.get())
- parammap["entityID"] = entityID.get();
- auto_ptr_char reqID(logoutRequest->getID());
- if (reqID.get())
- parammap["ID"] = reqID.get();
- pair<bool,long> result = notifyFrontChannel(application, request, response, ¶mmap);
- if (result.first)
- return result;
- }
-
- // For back-channel requests, or if no front-channel notification is needed...
+ if (!session_id.empty()) {
+ // Pass control to the first front channel notification point, if any.
+ map<string,string> parammap;
+ if (!relayState.empty())
+ parammap["RelayState"] = relayState;
+ auto_ptr_char entityID(entity ? entity->getEntityID() : nullptr);
+ if (entityID.get())
+ parammap["entityID"] = entityID.get();
+ auto_ptr_char reqID(logoutRequest->getID());
+ if (reqID.get())
+ parammap["ID"] = reqID.get();
+ pair<bool,long> result = notifyFrontChannel(application, request, response, ¶mmap);
+ if (result.first)
+ return result;
+ }
+ else {
+ m_log.info("client's session isn't available, skipping front-channel notifications");
+ }
+ }
+
+ // For back-channel requests, or if no front-channel notification is needed or possible...
bool worked1 = notifyBackChannel(application, request.getRequestURL(), sessions, false);
bool worked2 = true;
if (!session_id.empty()) {
if (logoutResponse) {
if (!policy->isAuthenticated()) {
SecurityPolicyException ex("Security of LogoutResponse not established.");
- if (policy->getIssuerMetadata())
- annotateException(&ex, policy->getIssuerMetadata()); // throws it
- ex.raise();
+ annotateException(&ex, policy->getIssuerMetadata()); // throws it
}
if (logout_event) {
}
if (!relayState.empty()) {
- limitRelayState(m_log, application, request, relayState.c_str());
+ application.limitRedirect(request, relayState.c_str());
return make_pair(true, response.sendRedirect(relayState.c_str()));
}
logout->setIssuer(issuer);
issuer->setName(application.getRelyingParty(dynamic_cast<EntityDescriptor*>(role->getParent()))->getXMLString("entityID").second);
fillStatus(*logout, code, subcode, msg);
- logout->setID(SAMLConfig::getConfig().generateIdentifier());
+ XMLCh* msgid = SAMLConfig::getConfig().generateIdentifier();
+ logout->setID(msgid);
+ XMLString::release(&msgid);
logout->setIssueInstant(time(nullptr));
if (logoutEvent) {