Make NameID optional in session.
authorScott Cantor <cantor.2@osu.edu>
Sun, 18 Mar 2007 21:56:48 +0000 (21:56 +0000)
committerScott Cantor <cantor.2@osu.edu>
Sun, 18 Mar 2007 21:56:48 +0000 (21:56 +0000)
shibsp/SessionCache.h
shibsp/attribute/resolver/AttributeResolver.h
shibsp/attribute/resolver/ResolutionContext.h
shibsp/attribute/resolver/impl/SimpleAttributeResolver.cpp
shibsp/handler/AssertionConsumerService.h
shibsp/handler/impl/AbstractHandler.cpp
shibsp/handler/impl/AssertionConsumerService.cpp
shibsp/handler/impl/SAML1Consumer.cpp
shibsp/impl/RemotedSessionCache.cpp
shibsp/impl/StorageServiceSessionCache.cpp
shibsp/shibsp.vcproj

index a4cc56b..f9403cc 100644 (file)
@@ -66,9 +66,9 @@ namespace shibsp {
          * 
          * <p>SAML 1.x identifiers will be promoted to the 2.0 type.
          * 
-         * @return reference to a SAML 2.0 NameID
+         * @return a SAML 2.0 NameID associated with the session, if any
          */
-        virtual const opensaml::saml2::NameID& getNameID() const=0;
+        virtual const opensaml::saml2::NameID* getNameID() const=0;
 
         /**
          * Returns the SessionIndex provided with the session.
@@ -175,11 +175,11 @@ namespace shibsp {
          * @param application       reference to Application that owns the Session
          * @param client_addr       network address of client
          * @param issuer            issuing metadata of assertion issuer, if known
-         * @param nameid            principal identifier, normalized to SAML 2
-         * @param authn_instant     UTC timestamp of authentication at IdP
-         * @param session_index     index of session between principal and IdP
-         * @param authncontext_class    method/category of authentication event
-         * @param authncontext_decl specifics of authentication event 
+         * @param nameid            principal identifier, normalized to SAML 2, if any
+         * @param authn_instant     UTC timestamp of authentication at IdP, if known
+         * @param session_index     index of session between principal and IdP, if any
+         * @param authncontext_class    method/category of authentication event, if known
+         * @param authncontext_decl specifics of authentication event, if known
          * @param tokens            assertions to cache with session, if any
          * @param attributes        optional set of resolved Attributes to cache with session
          * @return  newly created session's key
@@ -187,9 +187,9 @@ namespace shibsp {
         virtual std::string insert(
             time_t expires,
             const Application& application,
-            const char* client_addr,
-            const opensaml::saml2md::EntityDescriptor* issuer,
-            const opensaml::saml2::NameID& nameid,
+            const char* client_addr=NULL,
+            const opensaml::saml2md::EntityDescriptor* issuer=NULL,
+            const opensaml::saml2::NameID* nameid=NULL,
             const char* authn_instant=NULL,
             const char* session_index=NULL,
             const char* authncontext_class=NULL,
index 1503a7b..9e57789 100644 (file)
@@ -61,7 +61,7 @@ namespace shibsp {
          * @param application       reference to Application that owns the eventual Session
          * @param client_addr       network address of client
          * @param issuer            issuing metadata of assertion issuer, if known
-         * @param nameid            principal identifier, normalized to SAML 2
+         * @param nameid            principal identifier, normalized to SAML 2, if any
          * @param tokens            assertions initiating the session, if any
          * @return  newly created ResolutionContext, owned by caller
          */
@@ -69,7 +69,7 @@ namespace shibsp {
             const Application& application,
             const char* client_addr,
             const opensaml::saml2md::EntityDescriptor* issuer,
-            const opensaml::saml2::NameID& nameid,
+            const opensaml::saml2::NameID* nameid,
             const std::vector<const opensaml::Assertion*>* tokens=NULL
             ) const=0;
 
index bdc0ecd..980824a 100644 (file)
@@ -71,9 +71,9 @@ namespace shibsp {
          * 
          * <p>SAML 1.x identifiers will be promoted to the 2.0 type.
          * 
-         * @return reference to a SAML 2.0 NameID
+         * @return a SAML 2.0 NameID associated with the subject, if any
          */
-        virtual const opensaml::saml2::NameID& getNameID() const=0;
+        virtual const opensaml::saml2::NameID* getNameID() const=0;
 
         /**
          * Returns unresolved tokens associated with the subject, if any.
index b2da14e..2a427f4 100644 (file)
@@ -72,7 +72,7 @@ namespace shibsp {
             const Application& application,\r
             const char* client_addr,\r
             const EntityDescriptor* issuer,\r
-            const NameID& nameid,\r
+            const NameID* nameid,\r
             const vector<const opensaml::Assertion*>* tokens=NULL\r
             ) : m_app(application), m_session(NULL), m_client_addr(client_addr), m_metadata(NULL), m_entity(issuer),\r
                 m_nameid(nameid), m_tokens(tokens) {\r
@@ -103,7 +103,7 @@ namespace shibsp {
             }\r
             return NULL;\r
         }\r
-        const NameID& getNameID() const {\r
+        const NameID* getNameID() const {\r
             return m_nameid;\r
         }\r
         const vector<const opensaml::Assertion*>* getTokens() const {\r
@@ -125,7 +125,7 @@ namespace shibsp {
         const char* m_client_addr;\r
         mutable MetadataProvider* m_metadata;\r
         mutable const EntityDescriptor* m_entity;\r
-        const NameID& m_nameid;\r
+        const NameID* m_nameid;\r
         const vector<const opensaml::Assertion*>* m_tokens;\r
         vector<shibsp::Attribute*> m_attributes;\r
         vector<opensaml::Assertion*> m_assertions;\r
@@ -188,7 +188,7 @@ namespace shibsp {
             const Application& application,\r
             const char* client_addr,\r
             const EntityDescriptor* issuer,\r
-            const NameID& nameid,\r
+            const NameID* nameid,\r
             const vector<const opensaml::Assertion*>* tokens=NULL\r
             ) const {\r
             return new SimpleContext(application,client_addr,issuer,nameid,tokens);\r
@@ -333,23 +333,27 @@ void SimpleResolverImpl::resolve(
     map< pair<string,string>,pair<const AttributeDecoder*,string> >::const_iterator rule;\r
 #endif\r
 \r
-    // Check the NameID based on the format.\r
     const XMLCh* name;\r
-    const XMLCh* format = ctx.getNameID().getFormat();\r
-    if (!format || !*format)\r
-        format = NameID::UNSPECIFIED;\r
+    const XMLCh* format;\r
+    \r
+    // Check the NameID based on the format.\r
+    if (ctx.getNameID()) {\r
+        format = ctx.getNameID()->getFormat();\r
+        if (!format || !*format)\r
+            format = NameID::UNSPECIFIED;\r
 #ifdef HAVE_GOOD_STL\r
-    if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
+        if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
 #else\r
-    auto_ptr_char temp(format);\r
-    if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
+        auto_ptr_char temp(format);\r
+        if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
 #endif\r
-        if (aset.empty() || aset.count(rule->second.second)) {\r
-            resolved.push_back(\r
-                rule->second.first->decode(\r
-                    rule->second.second.c_str(), &ctx.getNameID(), assertingParty.get(), relyingParty\r
-                    )\r
-                );\r
+            if (aset.empty() || aset.count(rule->second.second)) {\r
+                resolved.push_back(\r
+                    rule->second.first->decode(\r
+                        rule->second.second.c_str(), ctx.getNameID(), assertingParty.get(), relyingParty\r
+                        )\r
+                    );\r
+            }\r
         }\r
     }\r
 \r
@@ -400,23 +404,27 @@ void SimpleResolverImpl::resolve(
     map< pair<string,string>,pair<const AttributeDecoder*,string> >::const_iterator rule;\r
 #endif\r
 \r
-    // Check the NameID based on the format.\r
     const XMLCh* name;\r
-    const XMLCh* format = ctx.getNameID().getFormat();\r
-    if (!format || !*format)\r
-        format = NameID::UNSPECIFIED;\r
+    const XMLCh* format;\r
+    \r
+    // Check the NameID based on the format.\r
+    if (ctx.getNameID()) {\r
+        format = ctx.getNameID()->getFormat();\r
+        if (!format || !*format)\r
+            format = NameID::UNSPECIFIED;\r
 #ifdef HAVE_GOOD_STL\r
-    if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
+        if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
 #else\r
-    auto_ptr_char temp(format);\r
-    if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
+        auto_ptr_char temp(format);\r
+        if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
 #endif\r
-        if (aset.empty() || aset.count(rule->second.second)) {\r
-            resolved.push_back(\r
-                rule->second.first->decode(\r
-                    rule->second.second.c_str(), &ctx.getNameID(), assertingParty.get(), relyingParty\r
-                    )\r
-                );\r
+            if (aset.empty() || aset.count(rule->second.second)) {\r
+                resolved.push_back(\r
+                    rule->second.first->decode(\r
+                        rule->second.second.c_str(), ctx.getNameID(), assertingParty.get(), relyingParty\r
+                        )\r
+                    );\r
+            }\r
         }\r
     }\r
 \r
@@ -659,11 +667,17 @@ void SimpleResolver::resolveAttributes(ResolutionContext& ctx, const vector<cons
 \r
     if (query) {\r
         if (token1 && !token1->getAuthenticationStatements().empty()) {\r
-            log.debug("attempting SAML 1.x attribute query");\r
-            return m_impl->query(ctx, *(token1->getAuthenticationStatements().front()->getSubject()->getNameIdentifier()), attributes);\r
+            const AuthenticationStatement* statement = token1->getAuthenticationStatements().front();\r
+            if (statement && statement->getSubject() && statement->getSubject()->getNameIdentifier()) {\r
+                log.debug("attempting SAML 1.x attribute query");\r
+                return m_impl->query(ctx, *(statement->getSubject()->getNameIdentifier()), attributes);\r
+            }\r
+        }\r
+        else if (token2 && ctx.getNameID()) {\r
+            log.debug("attempting SAML 2.0 attribute query");\r
+            return m_impl->query(ctx, *ctx.getNameID(), attributes);\r
         }\r
-        log.debug("attempting SAML 2.0 attribute query");\r
-        m_impl->query(ctx, ctx.getNameID(), attributes);\r
+        log.warn("can't attempt attribute query, no identifier in assertion subject");\r
     }\r
 }\r
 \r
index d6f3a5f..99d0750 100644 (file)
@@ -104,8 +104,8 @@ namespace shibsp {
         ResolutionContext* resolveAttributes(
             const Application& application,
             const opensaml::HTTPRequest& httpRequest,
-            const opensaml::saml2md::EntityDescriptor* issuer,
-            const opensaml::saml2::NameID& nameid,
+            const opensaml::saml2md::EntityDescriptor* issuer=NULL,
+            const opensaml::saml2::NameID* nameid=NULL,
             const std::vector<const opensaml::Assertion*>* tokens=NULL
             ) const;
         
index a61f40c..1bf4593 100644 (file)
@@ -41,6 +41,7 @@ using namespace std;
 
 namespace shibsp {
     SHIBSP_DLLLOCAL PluginManager<Handler,pair<const DOMElement*,const char*>>::Factory SAML1ConsumerFactory;
+    SHIBSP_DLLLOCAL PluginManager<Handler,pair<const DOMElement*,const char*>>::Factory SAML2ConsumerFactory;
 };
 
 void SHIBSP_API shibsp::registerHandlers()
@@ -48,6 +49,9 @@ void SHIBSP_API shibsp::registerHandlers()
     SPConfig& conf=SPConfig::getConfig();
     conf.AssertionConsumerServiceManager.registerFactory(SAML1_PROFILE_BROWSER_ARTIFACT, SAML1ConsumerFactory);
     conf.AssertionConsumerServiceManager.registerFactory(SAML1_PROFILE_BROWSER_POST, SAML1ConsumerFactory);
+    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2ConsumerFactory);
+    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2ConsumerFactory);
+    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2ConsumerFactory);
 }
 
 AbstractHandler::AbstractHandler(
index 7e0eb03..02995c4 100644 (file)
@@ -233,7 +233,7 @@ ResolutionContext* AssertionConsumerService::resolveAttributes(
     const Application& application,
     const HTTPRequest& httpRequest,
     const saml2md::EntityDescriptor* issuer,
-    const saml2::NameID& nameid,
+    const saml2::NameID* nameid,
     const vector<const Assertion*>* tokens
     ) const
 {
index 33744a7..8addb99 100644 (file)
@@ -186,8 +186,8 @@ string SAML1Consumer::implementProtocol(
     // To complete processing, we need to resolve attributes and then create the session.
 
     // First, normalize the SAML 1.x NameIdentifier...
-    auto_ptr<NameID> nameid(NameIDBuilder::buildNameID());
     NameIdentifier* n = ssoStatement->getSubject()->getNameIdentifier();
+    auto_ptr<NameID> nameid(n ? NameIDBuilder::buildNameID() : NULL);
     if (n) {
         nameid->setName(n->getName());
         nameid->setFormat(n->getFormat());
@@ -196,7 +196,7 @@ string SAML1Consumer::implementProtocol(
 
     const EntityDescriptor* issuerMetadata = dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent());
     auto_ptr<ResolutionContext> ctx(
-        resolveAttributes(application, httpRequest, issuerMetadata, *nameid.get(), &tokens)
+        resolveAttributes(application, httpRequest, issuerMetadata, nameid.get(), &tokens)
         );
 
     // Copy over any new tokens, but leave them in the context for cleanup.
@@ -223,7 +223,7 @@ string SAML1Consumer::implementProtocol(
         application,
         httpRequest.getRemoteAddr().c_str(),
         issuerMetadata,
-        *nameid.get(),
+        nameid.get(),
         authnInstant.get(),
         NULL,
         authnMethod.get(),
index f3f6d07..285e8b7 100644 (file)
@@ -52,16 +52,16 @@ namespace shibsp {
         RemotedSession(RemotedCache* cache, DDF& obj) : m_version(obj["version"].integer()), m_obj(obj),\r
                 m_nameid(NULL), m_expires(0), m_lastAccess(time(NULL)), m_cache(cache), m_lock(NULL) {\r
             const char* nameid = obj["nameid"].string();\r
-            if (!nameid)\r
-                throw FatalProfileException("NameID missing from remotely cached session.");\r
-            \r
-            // Parse and bind the NameID into an XMLObject.\r
-            istringstream instr(nameid);\r
-            DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(instr); \r
-            XercesJanitor<DOMDocument> janitor(doc);\r
-            auto_ptr<saml2::NameID> n(saml2::NameIDBuilder::buildNameID());\r
-            n->unmarshall(doc->getDocumentElement(), true);\r
-            janitor.release();\r
+            if (nameid) {\r
+                // Parse and bind the NameID into an XMLObject.\r
+                istringstream instr(nameid);\r
+                DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(instr); \r
+                XercesJanitor<DOMDocument> janitor(doc);\r
+                auto_ptr<saml2::NameID> n(saml2::NameIDBuilder::buildNameID());\r
+                n->unmarshall(doc->getDocumentElement(), true);\r
+                janitor.release();\r
+                m_nameid = n.release();\r
+            }\r
             \r
             auto_ptr_XMLCh exp(m_obj["expires"].string());\r
             if (exp.get()) {\r
@@ -71,7 +71,6 @@ namespace shibsp {
             }\r
 \r
             m_lock = Mutex::create();\r
-            m_nameid = n.release();\r
         }\r
         \r
         ~RemotedSession() {\r
@@ -102,8 +101,8 @@ namespace shibsp {
         const char* getAuthnInstant() const {\r
             return m_obj["authn_instant"].string();\r
         }\r
-        const opensaml::saml2::NameID& getNameID() const {\r
-            return *m_nameid;\r
+        const opensaml::saml2::NameID* getNameID() const {\r
+            return m_nameid;\r
         }\r
         const char* getSessionIndex() const {\r
             return m_obj["session_index"].string();\r
@@ -167,9 +166,9 @@ namespace shibsp {
         string insert(\r
             time_t expires,\r
             const Application& application,\r
-            const char* client_addr,\r
-            const saml2md::EntityDescriptor* issuer,\r
-            const saml2::NameID& nameid,\r
+            const char* client_addr=NULL,\r
+            const saml2md::EntityDescriptor* issuer=NULL,\r
+            const saml2::NameID* nameid=NULL,\r
             const char* authn_instant=NULL,\r
             const char* session_index=NULL,\r
             const char* authncontext_class=NULL,\r
@@ -356,7 +355,7 @@ string RemotedCache::insert(
     const Application& application,\r
     const char* client_addr,\r
     const saml2md::EntityDescriptor* issuer,\r
-    const saml2::NameID& nameid,\r
+    const saml2::NameID* nameid,\r
     const char* authn_instant,\r
     const char* session_index,\r
     const char* authncontext_class,\r
@@ -380,7 +379,8 @@ string RemotedCache::insert(
         in.addmember("expires").string(timebuf);\r
     }\r
     in.addmember("application_id").string(application.getId());\r
-    in.addmember("client_addr").string(client_addr);\r
+    if (client_addr)\r
+        in.addmember("client_addr").string(client_addr);\r
     if (issuer) {\r
         auto_ptr_char provid(issuer->getEntityID());\r
         in.addmember("entity_id").string(provid.get());\r
@@ -394,9 +394,11 @@ string RemotedCache::insert(
     if (authncontext_decl)\r
         in.addmember("authncontext_decl").string(authncontext_decl);\r
     \r
-    ostringstream namestr;\r
-    namestr << nameid;\r
-    in.addmember("nameid").string(namestr.str().c_str());\r
+    if (nameid) {\r
+        ostringstream namestr;\r
+        namestr << nameid;\r
+        in.addmember("nameid").string(namestr.str().c_str());\r
+    }\r
 \r
     if (tokens) {\r
         in.addmember("assertions").list();\r
@@ -425,7 +427,7 @@ string RemotedCache::insert(
     DDFJanitor jout(out);\r
     if (out["key"].isstring()) {\r
         // Transaction Logging\r
-        auto_ptr_char name(nameid.getName());\r
+        auto_ptr_char name(nameid ? nameid->getName() : NULL);\r
         const char* pid = in["entity_id"].string();\r
         TransactionLog* xlog = application.getServiceProvider().getTransactionLog();\r
         Locker locker(xlog);\r
@@ -437,9 +439,9 @@ string RemotedCache::insert(
             ") for principal from (IdP: " <<\r
                 (pid ? pid : "none") <<\r
             ") at (ClientAddress: " <<\r
-                client_addr <<\r
+                (client_addr ? client_addr : "none") <<\r
             ") with (NameIdentifier: " <<\r
-                name.get() <<\r
+                (name.get() ? name.get() : "none") <<\r
             ")";\r
 \r
         if (attributes) {\r
index 9a2d8ce..20bec25 100644 (file)
@@ -58,19 +58,18 @@ namespace shibsp {
     class StoredSession : public virtual Session\r
     {\r
     public:\r
-        StoredSession(SSCache* cache, DDF& obj) : m_obj(obj), m_cache(cache) {\r
+        StoredSession(SSCache* cache, DDF& obj) : m_obj(obj), m_nameid(NULL), m_cache(cache) {\r
             const char* nameid = obj["nameid"].string();\r
-            if (!nameid)\r
-                throw FatalProfileException("NameID missing from cached session.");\r
-            \r
-            // Parse and bind the document into an XMLObject.\r
-            istringstream instr(nameid);\r
-            DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(instr); \r
-            XercesJanitor<DOMDocument> janitor(doc);\r
-            auto_ptr<saml2::NameID> n(saml2::NameIDBuilder::buildNameID());\r
-            n->unmarshall(doc->getDocumentElement(), true);\r
-            janitor.release();\r
-            m_nameid = n.release();\r
+            if (nameid) {\r
+                // Parse and bind the document into an XMLObject.\r
+                istringstream instr(nameid);\r
+                DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(instr); \r
+                XercesJanitor<DOMDocument> janitor(doc);\r
+                auto_ptr<saml2::NameID> n(saml2::NameIDBuilder::buildNameID());\r
+                n->unmarshall(doc->getDocumentElement(), true);\r
+                janitor.release();\r
+                m_nameid = n.release();\r
+            }\r
         }\r
         \r
         ~StoredSession();\r
@@ -91,8 +90,8 @@ namespace shibsp {
         const char* getAuthnInstant() const {\r
             return m_obj["authn_instant"].string();\r
         }\r
-        const opensaml::saml2::NameID& getNameID() const {\r
-            return *m_nameid;\r
+        const opensaml::saml2::NameID* getNameID() const {\r
+            return m_nameid;\r
         }\r
         const char* getSessionIndex() const {\r
             return m_obj["session_index"].string();\r
@@ -146,9 +145,9 @@ namespace shibsp {
         string insert(\r
             time_t expires,\r
             const Application& application,\r
-            const char* client_addr,\r
-            const saml2md::EntityDescriptor* issuer,\r
-            const saml2::NameID& nameid,\r
+            const char* client_addr=NULL,\r
+            const saml2md::EntityDescriptor* issuer=NULL,\r
+            const saml2::NameID* nameid=NULL,\r
             const char* authn_instant=NULL,\r
             const char* session_index=NULL,\r
             const char* authncontext_class=NULL,\r
@@ -452,7 +451,7 @@ string SSCache::insert(
     const Application& application,\r
     const char* client_addr,\r
     const saml2md::EntityDescriptor* issuer,\r
-    const saml2::NameID& nameid,\r
+    const saml2::NameID* nameid,\r
     const char* authn_instant,\r
     const char* session_index,\r
     const char* authncontext_class,\r
@@ -485,7 +484,8 @@ string SSCache::insert(
         strftime(timebuf,32,"%Y-%m-%dT%H:%M:%SZ",ptime);\r
         obj.addmember("expires").string(timebuf);\r
     }\r
-    obj.addmember("client_addr").string(client_addr);\r
+    if (client_addr)\r
+        obj.addmember("client_addr").string(client_addr);\r
     if (issuer) {\r
         auto_ptr_char entity_id(issuer->getEntityID());\r
         obj.addmember("entity_id").string(entity_id.get());\r
@@ -499,10 +499,12 @@ string SSCache::insert(
     if (authncontext_decl)\r
         obj.addmember("authncontext_decl").string(authncontext_decl);\r
 \r
-    ostringstream namestr;\r
-    namestr << nameid;\r
-    obj.addmember("nameid").string(namestr.str().c_str());\r
-    \r
+    if (nameid) {\r
+        ostringstream namestr;\r
+        namestr << nameid;\r
+        obj.addmember("nameid").string(namestr.str().c_str());\r
+    }\r
+\r
     if (tokens) {\r
         obj.addmember("assertions").list();\r
         for (vector<const Assertion*>::const_iterator t = tokens->begin(); t!=tokens->end(); ++t) {\r
@@ -545,7 +547,7 @@ string SSCache::insert(
     m_log.debug("new session created: SessionID (%s) IdP (%s) Address (%s)", key.get(), pid ? pid : "none", client_addr);\r
 \r
     // Transaction Logging\r
-    auto_ptr_char name(nameid.getName());\r
+    auto_ptr_char name(nameid ? nameid->getName() : NULL);\r
     TransactionLog* xlog = application.getServiceProvider().getTransactionLog();\r
     Locker locker(xlog);\r
     xlog->log.infoStream() <<\r
@@ -556,9 +558,9 @@ string SSCache::insert(
         ") for principal from (IdP: " <<\r
             (pid ? pid : "none") <<\r
         ") at (ClientAddress: " <<\r
-            client_addr <<\r
+            (client_addr ? client_addr : "none") <<\r
         ") with (NameIdentifier: " <<\r
-            name.get() <<\r
+            (name.get() ? name.get() : "none") <<\r
         ")";\r
     \r
     if (attributes) {\r
index c230b57..cda16c8 100644 (file)
                                                RelativePath=".\handler\impl\SAML1Consumer.cpp"\r
                                                >\r
                                        </File>\r
+                                       <File\r
+                                               RelativePath=".\handler\impl\SAML2Consumer.cpp"\r
+                                               >\r
+                                       </File>\r
                                </Filter>\r
                        </Filter>\r
                </Filter>\r