2 * Copyright 2001-2005 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * shib-ccache.cpp -- SHAR Credential Cache
20 * Originally from mod_shib
21 * Modified by: Derek Atkins <derek@ihtfp.com>
32 #include <shib/shib-threads.h>
34 #include <log4cpp/Category.hh>
39 #ifdef HAVE_LIBDMALLOCXX
44 using namespace log4cpp;
46 using namespace shibboleth;
47 using namespace shibtarget;
49 static const XMLCh cleanupInterval[] =
50 { chLatin_c, chLatin_l, chLatin_e, chLatin_a, chLatin_n, chLatin_u, chLatin_p,
51 chLatin_I, chLatin_n, chLatin_t, chLatin_e, chLatin_r, chLatin_v, chLatin_a, chLatin_l, chNull
53 static const XMLCh cacheTimeout[] =
54 { chLatin_c, chLatin_a, chLatin_c, chLatin_h, chLatin_e,
55 chLatin_T, chLatin_i, chLatin_m, chLatin_e, chLatin_o, chLatin_u, chLatin_t, chNull
57 static const XMLCh AAConnectTimeout[] =
58 { chLatin_A, chLatin_A, chLatin_C, chLatin_o, chLatin_n, chLatin_n, chLatin_e, chLatin_c, chLatin_t,
59 chLatin_T, chLatin_i, chLatin_m, chLatin_e, chLatin_o, chLatin_u, chLatin_t, chNull
61 static const XMLCh AATimeout[] =
62 { chLatin_A, chLatin_A, chLatin_T, chLatin_i, chLatin_m, chLatin_e, chLatin_o, chLatin_u, chLatin_t, chNull };
64 static const XMLCh defaultLifetime[] =
65 { chLatin_d, chLatin_e, chLatin_f, chLatin_a, chLatin_u, chLatin_l, chLatin_t,
66 chLatin_L, chLatin_i, chLatin_f, chLatin_e, chLatin_t, chLatin_i, chLatin_m, chLatin_e, chNull
68 static const XMLCh retryInterval[] =
69 { chLatin_r, chLatin_e, chLatin_t, chLatin_r, chLatin_y,
70 chLatin_I, chLatin_n, chLatin_t, chLatin_e, chLatin_r, chLatin_v, chLatin_a, chLatin_l, chNull
72 static const XMLCh strictValidity[] =
73 { chLatin_s, chLatin_t, chLatin_r, chLatin_i, chLatin_c, chLatin_t,
74 chLatin_V, chLatin_a, chLatin_l, chLatin_i, chLatin_d, chLatin_i, chLatin_t, chLatin_y, chNull
76 static const XMLCh propagateErrors[] =
77 { chLatin_p, chLatin_r, chLatin_o, chLatin_p, chLatin_a, chLatin_g, chLatin_a, chLatin_t, chLatin_e,
78 chLatin_E, chLatin_r, chLatin_r, chLatin_o, chLatin_r, chLatin_s, chNull
82 class InternalCCacheEntry : public ISessionCacheEntry
86 InternalCCache* cache,
88 const IApplication* application,
89 const char* client_addr,
91 const char* providerId,
92 SAMLAuthenticationStatement* s,
94 const IRoleDescriptor* source=NULL,
98 ~InternalCCacheEntry();
100 void lock() { m_lock->lock(); }
101 void unlock() { m_lock->unlock(); }
103 bool isValid(time_t lifetime, time_t timeout) const;
104 const char* getClientAddress() const { return m_clientAddress.c_str(); }
105 ShibProfile getProfile() const { return m_profile; }
106 const char* getProviderId() const { return m_provider_id.c_str(); }
107 const SAMLAuthenticationStatement* getAuthnStatement() const { return m_auth_statement; }
108 CachedResponse getResponse();
110 time_t lastAccess() const { return m_lastAccess; }
112 bool checkApplication(const IApplication* application) { return (m_application_id==application->getId()); }
115 void populate(); // wraps process of checking cache, and repopulating if need be
116 bool responseValid(); // checks validity of existing response
117 pair<SAMLResponse*,SAMLResponse*> getNewResponse(); // wraps an actual query
119 SAMLResponse* filter(SAMLResponse* r, const IApplication* application, const IRoleDescriptor* source);
122 string m_application_id;
123 string m_provider_id;
124 string m_clientAddress;
125 time_t m_sessionCreated;
126 time_t m_responseCreated;
127 mutable time_t m_lastAccess;
130 ShibProfile m_profile;
131 SAMLAuthenticationStatement* m_auth_statement;
132 SAMLResponse* m_response_pre;
133 SAMLResponse* m_response_post;
134 InternalCCache *m_cache;
139 class InternalCCache : public ISessionCache
142 InternalCCache(const DOMElement* e);
143 virtual ~InternalCCache();
145 void thread_init() {};
146 void thread_end() {};
148 string generateKey() const;
149 ISessionCacheEntry* find(const char* key, const IApplication* application);
152 const IApplication* application,
153 const char* client_addr,
155 const char* providerId,
156 SAMLAuthenticationStatement* s,
157 SAMLResponse* r=NULL,
158 const IRoleDescriptor* source=NULL,
162 void remove(const char* key);
164 InternalCCacheEntry* findi(const char* key);
168 const DOMElement* m_root; // Only valid during initialization
170 map<string,InternalCCacheEntry*> m_hashtable;
172 log4cpp::Category* log;
174 static void* cleanup_fcn(void*); // Assumes an InternalCCache
176 CondWait* shutdown_wait;
177 Thread* cleanup_thread;
179 // extracted config settings
180 unsigned int m_AATimeout,m_AAConnectTimeout;
181 unsigned int m_defaultLifetime,m_retryInterval;
182 bool m_strictValidity,m_propagateErrors;
183 friend class InternalCCacheEntry;
186 IPlugIn* MemoryCacheFactory(const DOMElement* e)
188 return new InternalCCache(e);
191 /******************************************************************************/
192 /* InternalCCache: in memory session cache */
193 /******************************************************************************/
195 InternalCCache::InternalCCache(const DOMElement* e)
196 : m_root(e), lock(RWLock::create()), log(&Category::getInstance(SHIBT_LOGCAT".SessionCache")),
197 m_AATimeout(30), m_AAConnectTimeout(15), m_defaultLifetime(1800), m_retryInterval(300),
198 m_strictValidity(true), m_propagateErrors(false)
201 const XMLCh* tag=m_root->getAttributeNS(NULL,AATimeout);
203 m_AATimeout = XMLString::parseInt(tag);
207 SAMLConfig::getConfig().timeout = m_AATimeout;
209 tag=m_root->getAttributeNS(NULL,AAConnectTimeout);
211 m_AAConnectTimeout = XMLString::parseInt(tag);
212 if (!m_AAConnectTimeout)
213 m_AAConnectTimeout=15;
215 SAMLConfig::getConfig().conn_timeout = m_AAConnectTimeout;
217 tag=m_root->getAttributeNS(NULL,defaultLifetime);
219 m_defaultLifetime = XMLString::parseInt(tag);
220 if (!m_defaultLifetime)
221 m_defaultLifetime=1800;
224 tag=m_root->getAttributeNS(NULL,retryInterval);
226 m_retryInterval = XMLString::parseInt(tag);
227 if (!m_retryInterval)
231 tag=m_root->getAttributeNS(NULL,strictValidity);
232 if (tag && (*tag==chDigit_0 || *tag==chLatin_f))
233 m_strictValidity=false;
235 tag=m_root->getAttributeNS(NULL,propagateErrors);
236 if (tag && (*tag==chDigit_1 || *tag==chLatin_t))
237 m_propagateErrors=true;
239 shutdown_wait = CondWait::create();
241 cleanup_thread = Thread::create(&cleanup_fcn, (void*)this);
244 InternalCCache::~InternalCCache()
246 // Shut down the cleanup thread and let it know...
248 shutdown_wait->signal();
249 cleanup_thread->join(NULL);
251 for (map<string,InternalCCacheEntry*>::iterator i=m_hashtable.begin(); i!=m_hashtable.end(); i++)
254 delete shutdown_wait;
257 string InternalCCache::generateKey() const
264 // assumes a lock is held..
265 InternalCCacheEntry* InternalCCache::findi(const char* key)
267 map<string,InternalCCacheEntry*>::const_iterator i=m_hashtable.find(key);
268 if (i==m_hashtable.end()) {
269 log->debug("No match found");
272 log->debug("Match found");
277 ISessionCacheEntry* InternalCCache::find(const char* key, const IApplication* application)
279 log->debug("searching memory cache for key (%s)", key);
280 ReadLock rwlock(lock);
282 InternalCCacheEntry* entry = findi(key);
285 else if (!entry->checkApplication(application)) {
286 log->crit("An application (%s) attempted to access another application's session!", application->getId());
290 // Lock the "database record" for the caller -- they have to unlock the item.
295 void InternalCCache::insert(
297 const IApplication* application,
298 const char* client_addr,
300 const char* providerId,
301 SAMLAuthenticationStatement* s,
303 const IRoleDescriptor* source,
308 log->debug("caching new entry for application %s: \"%s\"", application->getId(), key);
310 InternalCCacheEntry* entry = new InternalCCacheEntry(
325 m_hashtable[key]=entry;
329 // remove the entry from the database and then destroy the cacheentry
330 void InternalCCache::remove(const char* key)
332 log->debug("removing cache entry with key (%s)", key);
334 // lock the cache for writing, which means we know nobody is sitting in find()
337 // grab the entry from the database.
338 ISessionCacheEntry* entry = findi(key);
345 // ok, remove the entry and lock it
346 m_hashtable.erase(key);
347 dynamic_cast<InternalCCacheEntry*>(entry)->lock();
350 // we can release the entry lock because we know we're not in the cache anymore
353 // Now delete the entry
357 void InternalCCache::cleanup()
360 saml::NDC ndc("cleanup()");
364 int timeout_life = 0;
365 Mutex* mutex = Mutex::create();
367 // Load our configuration details...
368 const XMLCh* tag=m_root->getAttributeNS(NULL,cleanupInterval);
370 rerun_timer = XMLString::parseInt(tag);
372 tag=m_root->getAttributeNS(NULL,cacheTimeout);
374 timeout_life = XMLString::parseInt(tag);
376 if (rerun_timer <= 0)
377 rerun_timer = 300; // rerun every 5 minutes
379 if (timeout_life <= 0)
380 timeout_life = 28800; // timeout after 8 hours
384 log->info("Cleanup thread started... Run every %d secs; timeout after %d secs",
385 rerun_timer, timeout_life);
387 while (shutdown == false) {
388 shutdown_wait->timedwait(mutex,rerun_timer);
390 if (shutdown == true)
393 log->debug("Cleanup thread running...");
395 // Ok, let's run through the cleanup process and clean out
396 // really old sessions. This is a two-pass process. The
397 // first pass is done holding a read-lock while we iterate over
398 // the database. The second pass doesn't need a lock because
399 // the 'deletes' will lock the database.
401 // Pass 1: iterate over the map and find all entries that have not been
403 vector<string> stale_keys;
404 time_t stale = time(NULL) - timeout_life;
407 for (map<string,InternalCCacheEntry*>::iterator i=m_hashtable.begin();
408 i != m_hashtable.end(); i++)
410 // If the last access was BEFORE the stale timeout...
412 time_t last=i->second->lastAccess();
415 stale_keys.push_back(i->first);
419 log->info("deleting %d old items.", stale_keys.size());
421 // Pass 2: walk through the list of stale entries and remove them from
423 for (vector<string>::iterator j = stale_keys.begin(); j != stale_keys.end(); j++) {
425 // Transaction Logging
426 STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
427 stc.getTransactionLog().infoStream() << "Purged expired session from memory (ID: " << j->c_str() << ")";
428 stc.releaseTransactionLog();
432 log->info("Cleanup thread finished.");
439 void* InternalCCache::cleanup_fcn(void* cache_p)
441 InternalCCache* cache = reinterpret_cast<InternalCCache*>(cache_p);
443 // First, let's block all signals
444 Thread::mask_all_signals();
446 // Now run the cleanup process.
451 /******************************************************************************/
452 /* InternalCCacheEntry: A Credential Cache Entry */
453 /******************************************************************************/
455 InternalCCacheEntry::InternalCCacheEntry(
456 InternalCCache* cache,
458 const IApplication* application,
459 const char* client_addr,
461 const char* providerId,
462 SAMLAuthenticationStatement* s,
464 const IRoleDescriptor* source,
467 ) : m_application_id(application->getId()), m_responseCreated(r ? time(NULL) : 0), m_lastRetry(0),
468 m_profile(profile), m_auth_statement(s), m_response_pre(r), m_response_post(NULL), m_cache(cache)
470 if (!cache || !key || !s || !client_addr || !providerId) {
471 if (cache) cache->log->error("missing required cache entry details");
472 throw SAMLException("InternalCCacheEntry() missing required cache entry details");
476 m_clientAddress = client_addr;
477 m_provider_id = providerId;
478 m_sessionCreated = (created==0) ? time(NULL) : created;
479 m_lastAccess = (accessed==0) ? time(NULL) : accessed;
481 // If pushing attributes, filter the response.
483 m_cache->log->debug("filtering pushed attribute information");
484 m_response_post=filter(r, application, source);
487 m_lock = Mutex::create();
489 m_cache->log->info("new session created with session ID (%s)", key);
490 if (m_cache->log->isDebugEnabled()) {
491 auto_ptr_char h(s->getSubject()->getNameIdentifier()->getName());
492 m_cache->log->debug("NameID (%s), IdP (%s), Address (%s)", h.get(), providerId, client_addr);
496 InternalCCacheEntry::~InternalCCacheEntry()
498 m_cache->log->debug("deleting session (ID: %s)", m_id.c_str());
499 delete m_response_pre;
500 delete m_response_post;
501 delete m_auth_statement;
505 bool InternalCCacheEntry::isValid(time_t lifetime, time_t timeout) const
508 saml::NDC ndc("isValid");
511 m_cache->log->debug("testing session (ID: %s) (lifetime=%ld, timeout=%ld)",
512 m_id.c_str(), lifetime, timeout);
514 time_t now=time(NULL);
515 if (lifetime > 0 && now > m_sessionCreated+lifetime) {
516 m_cache->log->info("session beyond lifetime (ID: %s)", m_id.c_str());
520 if (timeout > 0 && now-m_lastAccess >= timeout) {
521 m_cache->log->info("session timed out (ID: %s)", m_id.c_str());
528 ISessionCacheEntry::CachedResponse InternalCCacheEntry::getResponse()
531 saml::NDC ndc("getResponse");
534 return CachedResponse(m_response_pre,m_response_post);
537 bool InternalCCacheEntry::responseValid()
540 saml::NDC ndc("responseValid");
542 m_cache->log->debug("checking validity of attribute assertions");
543 time_t now=time(NULL) - SAMLConfig::getConfig().clock_skew_secs;
546 Iterator<SAMLAssertion*> assertions = m_response_post->getAssertions();
547 while (assertions.hasNext()) {
548 SAMLAssertion* assertion = assertions.next();
550 // Only examine this assertion if it contains an attribute statement.
551 Iterator<SAMLStatement*> statements = assertion->getStatements();
552 while (statements.hasNext()) {
553 if (dynamic_cast<SAMLAttributeStatement*>(statements.next())) {
554 const SAMLDateTime* thistime = assertion->getNotOnOrAfter();
556 // If there is no time, then just continue and ignore this assertion.
561 if (now >= thistime->getEpoch()) {
562 m_cache->log->debug("found an expired attribute assertion, response is invalid");
569 // If we didn't find any assertions with times, then see if we're
570 // older than the default response lifetime.
572 if (abs((int)(now - m_responseCreated)) > m_cache->m_defaultLifetime) {
573 m_cache->log->debug("response is beyond default life, so it's invalid");
578 m_cache->log->debug("response still valid");
582 void InternalCCacheEntry::populate()
585 saml::NDC ndc("populate");
587 m_cache->log->debug("populating attributes for session (ID: %s)", m_id.c_str());
589 // Do we have any data cached?
590 if (m_response_pre) {
591 // Can we use what we have?
595 // If we're being strict, dump what we have and reset timestamps.
596 if (m_cache->m_strictValidity) {
597 m_cache->log->info("strictly enforcing attribute validity, dumping expired data");
598 delete m_response_pre;
599 delete m_response_post;
600 m_response_pre=m_response_post=NULL;
607 pair<SAMLResponse*,SAMLResponse*> new_responses=getNewResponse();
608 if (new_responses.first) {
609 delete m_response_pre;
610 delete m_response_post;
611 m_response_pre=new_responses.first;
612 m_response_post=new_responses.second;
613 m_responseCreated=time(NULL);
615 m_cache->log->debug("fetched and stored new response");
616 STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
617 stc.getTransactionLog().infoStream() << "Successful attribute query for session (ID: " << m_id << ")";
618 stc.releaseTransactionLog();
621 catch (SAMLException&) {
622 if (m_cache->m_propagateErrors)
624 m_cache->log->warn("suppressed SAML exception caught while trying to fetch attributes");
628 if (m_cache->m_propagateErrors)
630 m_cache->log->warn("suppressed unknown exception caught while trying to fetch attributes");
635 pair<SAMLResponse*,SAMLResponse*> InternalCCacheEntry::getNewResponse()
638 saml::NDC ndc("getNewResponse");
641 // The retryInterval determines how often to poll an AA that might be down.
642 time_t now=time(NULL);
643 if ((now - m_lastRetry) < m_cache->m_retryInterval)
644 return pair<SAMLResponse*,SAMLResponse*>(NULL,NULL);
646 m_cache->log->debug("retry interval exceeded, so trying again");
649 m_cache->log->info("trying to get new attributes for session (ID=%s)", m_id.c_str());
651 // Transaction Logging
652 STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
653 stc.getTransactionLog().infoStream() <<
654 "Making attribute query for session (ID: " <<
656 ") on (applicationId: " <<
658 ") for principal from (IdP: " <<
661 stc.releaseTransactionLog();
664 // Caller must be holding the config lock.
665 // Lookup application for session to get providerId and attributes to request.
666 IConfig* conf=ShibTargetConfig::getConfig().getINI();
667 const IApplication* application=conf->getApplication(m_application_id.c_str());
669 m_cache->log->crit("unable to locate application for session, deleted?");
670 throw SAMLException("Unable to locate application for session, deleted?");
672 pair<bool,const XMLCh*> providerID=application->getXMLString("providerId");
673 if (!providerID.first) {
674 m_cache->log->crit("unable to determine ProviderID for application, not set?");
675 throw SAMLException("Unable to determine ProviderID for application, not set?");
679 Metadata m(application->getMetadataProviders());
680 const IEntityDescriptor* site=m.lookup(m_provider_id.c_str());
682 m_cache->log->error("unable to locate identity provider's metadata during attribute query");
683 return pair<SAMLResponse*,SAMLResponse*>(NULL,NULL);
686 // Try to locate an AA role.
688 const IAttributeAuthorityDescriptor* AA=site->getAttributeAuthorityDescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
690 AA=site->getAttributeAuthorityDescriptor(saml::XML::SAML10_PROTOCOL_ENUM);
692 m_cache->log->warn("unable to locate metadata for identity provider's Attribute Authority");
693 return pair<SAMLResponse*,SAMLResponse*>(NULL,NULL);
698 // Get protocol signing policy.
699 const IPropertySet* credUse=application->getCredentialUse(site);
700 pair<bool,bool> signRequest=credUse ? credUse->getBool("signRequest") : make_pair(false,false);
701 pair<bool,const char*> signatureAlg=credUse ? credUse->getString("signatureAlg") : pair<bool,const char*>(false,NULL);
702 if (!signatureAlg.first)
703 signatureAlg.second=URI_ID_RSA_SHA1;
704 pair<bool,const char*> digestAlg=credUse ? credUse->getString("digestAlg") : pair<bool,const char*>(false,NULL);
705 if (!digestAlg.first)
706 digestAlg.second=URI_ID_SHA1;
707 pair<bool,bool> signedResponse=credUse ? credUse->getBool("signedResponse") : make_pair(false,false);
708 pair<bool,const char*> signingCred=credUse ? credUse->getString("Signing") : pair<bool,const char*>(false,NULL);
710 SAMLResponse* response = NULL;
712 // Build a SAML Request....
713 SAMLAttributeQuery* q=new SAMLAttributeQuery(
714 new SAMLSubject(static_cast<SAMLNameIdentifier*>(m_auth_statement->getSubject()->getNameIdentifier()->clone())),
716 application->getAttributeDesignators().clone()
718 auto_ptr<SAMLRequest> req(new SAMLRequest(q));
719 req->setMinorVersion(minorVersion);
721 // Sign it? Highly doubtful we'll ever use this, but just for fun...
722 if (signRequest.first && signRequest.second && signingCred.first) {
723 if (req->getMinorVersion()==1) {
724 Credentials creds(conf->getCredentialsProviders());
725 const ICredResolver* cr=creds.lookup(signingCred.second);
727 req->sign(cr->getKey(),cr->getCertificates(),signatureAlg.second,digestAlg.second);
729 m_cache->log->error("unable to sign attribute query, specified credential (%s) was not found",signingCred.second);
732 m_cache->log->error("unable to sign SAML 1.0 attribute query, only SAML 1.1 defines signing adequately");
735 m_cache->log->debug("trying to query an AA...");
737 // Call context object
738 Trust t(application->getTrustProviders());
739 ShibHTTPHook::ShibHTTPHookCallContext ctx(credUse,AA);
741 // Use metadata to locate endpoints.
742 Iterator<const IEndpoint*> endpoints=AA->getAttributeServiceManager()->getEndpoints();
743 while (!response && endpoints.hasNext()) {
744 const IEndpoint* ep=endpoints.next();
746 // Get a binding object for this protocol.
747 const SAMLBinding* binding = application->getBinding(ep->getBinding());
749 auto_ptr_char prot(ep->getBinding());
750 m_cache->log->warn("skipping binding on unsupported protocol (%s)", prot.get());
753 static const XMLCh https[] = {chLatin_h, chLatin_t, chLatin_t, chLatin_p, chLatin_s, chColon, chNull};
754 auto_ptr<SAMLResponse> r(binding->send(ep->getLocation(), *(req.get()), &ctx));
756 if (!t.validate(*r,AA))
757 throw TrustException("Unable to verify signed response message.");
759 else if (!ctx.isAuthenticated() || XMLString::compareNString(ep->getLocation(),https,6))
760 throw TrustException("Response message was unauthenticated.");
761 response = r.release();
763 catch (SAMLException& e) {
764 m_cache->log->error("caught SAML exception during SAML attribute query: %s", e.what());
765 // Check for shib:InvalidHandle error and propagate it out.
766 Iterator<saml::QName> codes=e.getCodes();
767 if (codes.size()>1) {
768 const saml::QName& code=codes[1];
769 if (!XMLString::compareString(code.getNamespaceURI(),shibboleth::Constants::SHIB_NS) &&
770 !XMLString::compareString(code.getLocalName(), shibboleth::Constants::InvalidHandle)) {
772 throw InvalidHandleException(e.what(),params(),codes);
779 if (signedResponse.first && signedResponse.second && !response->isSigned()) {
781 m_cache->log->error("unsigned response obtained, but we were told it must be signed.");
782 throw TrustException("Unable to obtain a signed response message.");
785 // Run it through the filter.
786 return make_pair(response,filter(response,application,AA));
789 catch (SAMLException& e) {
790 m_cache->log->error("caught SAML exception during query to AA: %s", e.what());
791 annotateException(&e,AA);
794 m_cache->log->error("no response obtained");
795 return pair<SAMLResponse*,SAMLResponse*>(NULL,NULL);
798 SAMLResponse* InternalCCacheEntry::filter(SAMLResponse* r, const IApplication* application, const IRoleDescriptor* source)
800 const IPropertySet* credUse=application->getCredentialUse(source->getEntityDescriptor());
801 pair<bool,bool> signedAssertions=credUse ? credUse->getBool("signedAssertions") : make_pair(false,false);
802 Trust t(application->getTrustProviders());
804 // Examine each original assertion...
805 Iterator<SAMLAssertion*> assertions=r->getAssertions();
806 for (unsigned long i=0; i < assertions.size();) {
807 // Check signing policy.
808 if (signedAssertions.first && signedAssertions.second && !(assertions[i]->isSigned())) {
809 m_cache->log->warn("removing unsigned assertion from response, in accordance with signedAssertions policy");
810 r->removeAssertion(i);
814 // Check any conditions.
816 Iterator<SAMLCondition*> conds=assertions[i]->getConditions();
817 while (conds.hasNext()) {
818 SAMLAudienceRestrictionCondition* cond=dynamic_cast<SAMLAudienceRestrictionCondition*>(conds.next());
819 if (!cond || !cond->eval(application->getAudiences())) {
820 m_cache->log->warn("assertion condition invalid, removing it");
821 r->removeAssertion(i);
829 // Check token signature.
830 if (assertions[i]->isSigned() && !t.validate(*(assertions[i]),source)) {
831 m_cache->log->warn("signed assertion failed to validate, removing it");
832 r->removeAssertion(i);
838 // Make a copy of whatever's left and process that against the AAP.
839 auto_ptr<SAMLResponse> copy(static_cast<SAMLResponse*>(r->clone()));
842 Iterator<SAMLAssertion*> copies=copy->getAssertions();
843 for (unsigned long j=0; j < copies.size();) {
845 // Finally, filter the content.
846 AAP::apply(application->getAAPProviders(),*(copies[j]),source);
850 catch (SAMLException&) {
851 m_cache->log->info("no statements remain after AAP, removing assertion");
852 copy->removeAssertion(j);
856 // Audit the results.
857 STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
858 Category& tran=stc.getTransactionLog();
859 if (tran.isInfoEnabled()) {
861 "Caching the following attributes after AAP applied for session (ID: " <<
863 ") on (applicationId: " <<
865 ") for principal from (IdP: " <<
869 Iterator<SAMLAssertion*> loggies=copy->getAssertions();
870 while (loggies.hasNext()) {
871 SAMLAssertion* logit=loggies.next();
872 Iterator<SAMLStatement*> states=logit->getStatements();
873 while (states.hasNext()) {
874 SAMLAttributeStatement* state=dynamic_cast<SAMLAttributeStatement*>(states.next());
875 Iterator<SAMLAttribute*> attrs=state ? state->getAttributes() : EMPTY(SAMLAttribute*);
876 while (attrs.hasNext()) {
877 SAMLAttribute* attr=attrs.next();
878 auto_ptr_char attrname(attr->getName());
879 tran.infoStream() << "\t" << attrname.get() << " (" << attr->getValues().size() << " values)";
885 stc.releaseTransactionLog();
887 return copy.release();