bool isValid(time_t lifetime, time_t timeout) const;
const char* getClientAddress() const { return m_clientAddress.c_str(); }
- const char* getSerializedStatement() const { return m_statement.c_str(); }
- const SAMLAuthenticationStatement* getStatement() const { return p_auth; }
-
+ const SAMLAuthenticationStatement* getAuthnStatement() const { return p_auth; }
Iterator<SAMLAssertion*> getAssertions();
- void preFetch(int prefetch_window);
void setCache(InternalCCache *cache) { m_cache = cache; }
time_t lastAccess() const { return m_lastAccess; }
bool checkApplication(const IApplication* application) { return (m_application_id==application->getId()); }
private:
- bool responseValid(int slop);
- void populate(int slop);
- SAMLResponse* getNewResponse();
+ void populate(); // wraps process of checking cache, and repopulating if need be
+ bool responseValid(); // checks validity of existing response
+ SAMLResponse* getNewResponse(); // wraps an actual query
+
+ void filter(SAMLResponse* r, const IApplication* application, const IRoleDescriptor* source);
string m_id;
string m_application_id;
- string m_statement;
string m_originSite;
string m_clientAddress;
time_t m_sessionCreated;
/******************************************************************************/
InternalCCacheEntry::InternalCCacheEntry(
- const char* id, const IApplication* application, SAMLAuthenticationStatement *s, const char* client_addr, SAMLResponse* r, const IRoleDescriptor* source
+ const char* id,
+ const IApplication* application,
+ SAMLAuthenticationStatement *s,
+ const char* client_addr,
+ SAMLResponse* r,
+ const IRoleDescriptor* source
) : m_response(r), m_responseCreated(r ? time(NULL) : 0), m_lastRetry(0),
log(&Category::getInstance("shibtarget::InternalCCacheEntry"))
{
// Save for later.
p_auth = s;
- // Save the serialized version of the auth statement
- ostringstream os;
- os << *s;
- m_statement = os.str();
-
- if (r) {
- // Run pushed data through the AAP. Note that we could end up with an empty response!
- Iterator<SAMLAssertion*> assertions=r->getAssertions();
- for (unsigned long i=0; i < assertions.size();) {
- try {
- AAP::apply(application->getAAPProviders(),*(assertions[i]),source);
- i++;
- }
- catch (SAMLException&) {
- log->info("no statements remain, removing assertion");
- r->removeAssertion(i);
- }
- }
- }
+ // If pushing attributes, filter the response.
+ if (r)
+ filter(r, application, source);
m_lock = Mutex::create();
bool InternalCCacheEntry::isValid(time_t lifetime, time_t timeout) const
{
+#ifdef _DEBUG
saml::NDC ndc("isValid");
- log->debug("testing session (ID: %s) (lifetime=%ld, timeout=%ld)", m_id.c_str(), lifetime, timeout);
+#endif
+
+ log->debug("testing session (ID: %s) (lifetime=%ld, timeout=%ld)",
+ m_id.c_str(), lifetime, timeout);
+
time_t now=time(NULL);
if (lifetime > 0 && now > m_sessionCreated+lifetime) {
- log->debug("session beyond lifetime (ID: %s)", m_id.c_str());
+ log->info("session beyond lifetime (ID: %s)", m_id.c_str());
return false;
}
if (timeout > 0 && now-m_lastAccess >= timeout) {
- log->debug("session timed out (ID: %s)", m_id.c_str());
+ log->info("session timed out (ID: %s)", m_id.c_str());
return false;
}
m_lastAccess=now;
Iterator<SAMLAssertion*> InternalCCacheEntry::getAssertions()
{
+#ifdef _DEBUG
saml::NDC ndc("getAssertions");
- populate(0);
+#endif
+ populate();
return (m_response) ? m_response->getAssertions() : EMPTY(SAMLAssertion*);
}
-void InternalCCacheEntry::preFetch(int prefetch_window)
-{
- saml::NDC ndc("preFetch");
- populate(prefetch_window);
-}
-
-bool InternalCCacheEntry::responseValid(int slop)
+bool InternalCCacheEntry::responseValid()
{
+#ifdef _DEBUG
saml::NDC ndc("responseValid");
-
- log->debug("checking AA response validity");
+#endif
+ log->debug("checking attribute data validity");
+ time_t now=time(NULL) - SAMLConfig::getConfig().clock_skew_secs;
int count = 0;
Iterator<SAMLAssertion*> iter = m_response->getAssertions();
count++;
- if (time(NULL)+slop >= thistime->getEpoch()) {
+ if (now >= thistime->getEpoch()) {
log->debug("nope, not still valid");
return false;
}
// If we didn't find any assertions with times, then see if we're
// older than the default response lifetime.
if (!count) {
- if ((time(NULL)+slop - m_responseCreated) > m_cache->m_defaultLifetime) {
+ if ((now - m_responseCreated) > m_cache->m_defaultLifetime) {
log->debug("response is beyond default life, so it's invalid");
return false;
}
return true;
}
-void InternalCCacheEntry::populate(int slop)
+void InternalCCacheEntry::populate()
{
+#ifdef _DEBUG
saml::NDC ndc("populate");
+#endif
log->debug("populating attributes for session (ID: %s)", m_id.c_str());
// Do we have any data cached?
if (m_response) {
// Can we use what we have?
- if (responseValid(slop))
+ if (responseValid())
return;
// If we're being strict, dump what we have and reset timestamps.
}
}
- // Need to try and get a new response.
-
try {
-
// Transaction Logging
STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
stc.getTransactionLog().infoStream() <<
SAMLResponse* InternalCCacheEntry::getNewResponse()
{
+#ifdef _DEBUG
saml::NDC ndc("getNewResponse");
+#endif
// The retryInterval determines how often to poll an AA that might be down.
- if ((time(NULL) - m_lastRetry) < m_cache->m_retryInterval)
+ time_t now=time(NULL);
+ if ((now - m_lastRetry) < m_cache->m_retryInterval)
return NULL;
if (m_lastRetry)
log->debug("retry interval exceeded, so trying again");
- m_lastRetry=time(NULL);
+ m_lastRetry=now;
log->info("trying to get new attributes for session (ID=%s)", m_id.c_str());
throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to determine ProviderID for application, not set?");
}
- // Get signing policies.
+ // Get protocol signing policy.
pair<bool,bool> signRequest=application->getBool("signRequest");
pair<bool,bool> signedResponse=application->getBool("signedResponse");
- pair<bool,bool> signedAssertions=application->getBool("signedAssertions");
// Try this request. The binding wrapper class handles most of the details.
Metadata m(application->getMetadataProviders());
throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to locate metadata for identity provider's Attribute Authority.",site);
}
-
SAMLResponse* response = NULL;
try {
// Build a SAML Request....
bindconf.conn_timeout=m_cache->m_AAConnectTimeout;
ShibBinding binding(application->getRevocationProviders(),application->getTrustProviders(),conf->getCredentialsProviders());
response=binding.send(*req,AA,application->getTLSCred(site),application->getAudiences(),p_auth->getBindings(),bindconf);
+
+ if (signedResponse.first && signedResponse.second && !response->isSigned()) {
+ delete response;
+ response=NULL;
+ log->error("unsigned response obtained, but we were told it must be signed.");
+ }
+ else {
+ // Run it through the filter. Note that we could end up with an empty response.
+ filter(response,application,AA);
+ }
}
catch (SAMLException& e) {
log->error("caught SAML exception during query to AA: %s", e.what());
// See if we got a response.
if (!response) {
log->error("no response obtained");
- throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to obtain attributes from user's origin site.",AA);
- }
- else if (signedResponse.first && signedResponse.second && !response->isSigned()) {
- delete response;
- log->error("unsigned response obtained, but we were told it must be signed.");
- throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to obtain attributes from user's origin site.",AA);
+ throw ShibTargetException(SHIBRPC_INTERNAL_ERROR,"Unable to obtain attributes from user's identity provider.",AA);
}
+ return response;
+}
+
+void InternalCCacheEntry::filter(SAMLResponse* r, const IApplication* application, const IRoleDescriptor* source)
+{
+ Trust t(application->getTrustProviders());
+ pair<bool,bool> signedAssertions=application->getBool("signedAssertions");
- // Run it through the AAP. Note that we could end up with an empty response!
- Iterator<SAMLAssertion*> a=response->getAssertions();
- for (unsigned long i=0; i < a.size();) {
+ // Examine each new assertion...
+ Iterator<SAMLAssertion*> assertions=r->getAssertions();
+ for (unsigned long i=0; i < assertions.size();) {
try {
- if (signedAssertions.first && signedAssertions.second && !(a[i]->isSigned())) {
+ // Check signing policy.
+ if (signedAssertions.first && signedAssertions.second && !(assertions[i]->isSigned())) {
log->warn("removing unsigned assertion from response, in accordance with signedAssertions policy");
- response->removeAssertion(i);
+ r->removeAssertion(i);
continue;
}
- AAP::apply(application->getAAPProviders(),*(a[i]),AA);
+
+ // Check any conditions.
+ bool pruned=false;
+ Iterator<SAMLCondition*> conds=assertions[i]->getConditions();
+ while (conds.hasNext()) {
+ SAMLAudienceRestrictionCondition* cond=dynamic_cast<SAMLAudienceRestrictionCondition*>(conds.next());
+ if (!cond || !cond->eval(application->getAudiences())) {
+ log->warn("assertion condition invalid, removing it");
+ r->removeAssertion(i);
+ pruned=true;
+ break;
+ }
+ }
+ if (pruned)
+ continue;
+
+ // Check token signature.
+ if (assertions[i]->isSigned() && !t.validate(application->getRevocationProviders(),source,*(assertions[i]))) {
+ log->warn("signed assertion failed to validate, removing it");
+ r->removeAssertion(i);
+ continue;
+ }
+
+ // Finally, filter the content.
+ AAP::apply(application->getAAPProviders(),*(assertions[i]),source);
i++;
}
catch (SAMLException&) {
- log->info("no statements remain, removing assertion");
- response->removeAssertion(i);
+ log->info("no statements remain after AAP, removing assertion");
+ r->removeAssertion(i);
}
}
-
- return response;
}