Extend attribute resolution to include authn statement.
authorScott Cantor <cantor.2@osu.edu>
Tue, 27 Sep 2011 21:49:18 +0000 (21:49 +0000)
committerScott Cantor <cantor.2@osu.edu>
Tue, 27 Sep 2011 21:49:18 +0000 (21:49 +0000)
adfs/adfs.cpp
shibsp/handler/AssertionConsumerService.h
shibsp/handler/impl/AssertionConsumerService.cpp
shibsp/handler/impl/SAML1Consumer.cpp
shibsp/handler/impl/SAML2Consumer.cpp

index c49ec99..e14330c 100644 (file)
@@ -639,8 +639,10 @@ void ADFSConsumer::implementProtocol(
     if (!policy.isAuthenticated())
         throw SecurityPolicyException("Unable to establish security of incoming assertion.");
 
-    saml1::NameIdentifier* saml1name=nullptr;
+    const saml1::NameIdentifier* saml1name=nullptr;
+    const saml1::AuthenticationStatement* saml1statement=nullptr;
     saml2::NameID* saml2name=nullptr;
+    const saml2::AuthnStatement* saml2statement=nullptr;
     const XMLCh* authMethod=nullptr;
     const XMLCh* authInstant=nullptr;
     time_t now = time(nullptr), sessionExp = 0;
@@ -657,13 +659,13 @@ void ADFSConsumer::implementProtocol(
         // authnskew allows rejection of SSO if AuthnInstant is too old.
         pair<bool,unsigned int> authnskew = sessionProps ? sessionProps->getUnsignedInt("maxTimeSinceAuthn") : pair<bool,unsigned int>(false,0);
 
-        const saml1::AuthenticationStatement* ssoStatement=saml1token->getAuthenticationStatements().front();
-        if (ssoStatement->getAuthenticationInstant()) {
-            if (ssoStatement->getAuthenticationInstantEpoch() - XMLToolingConfig::getConfig().clock_skew_secs > now) {
+        saml1statement = saml1token->getAuthenticationStatements().front();
+        if (saml1statement->getAuthenticationInstant()) {
+            if (saml1statement->getAuthenticationInstantEpoch() - XMLToolingConfig::getConfig().clock_skew_secs > now) {
                 throw FatalProfileException("The login time at your identity provider was future-dated.");
             }
-            else if (authnskew.first && authnskew.second && ssoStatement->getAuthenticationInstantEpoch() <= now &&
-                    (now - ssoStatement->getAuthenticationInstantEpoch() > authnskew.second)) {
+            else if (authnskew.first && authnskew.second && saml1statement->getAuthenticationInstantEpoch() <= now &&
+                    (now - saml1statement->getAuthenticationInstantEpoch() > authnskew.second)) {
                 throw FatalProfileException("The gap between now and the time you logged into your identity provider exceeds the allowed limit.");
             }
         }
@@ -672,16 +674,16 @@ void ADFSConsumer::implementProtocol(
         }
 
         // Address checking.
-        saml1::SubjectLocality* locality = ssoStatement->getSubjectLocality();
+        saml1::SubjectLocality* locality = saml1statement->getSubjectLocality();
         if (locality && locality->getIPAddress()) {
             auto_ptr_char ip(locality->getIPAddress());
             checkAddress(application, httpRequest, ip.get());
         }
 
-        saml1name = ssoStatement->getSubject()->getNameIdentifier();
-        authMethod = ssoStatement->getAuthenticationMethod();
-        if (ssoStatement->getAuthenticationInstant())
-            authInstant = ssoStatement->getAuthenticationInstant()->getRawData();
+        saml1name = saml1statement->getSubject()->getNameIdentifier();
+        authMethod = saml1statement->getAuthenticationMethod();
+        if (saml1statement->getAuthenticationInstant())
+            authInstant = saml1statement->getAuthenticationInstant()->getRawData();
 
         // Session expiration.
         pair<bool,unsigned int> lifetime = sessionProps ? sessionProps->getUnsignedInt("lifetime") : pair<bool,unsigned int>(true,28800);
@@ -703,26 +705,26 @@ void ADFSConsumer::implementProtocol(
         // authnskew allows rejection of SSO if AuthnInstant is too old.
         pair<bool,unsigned int> authnskew = sessionProps ? sessionProps->getUnsignedInt("maxTimeSinceAuthn") : pair<bool,unsigned int>(false,0);
 
-        const saml2::AuthnStatement* ssoStatement=saml2token->getAuthnStatements().front();
+        saml2statement = saml2token->getAuthnStatements().front();
         if (authnskew.first && authnskew.second &&
-                ssoStatement->getAuthnInstant() && (now - ssoStatement->getAuthnInstantEpoch() > authnskew.second))
+                saml2statement->getAuthnInstant() && (now - saml2statement->getAuthnInstantEpoch() > authnskew.second))
             throw FatalProfileException("The gap between now and the time you logged into your identity provider exceeds the limit.");
 
         // Address checking.
-        saml2::SubjectLocality* locality = ssoStatement->getSubjectLocality();
+        saml2::SubjectLocality* locality = saml2statement->getSubjectLocality();
         if (locality && locality->getAddress()) {
             auto_ptr_char ip(locality->getAddress());
             checkAddress(application, httpRequest, ip.get());
         }
 
         saml2name = saml2token->getSubject() ? saml2token->getSubject()->getNameID() : nullptr;
-        if (ssoStatement->getAuthnContext() && ssoStatement->getAuthnContext()->getAuthnContextClassRef())
-            authMethod = ssoStatement->getAuthnContext()->getAuthnContextClassRef()->getReference();
-        if (ssoStatement->getAuthnInstant())
-            authInstant = ssoStatement->getAuthnInstant()->getRawData();
+        if (saml2statement->getAuthnContext() && saml2statement->getAuthnContext()->getAuthnContextClassRef())
+            authMethod = saml2statement->getAuthnContext()->getAuthnContextClassRef()->getReference();
+        if (saml2statement->getAuthnInstant())
+            authInstant = saml2statement->getAuthnInstant()->getRawData();
 
         // Session expiration for SAML 2.0 is jointly IdP- and SP-driven.
-        sessionExp = ssoStatement->getSessionNotOnOrAfter() ? ssoStatement->getSessionNotOnOrAfterEpoch() : 0;
+        sessionExp = saml2statement->getSessionNotOnOrAfter() ? saml2statement->getSessionNotOnOrAfterEpoch() : 0;
         pair<bool,unsigned int> lifetime = sessionProps ? sessionProps->getUnsignedInt("lifetime") : pair<bool,unsigned int>(true,28800);
         if (!lifetime.first || lifetime.second == 0)
             lifetime.second = 28800;
@@ -753,7 +755,9 @@ void ADFSConsumer::implementProtocol(
             policy.getIssuerMetadata(),
             m_protocol.get(),
             saml1name,
+            saml1statement,
             (saml1name ? nameid.get() : saml2name),
+            saml2statement,
             authMethod,
             nullptr,
             &tokens
index 3a32393..3d452b9 100644 (file)
@@ -35,9 +35,11 @@ namespace opensaml {
     class SAML_API Assertion;
     class SAML_API MessageDecoder;
     namespace saml1 {
+        class SAML_API AuthenticationStatement;
         class SAML_API NameIdentifier;
     };
     namespace saml2 {
+        class SAML_API AuthnStatement;
         class SAML_API NameID;
     };
     namespace saml2md {
@@ -150,6 +152,35 @@ namespace shibsp {
             ) const;
 
         /**
+         * @deprecated
+         * Attempt SSO-initiated attribute resolution using the supplied information,
+         * including NameID and token extraction and filtering followed by
+         * secondary resolution.
+         * 
+         * <p>The caller must free the returned context handle.
+         * 
+         * @param application           reference to application receiving message
+         * @param issuer                source of SSO tokens
+         * @param protocol              SSO protocol used
+         * @param v1nameid              identifier of principal in SAML 1.x form, if any
+         * @param nameid                identifier of principal in SAML 2.0 form
+         * @param authncontext_class    method/category of authentication event, if known
+         * @param authncontext_decl     specifics of authentication event, if known
+         * @param tokens                available assertions, if any
+         */
+        ResolutionContext* resolveAttributes(
+            const Application& application,
+            const opensaml::saml2md::RoleDescriptor* issuer=nullptr,
+            const XMLCh* protocol=nullptr,
+            const opensaml::saml1::NameIdentifier* v1nameid=nullptr,
+            const opensaml::saml2::NameID* nameid=nullptr,
+            const XMLCh* authncontext_class=nullptr,
+            const XMLCh* authncontext_decl=nullptr,
+            const std::vector<const opensaml::Assertion*>* tokens=nullptr
+            ) const;
+
+        /**
+         * @deprecated
          * Attempt SSO-initiated attribute resolution using the supplied information,
          * including NameID and token extraction and filtering followed by
          * secondary resolution.
@@ -170,7 +201,9 @@ namespace shibsp {
             const opensaml::saml2md::RoleDescriptor* issuer=nullptr,
             const XMLCh* protocol=nullptr,
             const opensaml::saml1::NameIdentifier* v1nameid=nullptr,
+            const opensaml::saml1::AuthenticationStatement* v1statement=nullptr,
             const opensaml::saml2::NameID* nameid=nullptr,
+            const opensaml::saml2::AuthnStatement* statement=nullptr,
             const XMLCh* authncontext_class=nullptr,
             const XMLCh* authncontext_decl=nullptr,
             const std::vector<const opensaml::Assertion*>* tokens=nullptr
index e2b4c49..81807a3 100644 (file)
@@ -314,6 +314,33 @@ ResolutionContext* AssertionConsumerService::resolveAttributes(
     const vector<const Assertion*>* tokens
     ) const
 {
+    return resolveAttributes(
+        application,
+        issuer,
+        protocol,
+        v1nameid,
+        nullptr,
+        nameid,
+        nullptr,
+        authncontext_class,
+        authncontext_decl,
+        tokens
+        );
+}
+
+ResolutionContext* AssertionConsumerService::resolveAttributes(
+    const Application& application,
+    const saml2md::RoleDescriptor* issuer,
+    const XMLCh* protocol,
+    const saml1::NameIdentifier* v1nameid,
+    const saml1::AuthenticationStatement* v1statement,
+    const saml2::NameID* nameid,
+    const saml2::AuthnStatement* statement,
+    const XMLCh* authncontext_class,
+    const XMLCh* authncontext_decl,
+    const vector<const Assertion*>* tokens
+    ) const
+{
     // First we do the extraction of any pushed information, including from metadata.
     vector<Attribute*> resolvedAttributes;
     AttributeExtractor* extractor = application.getAttributeExtractor();
@@ -337,23 +364,33 @@ ResolutionContext* AssertionConsumerService::resolveAttributes(
                 }
             }
         }
+
         m_log.debug("extracting pushed attributes...");
-        if (v1nameid) {
+
+        if (v1nameid || nameid) {
             try {
-                extractor->extractAttributes(application, issuer, *v1nameid, resolvedAttributes);
+                if (v1nameid)
+                    extractor->extractAttributes(application, issuer, *v1nameid, resolvedAttributes);
+                else
+                    extractor->extractAttributes(application, issuer, *nameid, resolvedAttributes);
             }
             catch (exception& ex) {
                 m_log.error("caught exception extracting attributes: %s", ex.what());
             }
         }
-        else if (nameid) {
+
+        if (v1statement || statement) {
             try {
-                extractor->extractAttributes(application, issuer, *nameid, resolvedAttributes);
+                if (v1statement)
+                    extractor->extractAttributes(application, issuer, *v1statement, resolvedAttributes);
+                else
+                    extractor->extractAttributes(application, issuer, *statement, resolvedAttributes);
             }
             catch (exception& ex) {
                 m_log.error("caught exception extracting attributes: %s", ex.what());
             }
         }
+
         if (tokens) {
             for (vector<const Assertion*>::const_iterator t = tokens->begin(); t!=tokens->end(); ++t) {
                 try {
index 46ef55c..adeebf3 100644 (file)
@@ -300,7 +300,9 @@ void SAML1Consumer::implementProtocol(
             (!response->getMinorVersion().first || response->getMinorVersion().second==1) ?
                 samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM,
             n,
+            ssoStatement,
             nameid.get(),
+            nullptr,
             ssoStatement->getAuthenticationMethod(),
             nullptr,
             &tokens
index 6af77e7..ad8fcdc 100644 (file)
@@ -419,7 +419,9 @@ void SAML2Consumer::implementProtocol(
                 policy.getIssuerMetadata(),
                 samlconstants::SAML20P_NS,
                 nullptr,
+                nullptr,
                 ssoName,
+                ssoStatement,
                 (authnContext && authnContext->getAuthnContextClassRef()) ? authnContext->getAuthnContextClassRef()->getReference() : nullptr,
                 (authnContext && authnContext->getAuthnContextDeclRef()) ? authnContext->getAuthnContextDeclRef()->getReference() : nullptr,
                 &tokens