/*
- * Copyright 2001-2005 Internet2
+ * Copyright 2001-2009 Internet2
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <xercesc/framework/MemBufInputSource.hpp>
using namespace std;
-using namespace log4cpp;
using namespace saml;
using namespace shibboleth;
using namespace shibtarget;
using namespace adfs;
+using namespace adfs::logging;
namespace {
class ADFSListener : public virtual IListener
if (e) {
e=saml::XML::getFirstChildElement(e,saml::XML::SAML_NS,L(Assertion));
if (e) {
- auto_ptr<SAMLAssertion> assertion(new SAMLAssertion(e));
+
+ // Wrap the assertion DOM in a dummy samlp:Response for subsequent processing.
+ // We have to manually create the Response DOM first in order to avoid
+ // corrupting the namespace declarations in the Assertion.
+
+ static const XMLCh One[]={chDigit_1, chNull};
+ static const XMLCh dummyID[] = {chLatin_A, chLatin_D, chLatin_F, chLatin_S, chNull};
+ static const XMLCh samlp_Success[]=
+ { chLatin_s, chLatin_a, chLatin_m, chLatin_l, chLatin_p, chColon,
+ chLatin_S, chLatin_u, chLatin_c, chLatin_c, chLatin_e, chLatin_s, chLatin_s, chNull };
+ DOMElement* rdom=rdoc->createElementNS(saml::XML::SAMLP_NS,L(Response));
+ rdom->setAttributeNS(saml::XML::XMLNS_NS,L_QNAME(xmlns,samlp),saml::XML::SAMLP_NS);
+ rdom->setAttributeNS(saml::XML::XMLNS_NS,L(xmlns),saml::XML::SAMLP_NS);
+ rdom->setAttributeNS(NULL,L(MajorVersion),One);
+ rdom->setAttributeNS(NULL,L(MinorVersion),One);
+ rdom->setAttributeNS(NULL,L(ResponseID),dummyID);
+ SAMLDateTime issued(time(NULL));
+ issued.parseDateTime();
+ rdom->setAttributeNS(NULL,L(IssueInstant),issued.getRawData());
+ DOMElement* status=rdoc->createElementNS(saml::XML::SAMLP_NS,L(Status));
+ rdom->appendChild(status);
+ DOMElement* code=rdoc->createElementNS(saml::XML::SAMLP_NS,L(StatusCode));
+ code->setAttributeNS(NULL,L(Value),samlp_Success);
+ status->appendChild(code);
+ rdom->appendChild(e); // append the assertion
+ auto_ptr<SAMLResponse> response(new SAMLResponse(rdom));
+ response->setDocument(rdoc); // give the Document to the response object
+ // root the response in the document so the signature will verify
+ rdoc->replaceChild(response->toDOM(rdoc,false),rdoc->getDocumentElement());
+ rdoc=NULL;
// Try and map to metadata.
+ SAMLAssertion* assertion=response->getAssertions().next();
const IEntityDescriptor* provider=m.lookup(assertion->getIssuer());
if (provider)
role=provider->getIDPSSODescriptor(adfs::XML::WSFED_NS);
try {
// Check over the assertion.
- SAMLAuthenticationStatement* authnStatement=checkAssertionProfile(assertion.get());
+ SAMLAuthenticationStatement* authnStatement=checkAssertionProfile(assertion);
if (!checkReplay.first || checkReplay.second) {
auto_ptr_char id(assertion->getId());
// Check signature.
log->debug("passing signed ADFS assertion to trust layer");
Trust t(app->getTrustProviders());
- if (!t.validate(*(assertion.get()),role)) {
- log->error("unable to verify signed authentication assertion");
+ if (!t.validate(*assertion,role)) {
+ log->error("unable to verify signed ADFS assertion");
throw TrustException("unable to verify signed authentication assertion");
}
-
- // Wrap the assertion in a dummy samlp:Response for subsequent processing.
- // Generate the Response DOM using the assertion's document and then
- // transfer ownership of the tree to the Response.
- auto_ptr<SAMLResponse> response(new SAMLResponse());
- response->addAssertion(assertion.release());
- response->toDOM(rdoc);
- response->setDocument(rdoc);
- rdoc=NULL;
+ log->info("verified digital signature over ADFS assertion");
// Now dummy up the SAML profile response wrapper.
param=parser.get_value("wctx");
bpr.TARGET=param;
bpr.profile=SAMLBrowserProfile::Post; // not really, but...
bpr.response=response.release();
- bpr.assertion=response->getAssertions().next();
+ bpr.assertion=assertion;
bpr.authnStatement=authnStatement;
}
catch (SAMLException& ex) {
const XMLCh* wip = bpr.authnStatement->getSubjectIP();
if (wip && *wip) {
// Verify the client address matches authentication
- auto_ptr_char this_ip(ip);
+ auto_ptr_char this_ip(wip);
if (strcmp(ip, this_ip.get())) {
FatalProfileException ex(
SESSION_E_ADDRESSMISMATCH,
}
// It passes all our tests -- create a new session.
- log->info("creating new session");
// Are attributes present?
bool attributesPushed=false;
}
auto_ptr_char oname(role->getEntityDescriptor()->getId());
- auto_ptr_char hname(bpr.authnStatement->getSubject()->getNameIdentifier()->getName());
+ auto_ptr_char hname(
+ bpr.authnStatement->getSubject()->getNameIdentifier() ?
+ bpr.authnStatement->getSubject()->getNameIdentifier()->getName() :
+ NULL
+ );
try {
// Create a new session key.
log->debug("new session id: %s", cookie.c_str());
// Transaction Logging
- Category::getInstance(SHIBTRAN_LOGCAT).infoStream() <<
+ FixedContextCategory tranLog(SHIBTRAN_LOGCAT);
+ tranLog.infoStream() <<
"New session (ID: " <<
cookie <<
") with (applicationId: " <<
") at (ClientAddress: " <<
ip <<
") with (NameIdentifier: " <<
- hname.get() <<
+ (hname.get() ? hname.get() : "none") <<
")";
//stc.releaseTransactionLog();
}
ISessionCacheEntry** pentry
) const
{
-#ifdef _DEBUG
- saml::NDC ndc("sessionGet");
-#endif
-
- *pentry=NULL;
- log->debug("checking for session: %s@%s", cookie, ip);
-
- // See if the session exists...
-
- ShibTargetConfig& stc=ShibTargetConfig::getConfig();
- IConfig* conf=stc.getINI();
- log->debug("application: %s", app->getId());
-
- bool checkIPAddress=true;
- int lifetime=0,timeout=0;
- const IPropertySet* props=app->getPropertySet("Sessions");
- if (props) {
- pair<bool,unsigned int> p=props->getUnsignedInt("lifetime");
- if (p.first)
- lifetime = p.second;
- p=props->getUnsignedInt("timeout");
- if (p.first)
- timeout = p.second;
- pair<bool,bool> pcheck=props->getBool("checkAddress");
- if (pcheck.first)
- checkIPAddress = pcheck.second;
- }
-
- *pentry = conf->getSessionCache()->find(cookie,app);
-
- // If not, leave now..
- if (!*pentry) {
- log->debug("session not found");
- throw InvalidSessionException("No session exists for key value ($session_id)",namedparams(1,"session_id",cookie));
- }
-
- // TEST the session...
- try {
- // Verify the address is the same
- if (checkIPAddress) {
- log->debug("Checking address against %s", (*pentry)->getClientAddress());
- if (strcmp(ip, (*pentry)->getClientAddress())) {
- log->debug("client address mismatch");
- InvalidSessionException ex(
- SESSION_E_ADDRESSMISMATCH,
- "Your IP address (%1) does not match the address recorded at the time the session was established.",
- params(1,ip)
- );
- Metadata m(app->getMetadataProviders());
- annotateException(&ex,m.lookup((*pentry)->getProviderId())); // throws it
- }
- }
-
- // and that the session is still valid...
- if (!(*pentry)->isValid(lifetime,timeout)) {
- log->debug("session expired");
- InvalidSessionException ex(SESSION_E_EXPIRED, "Your session has expired, and you must re-authenticate.");
- Metadata m(app->getMetadataProviders());
- annotateException(&ex,m.lookup((*pentry)->getProviderId())); // throws it
- }
- }
- catch (SAMLException&) {
- (*pentry)->unlock();
- *pentry=NULL;
- conf->getSessionCache()->remove(cookie);
-
- // Transaction Logging
- Category::getInstance(SHIBTRAN_LOGCAT).infoStream() <<
- "Destroyed invalid session (ID: " <<
- cookie <<
- ") with (applicationId: " <<
- app->getId() <<
- "), request was from (ClientAddress: " <<
- ip <<
- ")";
- //stc.releaseTransactionLog();
- throw;
- }
- catch (...) {
- log->error("caught unknown exception");
-#ifndef _DEBUG
- InvalidSessionException ex("An unexpected error occurred while validating your session, and you must re-authenticate.");
- Metadata m(app->getMetadataProviders());
- annotateException(&ex,m.lookup((*pentry)->getProviderId()),false);
-#endif
- (*pentry)->unlock();
- *pentry=NULL;
- conf->getSessionCache()->remove(cookie);
-
- // Transaction Logging
- Category::getInstance(SHIBTRAN_LOGCAT).infoStream() <<
- "Destroyed invalid session (ID: " <<
- cookie <<
- ") with (applicationId: " <<
- app->getId() <<
- "), request was from (ClientAddress: " <<
- ip <<
- ")";
- //stc.releaseTransactionLog();
-#ifdef _DEBUG
- throw;
-#else
- ex.raise();
-#endif
- }
-
- log->debug("session ok");
+ g_MemoryListener->sessionGet(app,cookie,ip,pentry);
}
void ADFSListener::sessionEnd(
const char* cookie
) const
{
-#ifdef _DEBUG
- saml::NDC ndc("sessionEnd");
-#endif
-
- log->debug("removing session: %s", cookie);
-
- ShibTargetConfig& stc=ShibTargetConfig::getConfig();
- stc.getINI()->getSessionCache()->remove(cookie);
-
- // Transaction Logging
- Category::getInstance(SHIBTRAN_LOGCAT).infoStream() << "Destroyed session (ID: " << cookie << ")";
- //stc.releaseTransactionLog();
+ g_MemoryListener->sessionEnd(application,cookie);
}
void ADFSListener::ping(int& i) const
{
- i++;
+ g_MemoryListener->ping(i);
}