Tagging 2.4RC1 release. tags/2.4RC1 2.4
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 3 Nov 2010 02:31:45 +0000 (02:31 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 3 Nov 2010 02:31:45 +0000 (02:31 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/tags/2.4RC1@3365 cb58f699-b61c-0410-a6fe-9272a202ed29

31 files changed:
Shibboleth.sln
apache/mod_apache.cpp
configs/metagen.sh
configs/shibd-suse.in
configure.ac
doc/NOTICE.txt
schemas/shibboleth-2.0-attribute-map.xsd
schemas/shibboleth-2.0-native-sp-config.xsd
shibboleth.spec.in
shibsp/AbstractSPRequest.cpp
shibsp/GSSRequest.h [new file with mode: 0644]
shibsp/Makefile.am
shibsp/ServiceProvider.cpp
shibsp/ServiceProvider.h
shibsp/attribute/Attribute.cpp
shibsp/attribute/AttributeDecoder.h
shibsp/attribute/Base64AttributeDecoder.cpp [new file with mode: 0644]
shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp
shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp
shibsp/attribute/resolver/impl/SimpleAggregationAttributeResolver.cpp
shibsp/handler/RemotedHandler.h
shibsp/handler/impl/MetadataGenerator.cpp
shibsp/handler/impl/RemotedHandler.cpp
shibsp/handler/impl/StatusHandler.cpp
shibsp/impl/StorageServiceSessionCache.cpp
shibsp/impl/XMLRequestMapper.cpp
shibsp/impl/XMLServiceProvider.cpp
shibsp/shibsp-lite.vcxproj
shibsp/shibsp-lite.vcxproj.filters
shibsp/shibsp.vcxproj
shibsp/shibsp.vcxproj.filters

index 112d8f2..76fd0bb 100644 (file)
@@ -71,17 +71,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{2543BC
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{31B171C1-E06C-464F-A541-38724AB52D79}"
        ProjectSection(SolutionItems) = preProject
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{31B171C1-E06C-464F-A541-38724AB52D79}"
        ProjectSection(SolutionItems) = preProject
-               acinclude.m4 = acinclude.m4
-               acx_pthread.m4 = acx_pthread.m4
-               bootstrap = bootstrap
+               m4\acinclude.m4 = m4\acinclude.m4
+               m4\acx_pthread.m4 = m4\acx_pthread.m4
                config_win32.h = config_win32.h
                configure.ac = configure.ac
                config_win32.h = config_win32.h
                configure.ac = configure.ac
-               depend = depend
                doxygen.am = doxygen.am
                doxygen.cfg = doxygen.cfg
                doxygen.am = doxygen.am
                doxygen.cfg = doxygen.cfg
-               doxygen.m4 = doxygen.m4
-               libtool.m4 = libtool.m4
-               ltmain.sh = ltmain.sh
+               m4\doxygen.m4 = m4\doxygen.m4
                Makefile.am = Makefile.am
                pkginfo.in = pkginfo.in
                Portfile.in = Portfile.in
                Makefile.am = Makefile.am
                pkginfo.in = pkginfo.in
                Portfile.in = Portfile.in
index e8b1765..0f0a770 100644 (file)
 # define _CRT_SECURE_NO_DEPRECATE 1
 #endif
 
 # define _CRT_SECURE_NO_DEPRECATE 1
 #endif
 
+#include <shibsp/exceptions.h>
 #include <shibsp/AbstractSPRequest.h>
 #include <shibsp/AccessControl.h>
 #include <shibsp/AbstractSPRequest.h>
 #include <shibsp/AccessControl.h>
-#include <shibsp/exceptions.h>
+#include <shibsp/GSSRequest.h>
 #include <shibsp/RequestMapper.h>
 #include <shibsp/SPConfig.h>
 #include <shibsp/ServiceProvider.h>
 #include <shibsp/SessionCache.h>
 #include <shibsp/attribute/Attribute.h>
 #include <shibsp/RequestMapper.h>
 #include <shibsp/SPConfig.h>
 #include <shibsp/ServiceProvider.h>
 #include <shibsp/SessionCache.h>
 #include <shibsp/attribute/Attribute.h>
+
 #include <xercesc/util/XMLUniDefs.hpp>
 #include <xercesc/util/regx/RegularExpression.hpp>
 #include <xmltooling/XMLToolingConfig.h>
 #include <xercesc/util/XMLUniDefs.hpp>
 #include <xercesc/util/regx/RegularExpression.hpp>
 #include <xmltooling/XMLToolingConfig.h>
@@ -95,7 +97,10 @@ namespace {
     string g_unsetHeaderValue,g_spoofKey;
     bool g_checkSpoofing = true;
     bool g_catchAll = false;
     string g_unsetHeaderValue,g_spoofKey;
     bool g_checkSpoofing = true;
     bool g_catchAll = false;
-    static const char* g_UserDataKey = "_shib_check_user_";
+#ifndef SHIB_APACHE_13
+    char* g_szGSSContextKey = "mod_auth_gssapi:gss_ctx";
+#endif
+    static const char* g_UserDataKey = "urn:mace:shibboleth:Apache:shib_check_user";
 }
 
 /* Apache 2.2.x headers must be accumulated and set in the output filter.
 }
 
 /* Apache 2.2.x headers must be accumulated and set in the output filter.
@@ -294,10 +299,11 @@ extern "C" const char* shib_table_set(cmd_parms* parms, shib_dir_config* dc, con
     return nullptr;
 }
 
     return nullptr;
 }
 
-/********************************************************************************/
-// Apache ShibTarget subclass(es) here.
 
 class ShibTargetApache : public AbstractSPRequest
 
 class ShibTargetApache : public AbstractSPRequest
+#if defined(HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
+    , public GSSRequest
+#endif
 {
   bool m_handler;
   mutable string m_body;
 {
   bool m_handler;
   mutable string m_body;
@@ -574,6 +580,13 @@ public:
   }
   long returnDecline(void) { return DECLINED; }
   long returnOK(void) { return OK; }
   }
   long returnDecline(void) { return DECLINED; }
   long returnOK(void) { return OK; }
+#if defined(HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
+  gss_ctx_id_t getGSSContext() const {
+    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
+    apr_pool_userdata_get((void**)&ctx, g_szGSSContextKey, m_req->pool);
+    return ctx;
+  }
+#endif
 };
 
 /********************************************************************************/
 };
 
 /********************************************************************************/
@@ -1028,17 +1041,18 @@ AccessControl::aclresult_t htAccessControl::authorized(const SPRequest& request,
             status = true;
         }
         else if (!strcmp(w,"user") && !remote_user.empty()) {
             status = true;
         }
         else if (!strcmp(w,"user") && !remote_user.empty()) {
-            bool regexp=false,negate=false;
+            bool regexp = false;
             while (*t) {
             while (*t) {
-                w=ap_getword_conf(sta->m_req->pool,&t);
-                if (*w=='~') {
-                    regexp=true;
+                w = ap_getword_conf(sta->m_req->pool,&t);
+                if (*w == '~') {
+                    regexp = true;
                     continue;
                 }
                     continue;
                 }
-                else if (*w=='!') {
-                    negate=true;
-                    if (*(w+1)=='~')
-                        regexp=true;
+                else if (*w == '!') {
+                    // A negated rule presumes success unless a match is found.
+                    status = true;
+                    if (*(w+1) == '~')
+                        regexp = true;
                     continue;
                 }
 
                     continue;
                 }
 
@@ -1058,87 +1072,93 @@ AccessControl::aclresult_t htAccessControl::authorized(const SPRequest& request,
                             string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
                     }
                 }
                             string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
                     }
                 }
-                else if (remote_user==w) {
+                else if (remote_user == w) {
                     match = true;
                 }
 
                 if (match) {
                     match = true;
                 }
 
                 if (match) {
-                    // If we matched, then we're done with this rule either way and status is set to reflect the outcome.
-                    status = !negate;
+                    // If we matched, then we're done with this rule either way and we flip status to reflect the outcome.
+                    status = !status;
                     if (request.isPriorityEnabled(SPRequest::SPDebug))
                         request.log(SPRequest::SPDebug,
                     if (request.isPriorityEnabled(SPRequest::SPDebug))
                         request.log(SPRequest::SPDebug,
-                            string("htaccess: require user ") + (negate ? "rejecting (" : "accepting (") + remote_user + ")");
+                            string("htaccess: require user ") + (!status ? "rejecting (" : "accepting (") + remote_user + ")");
                     break;
                 }
             }
         }
         else if (!strcmp(w,"group")  && !remote_user.empty()) {
                     break;
                 }
             }
         }
         else if (!strcmp(w,"group")  && !remote_user.empty()) {
-            SH_AP_TABLE* grpstatus=nullptr;
+            SH_AP_TABLE* grpstatus = nullptr;
             if (sta->m_dc->szAuthGrpFile) {
                 if (request.isPriorityEnabled(SPRequest::SPDebug))
                     request.log(SPRequest::SPDebug,string("htaccess plugin using groups file: ") + sta->m_dc->szAuthGrpFile);
             if (sta->m_dc->szAuthGrpFile) {
                 if (request.isPriorityEnabled(SPRequest::SPDebug))
                     request.log(SPRequest::SPDebug,string("htaccess plugin using groups file: ") + sta->m_dc->szAuthGrpFile);
-                grpstatus=groups_for_user(sta->m_req,remote_user.c_str(),sta->m_dc->szAuthGrpFile);
+                grpstatus = groups_for_user(sta->m_req,remote_user.c_str(),sta->m_dc->szAuthGrpFile);
             }
 
             }
 
-            bool negate=false;
             while (*t) {
             while (*t) {
-                w=ap_getword_conf(sta->m_req->pool,&t);
-                if (*w=='!') {
-                    negate=true;
+                w = ap_getword_conf(sta->m_req->pool,&t);
+                if (*w == '!') {
+                    // A negated rule presumes success unless a match is found.
+                    status = true;
                     continue;
                 }
 
                 if (grpstatus && ap_table_get(grpstatus,w)) {
                     continue;
                 }
 
                 if (grpstatus && ap_table_get(grpstatus,w)) {
-                    // If we matched, then we're done with this rule either way and status is set to reflect the outcome.
-                    status = !negate;
-                    request.log(SPRequest::SPDebug, string("htaccess: require group ") + (negate ? "rejecting (" : "accepting (") + w + ")");
+                    // If we matched, then we're done with this rule either way and we flip status to reflect the outcome.
+                    status = !status;
+                    request.log(SPRequest::SPDebug, string("htaccess: require group ") + (!status ? "rejecting (" : "accepting (") + w + ")");
                     break;
                 }
             }
         }
         else if (!strcmp(w,"authnContextClassRef") || !strcmp(w,"authnContextDeclRef")) {
             const char* ref = !strcmp(w,"authnContextClassRef") ? session->getAuthnContextClassRef() : session->getAuthnContextDeclRef();
                     break;
                 }
             }
         }
         else if (!strcmp(w,"authnContextClassRef") || !strcmp(w,"authnContextDeclRef")) {
             const char* ref = !strcmp(w,"authnContextClassRef") ? session->getAuthnContextClassRef() : session->getAuthnContextDeclRef();
-            bool regexp=false,negate=false;
-            while (ref && *t) {
-                w=ap_getword_conf(sta->m_req->pool,&t);
-                if (*w=='~') {
-                    regexp=true;
-                    continue;
-                }
-                else if (*w=='!') {
-                    negate=true;
-                    if (*(w+1)=='~')
+            if (ref && *ref) {
+                bool regexp = false;
+                while (ref && *t) {
+                    w = ap_getword_conf(sta->m_req->pool,&t);
+                    if (*w == '~') {
                         regexp=true;
                         regexp=true;
-                    continue;
-                }
+                        continue;
+                    }
+                    else if (*w == '!') {
+                        // A negated rule presumes success unless a match is found.
+                        status = true;
+                        if (*(w+1)=='~')
+                            regexp = true;
+                        continue;
+                    }
 
 
-                // Figure out if there's a match.
-                bool match = false;
-                if (regexp) {
-                    try {
-                        // To do regex matching, we have to convert from UTF-8.
-                        RegularExpression re(w);
-                        match = re.matches(ref);
+                    // Figure out if there's a match.
+                    bool match = false;
+                    if (regexp) {
+                        try {
+                            // To do regex matching, we have to convert from UTF-8.
+                            RegularExpression re(w);
+                            match = re.matches(ref);
+                        }
+                        catch (XMLException& ex) {
+                            auto_ptr_char tmp(ex.getMessage());
+                            request.log(SPRequest::SPError,
+                                string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
+                        }
                     }
                     }
-                    catch (XMLException& ex) {
-                        auto_ptr_char tmp(ex.getMessage());
-                        request.log(SPRequest::SPError,
-                            string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
+                    else if (!strcmp(w,ref)) {
+                        match = true;
                     }
                     }
-                }
-                else if (!strcmp(w,ref)) {
-                    match = true;
-                }
 
 
-                if (match) {
-                    // If we matched, then we're done with this rule either way and status is set to reflect the outcome.
-                    status = !negate;
-                    if (request.isPriorityEnabled(SPRequest::SPDebug))
-                        request.log(SPRequest::SPDebug,
-                            string("htaccess: require authnContext ") + (negate ? "rejecting (" : "accepting (") + ref + ")");
-                    break;
+                    if (match) {
+                        // If we matched, then we're done with this rule either way and we flip status to reflect the outcome.
+                        status = !status;
+                        if (request.isPriorityEnabled(SPRequest::SPDebug))
+                            request.log(SPRequest::SPDebug,
+                                string("htaccess: require authnContext ") + (!status ? "rejecting (" : "accepting (") + ref + ")");
+                        break;
+                    }
                 }
             }
                 }
             }
+            else if (request.isPriorityEnabled(SPRequest::SPDebug)) {
+                request.log(SPRequest::SPDebug, "htaccess: require authnContext rejecting session with no context associated");
+            }
         }
         else if (!session) {
             request.log(SPRequest::SPError, string("htaccess: require ") + w + " not given a valid session, are you using lazy sessions?");
         }
         else if (!session) {
             request.log(SPRequest::SPError, string("htaccess: require ") + w + " not given a valid session, are you using lazy sessions?");
@@ -1439,7 +1459,7 @@ static command_rec shire_cmds[] = {
    OR_AUTHCFG, TAKE1, "Set Shibboleth applicationId property for content"},
   {"ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
    (void *) XtOffsetOf (shib_dir_config, bBasicHijack),
    OR_AUTHCFG, TAKE1, "Set Shibboleth applicationId property for content"},
   {"ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
    (void *) XtOffsetOf (shib_dir_config, bBasicHijack),
-   OR_AUTHCFG, FLAG, "Respond to AuthType Basic and convert to shibboleth"},
+   OR_AUTHCFG, FLAG, "(DEPRECATED) Respond to AuthType Basic and convert to shibboleth"},
   {"ShibRequireSession", (config_fn_t)ap_set_flag_slot,
    (void *) XtOffsetOf (shib_dir_config, bRequireSession),
    OR_AUTHCFG, FLAG, "Initiates a new session if one does not exist"},
   {"ShibRequireSession", (config_fn_t)ap_set_flag_slot,
    (void *) XtOffsetOf (shib_dir_config, bRequireSession),
    OR_AUTHCFG, FLAG, "Initiates a new session if one does not exist"},
@@ -1501,6 +1521,8 @@ module MODULE_VAR_EXPORT mod_shib = {
 
 #elif defined(SHIB_APACHE_20) || defined(SHIB_APACHE_22)
 
 
 #elif defined(SHIB_APACHE_20) || defined(SHIB_APACHE_22)
 
+//static const char * const authnPre[] = { "mod_gss.c", nullptr };
+
 extern "C" void shib_register_hooks (apr_pool_t *p)
 {
 #ifdef SHIB_DEFERRED_HEADERS
 extern "C" void shib_register_hooks (apr_pool_t *p)
 {
 #ifdef SHIB_DEFERRED_HEADERS
@@ -1511,7 +1533,14 @@ extern "C" void shib_register_hooks (apr_pool_t *p)
   ap_hook_post_read_request(shib_post_read, nullptr, nullptr, APR_HOOK_MIDDLE);
 #endif
   ap_hook_child_init(shib_child_init, nullptr, nullptr, APR_HOOK_MIDDLE);
   ap_hook_post_read_request(shib_post_read, nullptr, nullptr, APR_HOOK_MIDDLE);
 #endif
   ap_hook_child_init(shib_child_init, nullptr, nullptr, APR_HOOK_MIDDLE);
-  ap_hook_check_user_id(shib_check_user, nullptr, nullptr, APR_HOOK_MIDDLE);
+  const char* prereq = getenv("SHIBSP_APACHE_PREREQ");
+  if (prereq && *prereq) {
+    const char* const authnPre[] = { prereq, nullptr };
+    ap_hook_check_user_id(shib_check_user, authnPre, nullptr, APR_HOOK_MIDDLE);
+  }
+  else {
+    ap_hook_check_user_id(shib_check_user, nullptr, nullptr, APR_HOOK_MIDDLE);
+  }
   ap_hook_auth_checker(shib_auth_checker, nullptr, nullptr, APR_HOOK_FIRST);
   ap_hook_handler(shib_handler, nullptr, nullptr, APR_HOOK_LAST);
   ap_hook_fixups(shib_fixups, nullptr, nullptr, APR_HOOK_MIDDLE);
   ap_hook_auth_checker(shib_auth_checker, nullptr, nullptr, APR_HOOK_FIRST);
   ap_hook_handler(shib_handler, nullptr, nullptr, APR_HOOK_LAST);
   ap_hook_fixups(shib_fixups, nullptr, nullptr, APR_HOOK_MIDDLE);
@@ -1527,6 +1556,8 @@ static command_rec shib_cmds[] = {
         RSRC_CONF, "Path to shibboleth2.xml config file"),
     AP_INIT_TAKE1("ShibCatalogs", (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
         RSRC_CONF, "Paths of XML schema catalogs"),
         RSRC_CONF, "Path to shibboleth2.xml config file"),
     AP_INIT_TAKE1("ShibCatalogs", (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
         RSRC_CONF, "Paths of XML schema catalogs"),
+    AP_INIT_TAKE1("ShibGSSKey", (config_fn_t)ap_set_global_string_slot, &g_szGSSContextKey,
+        RSRC_CONF, "Name of user data key containing GSS context established by GSS module"),
 
     AP_INIT_TAKE1("ShibURLScheme", (config_fn_t)shib_set_server_string_slot,
         (void *) offsetof (shib_server_config, szScheme),
 
     AP_INIT_TAKE1("ShibURLScheme", (config_fn_t)shib_set_server_string_slot,
         (void *) offsetof (shib_server_config, szScheme),
@@ -1543,7 +1574,7 @@ static command_rec shib_cmds[] = {
         OR_AUTHCFG, "Set Shibboleth applicationId property for content"),
     AP_INIT_FLAG("ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bBasicHijack),
         OR_AUTHCFG, "Set Shibboleth applicationId property for content"),
     AP_INIT_FLAG("ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bBasicHijack),
-        OR_AUTHCFG, "Respond to AuthType Basic and convert to shibboleth"),
+        OR_AUTHCFG, "(DEPRECATED) Respond to AuthType Basic and convert to shibboleth"),
     AP_INIT_FLAG("ShibRequireSession", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bRequireSession),
         OR_AUTHCFG, "Initiates a new session if one does not exist"),
     AP_INIT_FLAG("ShibRequireSession", (config_fn_t)ap_set_flag_slot,
         (void *) offsetof (shib_dir_config, bRequireSession),
         OR_AUTHCFG, "Initiates a new session if one does not exist"),
index 3c1efba..e460240 100755 (executable)
@@ -1,5 +1,7 @@
 #! /bin/sh
 
 #! /bin/sh
 
+DECLS=1
+
 SAML1=0
 SAML2=0
 ARTIFACT=0
 SAML1=0
 SAML2=0
 ARTIFACT=0
@@ -21,7 +23,7 @@ SAML20PAOS="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
 SAML1POST="urn:oasis:names:tc:SAML:1.0:profiles:browser-post"
 SAML1ART="urn:oasis:names:tc:SAML:1.0:profiles:artifact-01"
 
 SAML1POST="urn:oasis:names:tc:SAML:1.0:profiles:browser-post"
 SAML1ART="urn:oasis:names:tc:SAML:1.0:profiles:artifact-01"
 
-while getopts a:c:e:f:h:n:o:s:t:u:12ADLN c
+while getopts a:c:e:f:h:n:o:s:t:u:12ADLNO c
      do
          case $c in
            c)   CERTS[${#CERTS[*]}]=$OPTARG;;
      do
          case $c in
            c)   CERTS[${#CERTS[*]}]=$OPTARG;;
@@ -40,7 +42,8 @@ while getopts a:c:e:f:h:n:o:s:t:u:12ADLN c
            D)   DS=1;;
            L)   LOGOUT=1;;
            N)   NAMEIDMGMT=1;;
            D)   DS=1;;
            L)   LOGOUT=1;;
            N)   NAMEIDMGMT=1;;
-           \?)  echo metagen [-12ADLN] -c cert1 [-c cert2 ...] -h host1 [-h host2 ...] [-e entityID]
+           O)   DECLS=0;;
+           \?)  echo metagen [-12ADLNO] -c cert1 [-c cert2 ...] -h host1 [-h host2 ...] [-e entityID]
                 exit 1;;
          esac
      done
                 exit 1;;
          esac
      done
@@ -63,7 +66,11 @@ do
 done
 
 if [ -z $ENTITYID ] ; then
 done
 
 if [ -z $ENTITYID ] ; then
-    ENTITYID=https://${HOSTS[0]}/shibboleth
+    if [ ${#HOSTS[*]} -eq 0 ] ; then
+        ENTITYID=https://${NAKEDHOSTS[0]}/shibboleth
+    else
+        ENTITYID=https://${HOSTS[0]}/shibboleth
+    fi
 fi
 
 # Establish protocols and bindings.
 fi
 
 # Establish protocols and bindings.
@@ -88,9 +95,9 @@ if [ $LOGOUT -eq 1 -o $NAMEIDMGMT -eq 1 ] ; then
 fi
 
 if [ $SAML1 -eq 1 -a $SAML2 -eq 1 ] ; then
 fi
 
 if [ $SAML1 -eq 1 -a $SAML2 -eq 1 ] ; then
-    PROTENUM="$SAML20PROT $SAML11PROT $SAML10PROT"
+    PROTENUM="$SAML20PROT $SAML11PROT"
 elif [ $SAML1 -eq 1 ] ; then
 elif [ $SAML1 -eq 1 ] ; then
-    PROTENUM="$SAML11PROT $SAML10PROT"
+    PROTENUM="$SAML11PROT"
 else
     PROTENUM="$SAML20PROT"
 fi
 else
     PROTENUM="$SAML20PROT"
 fi
@@ -122,8 +129,17 @@ if [ $SAML2 -eq 1 ] ; then
     ACSLOC[${#ACSLOC[*]}]="SAML2/ECP"
 fi
 
     ACSLOC[${#ACSLOC[*]}]="SAML2/ECP"
 fi
 
+if [ $DECLS -eq 1 ] ; then
+    DECLS="xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" "
+    if [ $DS -eq 1 ] ; then
+        DECLS="${DECLS}xmlns:disco=\"urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol\" "
+    fi
+else
+    DECLS=""
+fi
+
 cat <<EOF
 cat <<EOF
-<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="${ENTITYID}">
+<md:EntityDescriptor ${DECLS}entityID="${ENTITYID}">
   <md:SPSSODescriptor protocolSupportEnumeration="${PROTENUM}">
 EOF
 
   <md:SPSSODescriptor protocolSupportEnumeration="${PROTENUM}">
 EOF
 
@@ -138,7 +154,7 @@ count=1
 for h in ${HOSTS[@]}
 do
   cat << EOF
 for h in ${HOSTS[@]}
 do
   cat << EOF
-      <DiscoveryResponse xmlns="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Location="https://$h/Shibboleth.sso/DS" index="$count"/>
+      <disco:DiscoveryResponse Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Location="https://$h/Shibboleth.sso/DS" index="$count"/>
 EOF
   let "count++"
 done
 EOF
   let "count++"
 done
@@ -146,7 +162,7 @@ done
 for h in ${NAKEDHOSTS[@]}
 do
   cat << EOF
 for h in ${NAKEDHOSTS[@]}
 do
   cat << EOF
-      <DiscoveryResponse xmlns="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Location="http://$h/Shibboleth.sso/DS" index="$count"/>
+      <disco:DiscoveryResponse xmlns="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Location="http://$h/Shibboleth.sso/DS" index="$count"/>
 EOF
   let "count++"
 done
 EOF
   let "count++"
 done
@@ -286,9 +302,10 @@ if [ -n "$ORGNAME" ] ; then
 EOF
 fi
 
 EOF
 fi
 
-for c in ${ADMIN[@]}
+count=${#ADMIN[*]}
+for (( i=0; i<count; i++ ))
 do
 do
-  c=(${c//\// })
+  IFS="/"; declare -a c=(${ADMIN[$i]})
   cat <<EOF
   <md:ContactPerson contactType="administrative">
     <md:GivenName>${c[0]}</md:GivenName>
   cat <<EOF
   <md:ContactPerson contactType="administrative">
     <md:GivenName>${c[0]}</md:GivenName>
@@ -298,9 +315,10 @@ do
 EOF
 done
 
 EOF
 done
 
-for c in ${SUP[@]}
+count=${#SUP[*]}
+for (( i=0; i<count; i++ ))
 do
 do
-  c=(${c//\// })
+  IFS="/"; declare -a c=(${SUP[$i]})
   cat <<EOF
   <md:ContactPerson contactType="support">
     <md:GivenName>${c[0]}</md:GivenName>
   cat <<EOF
   <md:ContactPerson contactType="support">
     <md:GivenName>${c[0]}</md:GivenName>
@@ -310,9 +328,10 @@ do
 EOF
 done
 
 EOF
 done
 
-for c in ${TECH[@]}
+count=${#TECH[*]}
+for (( i=0; i<count; i++ ))
 do
 do
-  c=(${c//\// })
+  IFS="/"; declare -a c=(${TECH[$i]})
   cat <<EOF
   <md:ContactPerson contactType="technical">
     <md:GivenName>${c[0]}</md:GivenName>
   cat <<EOF
   <md:ContactPerson contactType="technical">
     <md:GivenName>${c[0]}</md:GivenName>
@@ -324,4 +343,5 @@ done
 
 cat <<EOF 
 </md:EntityDescriptor>
 
 cat <<EOF 
 </md:EntityDescriptor>
+
 EOF
 EOF
index 0be3acf..d644455 100644 (file)
@@ -14,8 +14,7 @@
 # Default-Start: 3 5
 # Default-Stop: 0 1 2 6 
 # Short-Description: Shibboleth 2.x Service Provider Daemon
 # Default-Start: 3 5
 # Default-Stop: 0 1 2 6 
 # Short-Description: Shibboleth 2.x Service Provider Daemon
-# Description: Starts the separate daemon used by the Shibboleth
-# Apache module to manage state and SAML interactions.
+# Description: Starts the separate daemon used by the Shibboleth Apache module to manage state and SAML interactions.
 ### END INIT INFO
 #
  
 ### END INIT INFO
 #
  
index 95b3a47..50a6327 100644 (file)
@@ -1,10 +1,11 @@
-AC_PREREQ([2.67])
+AC_PREREQ([2.50])
 AC_INIT([shibboleth],[2.4],[https://bugs.internet2.edu/],[shibboleth])
 AC_CONFIG_SRCDIR(shibsp)
 AC_CONFIG_AUX_DIR(build-aux)
 AC_CONFIG_MACRO_DIR(m4)
 AM_INIT_AUTOMAKE
 AC_INIT([shibboleth],[2.4],[https://bugs.internet2.edu/],[shibboleth])
 AC_CONFIG_SRCDIR(shibsp)
 AC_CONFIG_AUX_DIR(build-aux)
 AC_CONFIG_MACRO_DIR(m4)
 AM_INIT_AUTOMAKE
-LT_INIT
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
 
 # Docygen features
 DX_HTML_FEATURE(ON)
 
 # Docygen features
 DX_HTML_FEATURE(ON)
@@ -35,7 +36,6 @@ AC_CONFIG_FILES([shibboleth.spec pkginfo Portfile])
 
 AC_PROG_CC([gcc gcc3 cc])
 AC_PROG_CXX([g++ g++3 c++ CC])
 
 AC_PROG_CC([gcc gcc3 cc])
 AC_PROG_CXX([g++ g++3 c++ CC])
-AC_DISABLE_STATIC
 AC_CANONICAL_HOST
 
 if test "$GCC" = "yes" ; then
 AC_CANONICAL_HOST
 
 if test "$GCC" = "yes" ; then
@@ -72,6 +72,7 @@ AC_STRUCT_TM
 # Checks for library functions.
 AC_FUNC_STRFTIME
 AC_FUNC_STRERROR_R
 # Checks for library functions.
 AC_FUNC_STRFTIME
 AC_FUNC_STRERROR_R
+AC_CHECK_HEADERS([sys/utsname.h])
 AC_CHECK_FUNCS([strchr strdup strstr timegm gmtime_r strtok_r strcasecmp])
 
 # checks for pthreads
 AC_CHECK_FUNCS([strchr strdup strstr timegm gmtime_r strtok_r strcasecmp])
 
 # checks for pthreads
@@ -118,25 +119,21 @@ AC_CXX_REQUIRE_STL
 # Thank you Solaris, really.
 AC_MSG_CHECKING(for ctime_r)
 if test -z "$ac_cv_ctime_args"; then
 # Thank you Solaris, really.
 AC_MSG_CHECKING(for ctime_r)
 if test -z "$ac_cv_ctime_args"; then
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[
-        time_t clock;
-        char buf[26];
-        ctime_r(&clock, buf);
-    ]])],[ac_cv_ctime_args=2],[])
-
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[
-        time_t clock;
-        char buf[26];
-        ctime_r(&clock, buf, 26);
-    ]])],[ac_cv_ctime_args=3],[])
+    AC_COMPILE_IFELSE(
+        [AC_LANG_PROGRAM([[#include <time.h>]], [[time_t clock; char buf[26]; ctime_r(&clock, buf);]])],
+        [ac_cv_ctime_args=2],[])
+
+    AC_COMPILE_IFELSE(
+        [AC_LANG_PROGRAM([[#include <time.h>]], [[time_t clock; char buf[26]; ctime_r(&clock, buf, 26);]])],
+        [ac_cv_ctime_args=3],[])
 fi
 if test -z "$ac_cv_ctime_args"; then
     AC_MSG_RESULT(no)
 else
     if test "$ac_cv_ctime_args" = 2; then
 fi
 if test -z "$ac_cv_ctime_args"; then
     AC_MSG_RESULT(no)
 else
     if test "$ac_cv_ctime_args" = 2; then
-        AC_DEFINE(HAVE_CTIME_R_2,1,[Define if ctime_r is present with 2 parameters.])
+        AC_DEFINE([HAVE_CTIME_R_2],[1],[Define if ctime_r is present with 2 parameters.])
     elif test "$ac_cv_ctime_args" = 3; then
     elif test "$ac_cv_ctime_args" = 3; then
-        AC_DEFINE(HAVE_CTIME_R_3,1,[Define if ctime_r is present with 3 parameters.])
+        AC_DEFINE([HAVE_CTIME_R_3],[1],[Define if ctime_r is present with 3 parameters.])
     fi
     AC_MSG_RESULT([yes, and it takes $ac_cv_ctime_args arguments])
 fi 
     fi
     AC_MSG_RESULT([yes, and it takes $ac_cv_ctime_args arguments])
 fi 
@@ -222,7 +219,9 @@ AC_COMPILE_IFELSE(
     [AC_MSG_RESULT([no])])
 
 AC_MSG_CHECKING([whether Xerces DOMNodeFilter API returns a short])
     [AC_MSG_RESULT([no])])
 
 AC_MSG_CHECKING([whether Xerces DOMNodeFilter API returns a short])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <xercesc/dom/DOM.hpp>]], [[using namespace XERCES_CPP_NAMESPACE;
+AC_COMPILE_IFELSE(
+    [AC_LANG_PROGRAM([[#include <xercesc/dom/DOM.hpp>]],
+        [[using namespace XERCES_CPP_NAMESPACE;
       class Blocker : public DOMNodeFilter {
       public:
         short acceptNode(const DOMNode* node) const {
       class Blocker : public DOMNodeFilter {
       public:
         short acceptNode(const DOMNode* node) const {
@@ -230,8 +229,9 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <xercesc/dom/DOM.hpp>]], [[using n
         }
       };
       static Blocker g_Blocker;
         }
       };
       static Blocker g_Blocker;
-    ]])],[AC_MSG_RESULT([yes])
-    AC_DEFINE([SHIBSP_XERCESC_SHORT_ACCEPTNODE],[1],[Define to 1 if Xerces DOMNodeFilter API returns a short.])],[AC_MSG_RESULT([no])])
+    ]])],
+    [AC_MSG_RESULT([yes])AC_DEFINE([SHIBSP_XERCESC_SHORT_ACCEPTNODE],[1],[Define to 1 if Xerces DOMNodeFilter API returns a short.])],
+    [AC_MSG_RESULT([no])])
 
 #XML-Tooling settings
 AC_ARG_WITH(xmltooling,
 
 #XML-Tooling settings
 AC_ARG_WITH(xmltooling,
@@ -336,16 +336,15 @@ save_LIBS="$LIBS"
 LIBS="$XMLSEC_LIBS $LIBS"
 
 AC_CHECK_HEADER([saml/saml2/metadata/Metadata.h],,AC_MSG_ERROR([unable to find OpenSAML header files]))
 LIBS="$XMLSEC_LIBS $LIBS"
 
 AC_CHECK_HEADER([saml/saml2/metadata/Metadata.h],,AC_MSG_ERROR([unable to find OpenSAML header files]))
-AC_LINK_IFELSE([AC_LANG_PROGRAM([[
-#include <saml/SAMLConfig.h>
-#include <saml/version.h>
-       ]], [[
-#if _OPENSAML_VERSION >= 20400
+AC_LINK_IFELSE(
+    [AC_LANG_PROGRAM([[#include <saml/SAMLConfig.h>
+#include <saml/version.h>]],
+[[#if _OPENSAML_VERSION >= 20400
 opensaml::SAMLConfig::getConfig();
 #else
 #error Need OpenSAML version 2.4 or higher
 opensaml::SAMLConfig::getConfig();
 #else
 #error Need OpenSAML version 2.4 or higher
-#endif
-       ]])],[AC_DEFINE(HAVE_SAML,1,[Define if saml library was found])],[AC_MSG_ERROR([unable to link with OpenSAML, or version was too old])
+#endif]])],
+    ,[AC_MSG_ERROR([unable to link with OpenSAML, or version was too old])
        ])
 
 # restore master libs
        ])
 
 # restore master libs
@@ -926,11 +925,13 @@ if test "$build_odbc" = "yes" ; then
       save_LIBS="$LIBS"
       LIBS="$LIBS $ODBC_LIBS"
       AC_MSG_CHECKING(if we can link againt ODBC)
       save_LIBS="$LIBS"
       LIBS="$LIBS $ODBC_LIBS"
       AC_MSG_CHECKING(if we can link againt ODBC)
-      AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sql.h>
-         #include <sqlext.h>
-         #include <stdio.h>]], [[SQLSetEnvAttr(SQL_NULL_HANDLE, SQL_ATTR_CONNECTION_POOLING, (void*)SQL_CP_ONE_PER_HENV, 0)]])],[have_odbc_libs=yes],[have_odbc_libs=no])
+      AC_LINK_IFELSE(
+        [AC_LANG_PROGRAM([[#include <sql.h>
+ #include <sqlext.h>
+ #include <stdio.h>]],
+            [[SQLSetEnvAttr(SQL_NULL_HANDLE, SQL_ATTR_CONNECTION_POOLING, (void*)SQL_CP_ONE_PER_HENV, 0)]])],
+        [have_odbc_libs=yes],[have_odbc_libs=no])
       LIBS="$save_LIBS"
       LIBS="$save_LIBS"
-
       if test "$have_odbc_libs" = no ; then
          if test "$odbc_enabled" = "yes" ; then
             AC_MSG_ERROR([unable to link with ODBC Library])
       if test "$have_odbc_libs" = no ; then
          if test "$odbc_enabled" = "yes" ; then
             AC_MSG_ERROR([unable to link with ODBC Library])
@@ -952,6 +953,142 @@ if test "$have_odbc_libs" = yes ; then
    AC_SUBST(ODBC_LIBS)
 fi
 
    AC_SUBST(ODBC_LIBS)
 fi
 
+# GSS-API checking
+
+GSSAPI_ROOT="/usr"
+AC_ARG_WITH(gssapi-includes,
+  AS_HELP_STRING([--with-gssapi-includes=DIR],[Specify location of GSSAPI header]),
+  [ GSSAPI_INCS="-I$withval"
+    want_gss="yes" ]
+)
+
+AC_ARG_WITH(gssapi-libs,
+  AS_HELP_STRING([--with-gssapi-libs=DIR],[Specify location of GSSAPI libs]),
+  [ GSSAPI_LIB_DIR="-L$withval"
+    want_gss="yes" ]
+)
+
+AC_ARG_WITH(gssapi,
+  AS_HELP_STRING([--with-gssapi=DIR],[Where to look for GSSAPI]),
+  [ GSSAPI_ROOT="$withval"
+  if test x"$GSSAPI_ROOT" != xno; then
+    want_gss="yes"
+    if test x"$GSSAPI_ROOT" = xyes; then
+      dnl if yes, then use default root
+      GSSAPI_ROOT="/usr"
+    fi
+  fi
+])
+
+save_CPPFLAGS="$CPPFLAGS"
+AC_MSG_CHECKING([if GSSAPI support is requested])
+if test x"$want_gss" = xyes; then
+  AC_MSG_RESULT(yes)
+
+  if test -z "$GSSAPI_INCS"; then
+     if test -f "$GSSAPI_ROOT/bin/krb5-config"; then
+        GSSAPI_INCS=`$GSSAPI_ROOT/bin/krb5-config --cflags gssapi`
+     elif test "$GSSAPI_ROOT" != "yes"; then
+        GSSAPI_INCS="-I$GSSAPI_ROOT/include"
+     fi
+  fi
+
+  CPPFLAGS="$CPPFLAGS $GSSAPI_INCS"
+
+  AC_CHECK_HEADER(gss.h,
+    [
+      dnl found in the given dirs
+      AC_DEFINE([HAVE_GSSGNU],[1],[if you have the GNU gssapi libraries])
+      gnu_gss=yes
+    ],
+    [
+      dnl not found, check Heimdal or MIT
+      AC_CHECK_HEADERS([gssapi/gssapi.h], [], [not_mit=1])
+      AC_CHECK_HEADERS(
+        [gssapi/gssapi_generic.h gssapi/gssapi_krb5.h],
+        [],
+        [not_mit=1],
+        [
+AC_INCLUDES_DEFAULT
+#ifdef HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#endif
+        ])
+      if test "x$not_mit" = "x1"; then
+        dnl MIT not found, check for Heimdal
+        AC_CHECK_HEADER([gssapi.h],
+            [
+              dnl found
+              AC_DEFINE([HAVE_GSSHEIMDAL],[1],[if you have the Heimdal gssapi libraries])
+            ],
+            [
+              dnl no header found, disabling GSS
+              want_gss=no
+              AC_MSG_WARN([disabling GSSAPI since no header files was found])
+            ]
+          )
+      else
+        dnl MIT found
+        AC_DEFINE([HAVE_GSSMIT],[1],[if you have the MIT gssapi libraries])
+        dnl check if we have a really old MIT kerberos (<= 1.2)
+        AC_MSG_CHECKING([if gssapi headers declare GSS_C_NT_HOSTBASED_SERVICE])
+        AC_COMPILE_IFELSE([
+          AC_LANG_PROGRAM([[
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+          ]],[[
+            gss_import_name(
+                            (OM_uint32 *)0,
+                            (gss_buffer_t)0,
+                            GSS_C_NT_HOSTBASED_SERVICE,
+                            (gss_name_t *)0);
+          ]])
+        ],[
+          AC_MSG_RESULT([yes])
+        ],[
+          AC_MSG_RESULT([no])
+          AC_DEFINE([HAVE_OLD_GSSMIT],[1],[if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE])
+        ])
+      fi
+    ]
+  )
+else
+  AC_MSG_RESULT(no)
+fi
+if test x"$want_gss" = xyes; then
+  AC_DEFINE([HAVE_GSSAPI],[1],[if you have the gssapi libraries])
+
+  if test -n "$gnu_gss"; then
+    LDFLAGS="$LDFLAGS $GSSAPI_LIB_DIR"
+    LIBS="$LIBS -lgss"
+  elif test -z "$GSSAPI_LIB_DIR"; then
+     case $host in
+     *-*-darwin*)
+        LIBS="$LIBS -lgssapi_krb5 -lresolv"
+        ;;
+     *)
+        if test -f "$GSSAPI_ROOT/bin/krb5-config"; then
+           dnl krb5-config doesn't have --libs-only-L or similar, put everything
+           dnl into LIBS
+           gss_libs=`$GSSAPI_ROOT/bin/krb5-config --libs gssapi`
+           LIBS="$LIBS $gss_libs"
+        elif test "$GSSAPI_ROOT" != "yes"; then
+           LDFLAGS="$LDFLAGS -L$GSSAPI_ROOT/lib$libsuff"
+           LIBS="$LIBS -lgssapi"
+        else
+           LIBS="$LIBS -lgssapi"
+        fi
+        ;;
+     esac
+  else
+     LDFLAGS="$LDFLAGS $GSSAPI_LIB_DIR"
+     LIBS="$LIBS -lgssapi"
+  fi
+else
+  CPPFLAGS="$save_CPPFLAGS"
+fi
+
 
 AC_SUBST(WANT_SUBDIRS)
 
 
 AC_SUBST(WANT_SUBDIRS)
 
index 8fe5fa7..1ff0bd2 100644 (file)
@@ -12,3 +12,5 @@ Source code for these libraries is available on request.
 
 This project includes software developed by the National Research Council 
 of Canada.
 
 This project includes software developed by the National Research Council 
 of Canada.
+
+This project includes software developed by the Danish CLARIN Consortium.
index bf95425..d119da3 100644 (file)
         </complexContent>
     </complexType>
 
         </complexContent>
     </complexType>
 
+    <complexType name="Base64AttributeDecoder">
+        <annotation>
+            <documentation>
+                Decoder for attributes with base64-encoded string values.
+            </documentation>
+        </annotation>
+        <complexContent>
+            <extension base="am:AttributeDecoderType" />
+        </complexContent>
+    </complexType>
+
 </schema>
 </schema>
index 87eeab5..7c39b8e 100644 (file)
@@ -2,7 +2,7 @@
 <schema targetNamespace="urn:mace:shibboleth:2.0:native:sp:config"
        xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:conf="urn:mace:shibboleth:2.0:native:sp:config"
 <schema targetNamespace="urn:mace:shibboleth:2.0:native:sp:config"
        xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:conf="urn:mace:shibboleth:2.0:native:sp:config"
-    xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+  xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
        xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
        xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
        xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
        xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
        xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
        xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
     <attribute name="checkSpoofing" type="boolean"/>
     <attribute name="spoofKey" type="conf:string"/>
     <attribute name="catchAll" type="boolean"/>
     <attribute name="checkSpoofing" type="boolean"/>
     <attribute name="spoofKey" type="conf:string"/>
     <attribute name="catchAll" type="boolean"/>
+    <attribute name="extraAuthTypes" type="conf:listOfStrings"/>
     <anyAttribute namespace="##other" processContents="lax"/>
   </complexType>
 
     <anyAttribute namespace="##other" processContents="lax"/>
   </complexType>
 
index d510452..5888fbb 100644 (file)
@@ -2,14 +2,14 @@ Name:         @PACKAGE_NAME@
 Version:       @PACKAGE_VERSION@
 Release:       1
 Summary:    Open source system for attribute-based Web SSO
 Version:       @PACKAGE_VERSION@
 Release:       1
 Summary:    Open source system for attribute-based Web SSO
-Group:         System Environment/Libraries
+Group:         Productivity/Networking/Security
 Vendor:     Internet2
 License:       Apache 2.0
 URL:           http://shibboleth.internet2.edu/
 Source:     %{name}-sp-%{version}.tar.gz
 BuildRoot:     %{_tmppath}/%{name}-%{version}-root
 PreReq:     openssl, xmltooling-schemas, opensaml-schemas
 Vendor:     Internet2
 License:       Apache 2.0
 URL:           http://shibboleth.internet2.edu/
 Source:     %{name}-sp-%{version}.tar.gz
 BuildRoot:     %{_tmppath}/%{name}-%{version}-root
 PreReq:     openssl, xmltooling-schemas, opensaml-schemas
-%if 0%{?suse_version} > 1030
+%if 0%{?suse_version} > 1030 && 0%{?suse_version} < 1130
 PreReq:         %{insserv_prereq}
 BuildRequires:  libXerces-c-devel >= 2.8.0
 %else
 PreReq:         %{insserv_prereq}
 BuildRequires:  libXerces-c-devel >= 2.8.0
 %else
@@ -48,9 +48,9 @@ and Apache module(s).
 
 %package devel
 Summary:       Shibboleth development Headers
 
 %package devel
 Summary:       Shibboleth development Headers
-Group:         Development/Libraries
+Group:         Development/Libraries/C and C++
 Requires:      %{name} = %{version}-%{release}
 Requires:      %{name} = %{version}-%{release}
-%if 0%{?suse_version} > 1030
+%if 0%{?suse_version} > 1030 && 0%{?suse_version} < 1130
 Requires:      libXerces-c-devel >= 2.8.0
 %else
 Requires:      libxerces-c-devel >= 2.8.0
 Requires:      libXerces-c-devel >= 2.8.0
 %else
 Requires:      libxerces-c-devel >= 2.8.0
index b6c5e80..6f9b005 100644 (file)
@@ -50,6 +50,16 @@ void SPRequest::setAuthType(const char* authtype)
 {
 }
 
 {
 }
 
+#ifdef HAVE_GSSAPI
+GSSRequest::GSSRequest()
+{
+}
+
+GSSRequest::~GSSRequest()
+{
+}
+#endif
+
 AbstractSPRequest::AbstractSPRequest(const char* category)
     : m_sp(nullptr), m_mapper(nullptr), m_app(nullptr), m_sessionTried(false), m_session(nullptr),
         m_log(&Category::getInstance(category)), m_parser(nullptr)
 AbstractSPRequest::AbstractSPRequest(const char* category)
     : m_sp(nullptr), m_mapper(nullptr), m_app(nullptr), m_sessionTried(false), m_session(nullptr),
         m_log(&Category::getInstance(category)), m_parser(nullptr)
diff --git a/shibsp/GSSRequest.h b/shibsp/GSSRequest.h
new file mode 100644 (file)
index 0000000..cb1c56f
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  Copyright 2010 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/GSSRequest.h
+ *
+ * Interface to a GSS-authenticated request.
+ */
+
+#if !defined(__shibsp_gssreq_h__) && defined(HAVE_GSSAPI)
+#define __shibsp_gssreq_h__
+
+#include <shibsp/base.h>
+#include <xmltooling/io/GenericRequest.h>
+
+#ifdef HAVE_GSSGNU
+# include <gss.h>
+#elif defined HAVE_GSSMIT
+# include <gssapi/gssapi.h>
+# include <gssapi/gssapi_generic.h>
+#else
+# include <gssapi.h>
+#endif
+
+namespace shibsp {
+
+    /**
+     * Interface to a GSS-authenticated request.
+     */
+    class SHIBSP_API GSSRequest : public virtual xmltooling::GenericRequest
+    {
+    protected:
+        GSSRequest();
+    public:
+        virtual ~GSSRequest();
+
+        /**
+         * Returns the GSS-API context established for this request, or
+         * GSS_C_NO_CONTEXT if none is available.
+         *
+         * @return  a GSS-API context handle, or GSS_C_NO_CONTEXT
+         */
+        virtual gss_ctx_id_t getGSSContext() const=0;
+    };
+};
+
+#endif /* __shibsp_gssreq_h__ */
index 55072f9..1a9c00e 100644 (file)
@@ -31,6 +31,7 @@ libshibspinclude_HEADERS = \
        base.h \
        exceptions.h \
        paths.h \
        base.h \
        exceptions.h \
        paths.h \
+       GSSRequest.h \
        RequestMapper.h \
        ServiceProvider.h \
        SessionCache.h \
        RequestMapper.h \
        ServiceProvider.h \
        SessionCache.h \
@@ -164,6 +165,7 @@ libshibsp_lite_la_SOURCES = \
 
 libshibsp_la_SOURCES = \
        ${common_sources} \
 
 libshibsp_la_SOURCES = \
        ${common_sources} \
+       attribute/Base64AttributeDecoder.cpp \
        attribute/DOMAttributeDecoder.cpp \
        attribute/KeyInfoAttributeDecoder.cpp \
        attribute/NameIDAttributeDecoder.cpp \
        attribute/DOMAttributeDecoder.cpp \
        attribute/KeyInfoAttributeDecoder.cpp \
        attribute/NameIDAttributeDecoder.cpp \
index 30e4423..b358948 100644 (file)
@@ -163,6 +163,7 @@ void SHIBSP_API shibsp::registerServiceProviders()
 
 ServiceProvider::ServiceProvider()
 {
 
 ServiceProvider::ServiceProvider()
 {
+    m_authTypes.insert("shibboleth");
 }
 
 ServiceProvider::~ServiceProvider()
 }
 
 ServiceProvider::~ServiceProvider()
@@ -266,16 +267,18 @@ pair<bool,long> ServiceProvider::doAuthentication(SPRequest& request, bool handl
         pair<bool,bool> requireSession = settings.first->getBool("requireSession");
         pair<bool,const char*> requireSessionWith = settings.first->getString("requireSessionWith");
 
         pair<bool,bool> requireSession = settings.first->getBool("requireSession");
         pair<bool,const char*> requireSessionWith = settings.first->getString("requireSessionWith");
 
-        // If no session is required AND the AuthType (an Apache-derived concept) isn't shibboleth,
+        string lcAuthType;
+        if (authType.first) {
+            while (*authType.second)
+                lcAuthType += tolower(*authType.second++);
+        }
+
+        // If no session is required AND the AuthType (an Apache-derived concept) isn't recognized,
         // then we ignore this request and consider it unprotected. Apache might lie to us if
         // ShibBasicHijack is on, but that's up to it.
         if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first &&
         // then we ignore this request and consider it unprotected. Apache might lie to us if
         // ShibBasicHijack is on, but that's up to it.
         if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first &&
-#ifdef HAVE_STRCASECMP
-                (!authType.first || strcasecmp(authType.second,"shibboleth")))
-#else
-                (!authType.first || _stricmp(authType.second,"shibboleth")))
-#endif
-            return make_pair(true,request.returnDecline());
+                (!authType.first || m_authTypes.find(lcAuthType) == m_authTypes.end()))
+            return make_pair(true, request.returnDecline());
 
         // Fix for secadv 20050901
         clearHeaders(request);
 
         // Fix for secadv 20050901
         clearHeaders(request);
@@ -315,7 +318,7 @@ pair<bool,long> ServiceProvider::doAuthentication(SPRequest& request, bool handl
             return initiator->run(request,false);
         }
 
             return initiator->run(request,false);
         }
 
-        request.setAuthType("shibboleth");
+        request.setAuthType(lcAuthType.c_str());
 
         // We're done.  Everything is okay.  Nothing to report.  Nothing to do..
         // Let the caller decide how to proceed.
 
         // We're done.  Everything is okay.  Nothing to report.  Nothing to do..
         // Let the caller decide how to proceed.
@@ -349,16 +352,18 @@ pair<bool,long> ServiceProvider::doAuthorization(SPRequest& request) const
         pair<bool,bool> requireSession = settings.first->getBool("requireSession");
         pair<bool,const char*> requireSessionWith = settings.first->getString("requireSessionWith");
 
         pair<bool,bool> requireSession = settings.first->getBool("requireSession");
         pair<bool,const char*> requireSessionWith = settings.first->getString("requireSessionWith");
 
-        // If no session is required AND the AuthType (an Apache-derived concept) isn't shibboleth,
+        string lcAuthType;
+        if (authType.first) {
+            while (*authType.second)
+                lcAuthType += tolower(*authType.second++);
+        }
+
+        // If no session is required AND the AuthType (an Apache-derived concept) isn't recognized,
         // then we ignore this request and consider it unprotected. Apache might lie to us if
         // ShibBasicHijack is on, but that's up to it.
         if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first &&
         // then we ignore this request and consider it unprotected. Apache might lie to us if
         // ShibBasicHijack is on, but that's up to it.
         if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first &&
-#ifdef HAVE_STRCASECMP
-                (!authType.first || strcasecmp(authType.second,"shibboleth")))
-#else
-                (!authType.first || _stricmp(authType.second,"shibboleth")))
-#endif
-            return make_pair(true,request.returnDecline());
+                (!authType.first || m_authTypes.find(lcAuthType) == m_authTypes.end()))
+            return make_pair(true, request.returnDecline());
 
         // Do we have an access control plugin?
         if (settings.second) {
 
         // Do we have an access control plugin?
         if (settings.second) {
index 2486967..bd76b8c 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <shibsp/util/PropertySet.h>
 
 
 #include <shibsp/util/PropertySet.h>
 
+#include <set>
 #include <xmltooling/Lockable.h>
 
 namespace xmltooling {
 #include <xmltooling/Lockable.h>
 
 namespace xmltooling {
@@ -239,6 +240,10 @@ namespace shibsp {
          */
         virtual Remoted* lookupListener(const char* address) const;
 
          */
         virtual Remoted* lookupListener(const char* address) const;
 
+    protected:
+        /** The AuthTypes to "recognize" (defaults to "shibboleth"). */
+        std::set<std::string> m_authTypes;
+
     private:
         std::map<std::string,Remoted*> m_listenerMap;
     };
     private:
         std::map<std::string,Remoted*> m_listenerMap;
     };
index 6a7da4b..89f69bf 100644 (file)
@@ -56,6 +56,7 @@ namespace shibsp {
     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory KeyInfoAttributeDecoderFactory;
     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory DOMAttributeDecoderFactory;
     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory XMLAttributeDecoderFactory;
     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory KeyInfoAttributeDecoderFactory;
     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory DOMAttributeDecoderFactory;
     SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory XMLAttributeDecoderFactory;
+    SHIBSP_DLLLOCAL PluginManager<AttributeDecoder,xmltooling::QName,const DOMElement*>::Factory Base64AttributeDecoderFactory;
 
     static const XMLCh _StringAttributeDecoder[] = UNICODE_LITERAL_22(S,t,r,i,n,g,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _ScopedAttributeDecoder[] = UNICODE_LITERAL_22(S,c,o,p,e,d,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
 
     static const XMLCh _StringAttributeDecoder[] = UNICODE_LITERAL_22(S,t,r,i,n,g,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _ScopedAttributeDecoder[] = UNICODE_LITERAL_22(S,c,o,p,e,d,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
@@ -64,6 +65,11 @@ namespace shibsp {
     static const XMLCh _KeyInfoAttributeDecoder[] =UNICODE_LITERAL_23(K,e,y,I,n,f,o,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _DOMAttributeDecoder[] =    UNICODE_LITERAL_19(D,O,M,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _XMLAttributeDecoder[] =    UNICODE_LITERAL_19(X,M,L,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _KeyInfoAttributeDecoder[] =UNICODE_LITERAL_23(K,e,y,I,n,f,o,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _DOMAttributeDecoder[] =    UNICODE_LITERAL_19(D,O,M,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh _XMLAttributeDecoder[] =    UNICODE_LITERAL_19(X,M,L,A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
+    static const XMLCh _Base64AttributeDecoder[] = {
+        chLatin_B, chLatin_a, chLatin_s, chLatin_e, chDigit_6, chDigit_4,
+        chLatin_A, chLatin_t, chLatin_t, chLatin_r, chLatin_i, chLatin_b, chLatin_u, chLatin_t, chLatin_e,
+        chLatin_D, chLatin_e, chLatin_c, chLatin_o, chLatin_d, chLatin_e, chLatin_r, chNull
+    };
 
     static const XMLCh caseSensitive[] =           UNICODE_LITERAL_13(c,a,s,e,S,e,n,s,i,t,i,v,e);
     static const XMLCh hashAlg[] =                 UNICODE_LITERAL_7(h,a,s,h,A,l,g);
 
     static const XMLCh caseSensitive[] =           UNICODE_LITERAL_13(c,a,s,e,S,e,n,s,i,t,i,v,e);
     static const XMLCh hashAlg[] =                 UNICODE_LITERAL_7(h,a,s,h,A,l,g);
@@ -79,6 +85,7 @@ xmltooling::QName shibsp::NameIDFromScopedAttributeDecoderType(shibspconstants::
 xmltooling::QName shibsp::KeyInfoAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _KeyInfoAttributeDecoder);
 xmltooling::QName shibsp::DOMAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _DOMAttributeDecoder);
 xmltooling::QName shibsp::XMLAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _XMLAttributeDecoder);
 xmltooling::QName shibsp::KeyInfoAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _KeyInfoAttributeDecoder);
 xmltooling::QName shibsp::DOMAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _DOMAttributeDecoder);
 xmltooling::QName shibsp::XMLAttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _XMLAttributeDecoder);
+xmltooling::QName shibsp::Base64AttributeDecoderType(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _Base64AttributeDecoder);
 
 void shibsp::registerAttributeDecoders()
 {
 
 void shibsp::registerAttributeDecoders()
 {
@@ -90,6 +97,7 @@ void shibsp::registerAttributeDecoders()
     conf.AttributeDecoderManager.registerFactory(KeyInfoAttributeDecoderType, KeyInfoAttributeDecoderFactory);
     conf.AttributeDecoderManager.registerFactory(DOMAttributeDecoderType, DOMAttributeDecoderFactory);
     conf.AttributeDecoderManager.registerFactory(XMLAttributeDecoderType, XMLAttributeDecoderFactory);
     conf.AttributeDecoderManager.registerFactory(KeyInfoAttributeDecoderType, KeyInfoAttributeDecoderFactory);
     conf.AttributeDecoderManager.registerFactory(DOMAttributeDecoderType, DOMAttributeDecoderFactory);
     conf.AttributeDecoderManager.registerFactory(XMLAttributeDecoderType, XMLAttributeDecoderFactory);
+    conf.AttributeDecoderManager.registerFactory(Base64AttributeDecoderType, Base64AttributeDecoderFactory);
 }
 
 AttributeDecoder::AttributeDecoder(const DOMElement *e)
 }
 
 AttributeDecoder::AttributeDecoder(const DOMElement *e)
index 24054f2..03b7485 100644 (file)
@@ -110,6 +110,9 @@ namespace shibsp {
     /** Decodes arbitrary XML into an XMLAttribute. */
     extern SHIBSP_API xmltooling::QName XMLAttributeDecoderType;
 
     /** Decodes arbitrary XML into an XMLAttribute. */
     extern SHIBSP_API xmltooling::QName XMLAttributeDecoderType;
 
+    /** Decodes base64-encoded data into a SimpleAttribute. */
+    extern SHIBSP_API xmltooling::QName Base64AttributeDecoderType;
+
     /** Registers built-in AttributeDecoders into the runtime. */
     void registerAttributeDecoders();
 };
     /** Registers built-in AttributeDecoders into the runtime. */
     void registerAttributeDecoders();
 };
diff --git a/shibsp/attribute/Base64AttributeDecoder.cpp b/shibsp/attribute/Base64AttributeDecoder.cpp
new file mode 100644 (file)
index 0000000..6f1edd7
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ *  Copyright 2010 The Danish CLARIN Consortium
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Base64AttributeDecoder.cpp
+ *
+ * Decodes SAML containing base64-encoded values into SimpleAttributes.
+ */
+
+#include "internal.h"
+#include "attribute/AttributeDecoder.h"
+#include "attribute/SimpleAttribute.h"
+
+#include <saml/saml1/core/Assertions.h>
+#include <saml/saml2/core/Assertions.h>
+
+#include <xercesc/util/Base64.hpp>
+
+using namespace shibsp;
+using namespace opensaml::saml1;
+using namespace opensaml::saml2;
+using namespace xmltooling::logging;
+using namespace xmltooling;
+using namespace std;
+
+namespace shibsp {
+    class SHIBSP_DLLLOCAL Base64AttributeDecoder : virtual public AttributeDecoder
+    {
+    public:
+        Base64AttributeDecoder(const DOMElement* e) : AttributeDecoder(e) {}
+        ~Base64AttributeDecoder() {}
+
+        shibsp::Attribute* decode(
+            const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=nullptr, const char* relyingParty=nullptr
+            ) const;
+    };
+
+    AttributeDecoder* SHIBSP_DLLLOCAL Base64AttributeDecoderFactory(const DOMElement* const & e)
+    {
+        return new Base64AttributeDecoder(e);
+    }
+};
+
+shibsp::Attribute* Base64AttributeDecoder::decode(
+    const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty
+    ) const
+{
+    auto_ptr<SimpleAttribute> simple(new SimpleAttribute(ids));
+    vector<string>& dest = simple->getValues();
+    vector<XMLObject*>::const_iterator v,stop;
+
+    Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.Base64");
+
+    if (xmlObject && XMLString::equals(opensaml::saml1::Attribute::LOCAL_NAME,xmlObject->getElementQName().getLocalPart())) {
+        const opensaml::saml2::Attribute* saml2attr = dynamic_cast<const opensaml::saml2::Attribute*>(xmlObject);
+        if (saml2attr) {
+            const vector<XMLObject*>& values = saml2attr->getAttributeValues();
+            v = values.begin();
+            stop = values.end();
+            if (log.isDebugEnabled()) {
+                auto_ptr_char n(saml2attr->getName());
+                log.debug(
+                    "decoding SimpleAttribute (%s) from SAML 2 Attribute (%s) with %lu base64-encoded value(s)",
+                    ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
+                    );
+            }
+        }
+        else {
+            const opensaml::saml1::Attribute* saml1attr = dynamic_cast<const opensaml::saml1::Attribute*>(xmlObject);
+            if (saml1attr) {
+                const vector<XMLObject*>& values = saml1attr->getAttributeValues();
+                v = values.begin();
+                stop = values.end();
+                if (log.isDebugEnabled()) {
+                    auto_ptr_char n(saml1attr->getAttributeName());
+                log.debug(
+                    "decoding SimpleAttribute (%s) from SAML 1 Attribute (%s) with %lu base64-encoded value(s)",
+                    ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
+                    );
+                }
+            }
+            else {
+                log.warn("XMLObject type not recognized by Base64AttributeDecoder, no values returned");
+                return nullptr;
+            }
+        }
+
+        for (; v!=stop; ++v) {
+            if (!(*v)->hasChildren()) {
+                auto_ptr_char val((*v)->getTextContent());
+                if (val.get() && *val.get()) {
+                    xsecsize_t x;
+                    XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(val.get()),&x);
+                    if (decoded) {
+                        dest.push_back(reinterpret_cast<char*>(decoded));
+#ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
+                        XMLString::release(&decoded);
+#else
+                        XMLString::release((char**)&decoded);
+#endif
+                    }
+                    else {
+                        log.warn("skipping AttributeValue, unable to base64-decode");
+                    }
+                }
+                else
+                    log.warn("skipping empty AttributeValue");
+            }
+            else {
+                log.warn("skipping complex AttributeValue");
+            }
+        }
+
+        return dest.empty() ? nullptr : _decode(simple.release());
+    }
+
+    const NameID* saml2name = dynamic_cast<const NameID*>(xmlObject);
+    if (saml2name) {
+        if (log.isDebugEnabled()) {
+            auto_ptr_char f(saml2name->getFormat());
+            log.debug("decoding SimpleAttribute (%s) from SAML 2 NameID with Format (%s)", ids.front().c_str(), f.get() ? f.get() : "unspecified");
+        }
+        auto_ptr_char val(saml2name->getName());
+        if (val.get() && *val.get()) {
+            xsecsize_t x;
+            XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(val.get()),&x);
+            if (decoded) {
+                dest.push_back(reinterpret_cast<char*>(decoded));
+#ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
+                XMLString::release(&decoded);
+#else
+                XMLString::release((char**)&decoded);
+#endif
+            }
+            else {
+                log.warn("ignoring NameID, unable to base64-decode");
+            }
+        }
+        else
+            log.warn("ignoring empty NameID");
+    }
+    else {
+        const NameIdentifier* saml1name = dynamic_cast<const NameIdentifier*>(xmlObject);
+        if (saml1name) {
+            if (log.isDebugEnabled()) {
+                auto_ptr_char f(saml1name->getFormat());
+                log.debug(
+                    "decoding SimpleAttribute (%s) from SAML 1 NameIdentifier with Format (%s)",
+                    ids.front().c_str(), f.get() ? f.get() : "unspecified"
+                    );
+            }
+            auto_ptr_char val(saml1name->getName());
+            if (val.get() && *val.get()) {
+                xsecsize_t x;
+                XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(val.get()),&x);
+                if (decoded) {
+                    dest.push_back(reinterpret_cast<char*>(decoded));
+    #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
+                    XMLString::release(&decoded);
+    #else
+                    XMLString::release((char**)&decoded);
+    #endif
+                }
+                else {
+                    log.warn("ignoring NameIdentifier, unable to base64-decode");
+                }
+            }
+            else
+                log.warn("ignoring empty NameIdentifier");
+        }
+        else {
+            log.warn("XMLObject type not recognized by Base64AttributeDecoder, no values returned");
+            return nullptr;
+        }
+    }
+
+    return dest.empty() ? nullptr : _decode(simple.release());
+}
index 18bda2f..639d7e9 100644 (file)
@@ -379,7 +379,7 @@ void XMLFilterImpl::filterAttributes(const FilteringContext& context, vector<Att
         // If no rules apply, remove the attribute entirely.
         if (rulesToRun.empty()) {
             m_log.warn(
         // If no rules apply, remove the attribute entirely.
         if (rulesToRun.empty()) {
             m_log.warn(
-                "no rule found, removing attribute (%s) from (%s)",
+                "no rule found, will remove attribute (%s) from (%s)",
                 attr->getId(), issuer.get() ? issuer.get() : "unknown source"
                 );
             deletedAttributes[a] = true;
                 attr->getId(), issuer.get() ? issuer.get() : "unknown source"
                 );
             deletedAttributes[a] = true;
@@ -426,6 +426,10 @@ void XMLFilterImpl::filterAttributes(const FilteringContext& context, vector<Att
         Attribute* attr = attributes[a];
 
         if (deletedAttributes[a]) {
         Attribute* attr = attributes[a];
 
         if (deletedAttributes[a]) {
+            m_log.warn(
+                "removing filtered attribute (%s) from (%s)",
+                attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+                );
             delete attr;
             deletedAttributes.erase(deletedAttributes.begin() + a);
             attributes.erase(attributes.begin() + a);
             delete attr;
             deletedAttributes.erase(deletedAttributes.begin() + a);
             attributes.erase(attributes.begin() + a);
@@ -449,6 +453,7 @@ void XMLFilterImpl::filterAttributes(const FilteringContext& context, vector<Att
                 attr->getId(), issuer.get() ? issuer.get() : "unknown source"
                 );
             delete attr;
                 attr->getId(), issuer.get() ? issuer.get() : "unknown source"
                 );
             delete attr;
+            deletedAttributes.erase(deletedAttributes.begin() + a);
             attributes.erase(attributes.begin() + a);
             continue;
         }
             attributes.erase(attributes.begin() + a);
             continue;
         }
index 0c6a453..85a1d88 100644 (file)
@@ -24,7 +24,7 @@
 #include "Application.h"
 #include "ServiceProvider.h"
 #include "SessionCache.h"
 #include "Application.h"
 #include "ServiceProvider.h"
 #include "SessionCache.h"
-#include "attribute/Attribute.h"
+#include "attribute/SimpleAttribute.h"
 #include "attribute/filtering/AttributeFilter.h"
 #include "attribute/filtering/BasicFilteringContext.h"
 #include "attribute/resolver/AttributeExtractor.h"
 #include "attribute/filtering/AttributeFilter.h"
 #include "attribute/filtering/BasicFilteringContext.h"
 #include "attribute/resolver/AttributeExtractor.h"
@@ -45,7 +45,9 @@
 #include <saml/saml2/metadata/Metadata.h>
 #include <saml/saml2/metadata/MetadataCredentialCriteria.h>
 #include <saml/saml2/metadata/MetadataProvider.h>
 #include <saml/saml2/metadata/Metadata.h>
 #include <saml/saml2/metadata/MetadataCredentialCriteria.h>
 #include <saml/saml2/metadata/MetadataProvider.h>
+#include <xmltooling/XMLToolingConfig.h>
 #include <xmltooling/util/NDC.h>
 #include <xmltooling/util/NDC.h>
+#include <xmltooling/util/URLEncoder.h>
 #include <xmltooling/util/XMLHelper.h>
 #include <xercesc/util/XMLUniDefs.hpp>
 
 #include <xmltooling/util/XMLHelper.h>
 #include <xercesc/util/XMLUniDefs.hpp>
 
@@ -201,14 +203,15 @@ namespace shibsp {
         }
 
     private:
         }
 
     private:
-        bool SAML1Query(QueryContext& ctx) const;
-        bool SAML2Query(QueryContext& ctx) const;
+        void SAML1Query(QueryContext& ctx) const;
+        void SAML2Query(QueryContext& ctx) const;
 
         Category& m_log;
         string m_policyId;
         bool m_subjectMatch;
         vector<AttributeDesignator*> m_SAML1Designators;
         vector<saml2::Attribute*> m_SAML2Designators;
 
         Category& m_log;
         string m_policyId;
         bool m_subjectMatch;
         vector<AttributeDesignator*> m_SAML1Designators;
         vector<saml2::Attribute*> m_SAML2Designators;
+        vector<string> m_exceptionId;
     };
 
     AttributeResolver* SHIBSP_DLLLOCAL QueryResolverFactory(const DOMElement* const & e)
     };
 
     AttributeResolver* SHIBSP_DLLLOCAL QueryResolverFactory(const DOMElement* const & e)
@@ -216,6 +219,7 @@ namespace shibsp {
         return new QueryResolver(e);
     }
 
         return new QueryResolver(e);
     }
 
+    static const XMLCh exceptionId[] =  UNICODE_LITERAL_11(e,x,c,e,p,t,i,o,n,I,d);
     static const XMLCh policyId[] =     UNICODE_LITERAL_8(p,o,l,i,c,y,I,d);
     static const XMLCh subjectMatch[] = UNICODE_LITERAL_12(s,u,b,j,e,c,t,M,a,t,c,h);
 };
     static const XMLCh policyId[] =     UNICODE_LITERAL_8(p,o,l,i,c,y,I,d);
     static const XMLCh subjectMatch[] = UNICODE_LITERAL_12(s,u,b,j,e,c,t,M,a,t,c,h);
 };
@@ -254,9 +258,13 @@ QueryResolver::QueryResolver(const DOMElement* e)
         }
         child = XMLHelper::getNextSiblingElement(child);
     }
         }
         child = XMLHelper::getNextSiblingElement(child);
     }
+
+    string exid(XMLHelper::getAttrString(e, nullptr, exceptionId));
+    if (!exid.empty())
+        m_exceptionId.push_back(exid);
 }
 
 }
 
-bool QueryResolver::SAML1Query(QueryContext& ctx) const
+void QueryResolver::SAML1Query(QueryContext& ctx) const
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("query");
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("query");
@@ -267,7 +275,7 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
         find_if(ctx.getEntityDescriptor()->getAttributeAuthorityDescriptors(), isValidForProtocol(ctx.getProtocol()));
     if (!AA) {
         m_log.warn("no SAML 1.%d AttributeAuthority role found in metadata", version);
         find_if(ctx.getEntityDescriptor()->getAttributeAuthorityDescriptors(), isValidForProtocol(ctx.getProtocol()));
     if (!AA) {
         m_log.warn("no SAML 1.%d AttributeAuthority role found in metadata", version);
-        return false;
+        return;
     }
 
     const Application& application = ctx.getApplication();
     }
 
     const Application& application = ctx.getApplication();
@@ -319,23 +327,24 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
 
     if (!response) {
         m_log.error("unable to obtain a SAML response from attribute authority");
 
     if (!response) {
         m_log.error("unable to obtain a SAML response from attribute authority");
-        return false;
+        throw BindingException("Unable to obtain a SAML response from attribute authority.");
     }
     else if (!response->getStatus() || !response->getStatus()->getStatusCode() || response->getStatus()->getStatusCode()->getValue()==nullptr ||
             *(response->getStatus()->getStatusCode()->getValue()) != saml1p::StatusCode::SUCCESS) {
         delete response;
         m_log.error("attribute authority returned a SAML error");
     }
     else if (!response->getStatus() || !response->getStatus()->getStatusCode() || response->getStatus()->getStatusCode()->getValue()==nullptr ||
             *(response->getStatus()->getStatusCode()->getValue()) != saml1p::StatusCode::SUCCESS) {
         delete response;
         m_log.error("attribute authority returned a SAML error");
-        return true;
+        throw FatalProfileException("Attribute authority returned a SAML error.");
     }
 
     const vector<saml1::Assertion*>& assertions = const_cast<const saml1p::Response*>(response)->getAssertions();
     if (assertions.empty()) {
         delete response;
         m_log.warn("response from attribute authority was empty");
     }
 
     const vector<saml1::Assertion*>& assertions = const_cast<const saml1p::Response*>(response)->getAssertions();
     if (assertions.empty()) {
         delete response;
         m_log.warn("response from attribute authority was empty");
-        return true;
+        return;
     }
     }
-    else if (assertions.size()>1)
+    else if (assertions.size()>1) {
         m_log.warn("simple resolver only supports one assertion in the query response");
         m_log.warn("simple resolver only supports one assertion in the query response");
+    }
 
     auto_ptr<saml1p::Response> wrapper(response);
     saml1::Assertion* newtoken = assertions.front();
 
     auto_ptr<saml1p::Response> wrapper(response);
     saml1::Assertion* newtoken = assertions.front();
@@ -343,7 +352,7 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
     pair<bool,bool> signedAssertions = relyingParty->getBool("requireSignedAssertions");
     if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
         m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
     pair<bool,bool> signedAssertions = relyingParty->getBool("requireSignedAssertions");
     if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
         m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
-        return true;
+        throw SecurityPolicyException("Rejected unsigned assertion based on local policy.");
     }
 
     try {
     }
 
     try {
@@ -361,7 +370,7 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
     }
     catch (exception& ex) {
         m_log.error("assertion failed policy validation: %s", ex.what());
     }
     catch (exception& ex) {
         m_log.error("assertion failed policy validation: %s", ex.what());
-        return true;
+        throw;
     }
 
     newtoken->detach();
     }
 
     newtoken->detach();
@@ -404,12 +413,11 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
         for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
         ctx.getResolvedAttributes().clear();
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
         for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
         ctx.getResolvedAttributes().clear();
+        throw;
     }
     }
-
-    return true;
 }
 
 }
 
-bool QueryResolver::SAML2Query(QueryContext& ctx) const
+void QueryResolver::SAML2Query(QueryContext& ctx) const
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("query");
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("query");
@@ -419,7 +427,7 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
         find_if(ctx.getEntityDescriptor()->getAttributeAuthorityDescriptors(), isValidForProtocol(samlconstants::SAML20P_NS));
     if (!AA) {
         m_log.warn("no SAML 2 AttributeAuthority role found in metadata");
         find_if(ctx.getEntityDescriptor()->getAttributeAuthorityDescriptors(), isValidForProtocol(samlconstants::SAML20P_NS));
     if (!AA) {
         m_log.warn("no SAML 2 AttributeAuthority role found in metadata");
-        return false;
+        return;
     }
 
     const Application& application = ctx.getApplication();
     }
 
     const Application& application = ctx.getApplication();
@@ -484,7 +492,7 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
 
     if (!srt) {
         m_log.error("unable to obtain a SAML response from attribute authority");
 
     if (!srt) {
         m_log.error("unable to obtain a SAML response from attribute authority");
-        return false;
+        throw BindingException("Unable to obtain a SAML response from attribute authority.");
     }
 
     auto_ptr<saml2p::StatusResponseType> wrapper(srt);
     }
 
     auto_ptr<saml2p::StatusResponseType> wrapper(srt);
@@ -492,12 +500,12 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
     saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt);
     if (!response) {
         m_log.error("message was not a samlp:Response");
     saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt);
     if (!response) {
         m_log.error("message was not a samlp:Response");
-        return true;
+        throw FatalProfileException("Attribute authority returned an unrecognized message.");
     }
     else if (!response->getStatus() || !response->getStatus()->getStatusCode() ||
             !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
         m_log.error("attribute authority returned a SAML error");
     }
     else if (!response->getStatus() || !response->getStatus()->getStatusCode() ||
             !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
         m_log.error("attribute authority returned a SAML error");
-        return true;
+        throw FatalProfileException("Attribute authority returned a SAML error.");
     }
 
     saml2::Assertion* newtoken = nullptr;
     }
 
     saml2::Assertion* newtoken = nullptr;
@@ -507,7 +515,7 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
         const vector<saml2::EncryptedAssertion*>& encassertions = const_cast<const saml2p::Response*>(response)->getEncryptedAssertions();
         if (encassertions.empty()) {
             m_log.warn("response from attribute authority was empty");
         const vector<saml2::EncryptedAssertion*>& encassertions = const_cast<const saml2p::Response*>(response)->getEncryptedAssertions();
         if (encassertions.empty()) {
             m_log.warn("response from attribute authority was empty");
-            return true;
+            return;
         }
         else if (encassertions.size() > 1) {
             m_log.warn("simple resolver only supports one assertion in the query response");
         }
         else if (encassertions.size() > 1) {
             m_log.warn("simple resolver only supports one assertion in the query response");
@@ -516,7 +524,7 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
         CredentialResolver* cr=application.getCredentialResolver();
         if (!cr) {
             m_log.warn("found encrypted assertion, but no CredentialResolver was available");
         CredentialResolver* cr=application.getCredentialResolver();
         if (!cr) {
             m_log.warn("found encrypted assertion, but no CredentialResolver was available");
-            return true;
+            throw FatalProfileException("Assertion was encrypted, but no decryption credentials are available.");
         }
 
         // Attempt to decrypt it.
         }
 
         // Attempt to decrypt it.
@@ -528,18 +536,13 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
                 tokenwrapper.release();
                 if (m_log.isDebugEnabled())
                     m_log.debugStream() << "decrypted Assertion: " << *newtoken << logging::eol;
                 tokenwrapper.release();
                 if (m_log.isDebugEnabled())
                     m_log.debugStream() << "decrypted Assertion: " << *newtoken << logging::eol;
+                // Free the Response now, so we know this is a stand-alone token later.
+                delete wrapper.release();
             }
         }
         catch (exception& ex) {
             m_log.error(ex.what());
             }
         }
         catch (exception& ex) {
             m_log.error(ex.what());
-        }
-        if (newtoken) {
-            // Free the Response now, so we know this is a stand-alone token later.
-            delete wrapper.release();
-        }
-        else {
-            // Nothing decrypted, should already be logged.
-            return true;
+            throw;
         }
     }
     else {
         }
     }
     else {
@@ -552,7 +555,7 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
         m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
         if (!wrapper.get())
             delete newtoken;
         m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
         if (!wrapper.get())
             delete newtoken;
-        return true;
+        throw SecurityPolicyException("Rejected unsigned assertion based on local policy.");
     }
 
     try {
     }
 
     try {
@@ -606,7 +609,7 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
                     m_log.warn("ignoring Assertion without NameID in Subject");
                 if (!wrapper.get())
                     delete newtoken;
                     m_log.warn("ignoring Assertion without NameID in Subject");
                 if (!wrapper.get())
                     delete newtoken;
-                return true;
+                return;
             }
         }
     }
             }
         }
     }
@@ -614,7 +617,7 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
         m_log.error("assertion failed policy validation: %s", ex.what());
         if (!wrapper.get())
             delete newtoken;
         m_log.error("assertion failed policy validation: %s", ex.what());
         if (!wrapper.get())
             delete newtoken;
-        return true;
+        throw;
     }
 
     if (wrapper.get()) {
     }
 
     if (wrapper.get()) {
@@ -642,9 +645,8 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
         for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
         ctx.getResolvedAttributes().clear();
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
         for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
         ctx.getResolvedAttributes().clear();
+        throw;
     }
     }
-
-    return true;
 }
 
 void QueryResolver::resolveAttributes(ResolutionContext& ctx) const
 }
 
 void QueryResolver::resolveAttributes(ResolutionContext& ctx) const
@@ -659,21 +661,31 @@ void QueryResolver::resolveAttributes(ResolutionContext& ctx) const
         return;
     }
 
         return;
     }
 
-    if (qctx.getNameID() && qctx.getEntityDescriptor()) {
-        if (XMLString::equals(qctx.getProtocol(), samlconstants::SAML20P_NS)) {
-            m_log.debug("attempting SAML 2.0 attribute query");
-            SAML2Query(qctx);
-        }
-        else if (XMLString::equals(qctx.getProtocol(), samlconstants::SAML11_PROTOCOL_ENUM) ||
-                XMLString::equals(qctx.getProtocol(), samlconstants::SAML10_PROTOCOL_ENUM)) {
-            m_log.debug("attempting SAML 1.x attribute query");
-            SAML1Query(qctx);
+    try {
+        if (qctx.getNameID() && qctx.getEntityDescriptor()) {
+            if (XMLString::equals(qctx.getProtocol(), samlconstants::SAML20P_NS)) {
+                m_log.debug("attempting SAML 2.0 attribute query");
+                SAML2Query(qctx);
+            }
+            else if (XMLString::equals(qctx.getProtocol(), samlconstants::SAML11_PROTOCOL_ENUM) ||
+                    XMLString::equals(qctx.getProtocol(), samlconstants::SAML10_PROTOCOL_ENUM)) {
+                m_log.debug("attempting SAML 1.x attribute query");
+                SAML1Query(qctx);
+            }
+            else {
+                m_log.info("SSO protocol does not allow for attribute query");
+            }
         }
         else {
         }
         else {
-            m_log.info("SSO protocol does not allow for attribute query");
+            m_log.warn("can't attempt attribute query, either no NameID or no metadata to use");
         }
     }
         }
     }
-    else {
-        m_log.warn("can't attempt attribute query, either no NameID or no metadata to use");
+    catch (exception& ex) {
+        // Already logged.
+        if (!m_exceptionId.empty()) {
+            SimpleAttribute* attr = new SimpleAttribute(m_exceptionId);
+            attr->getValues().push_back(XMLToolingConfig::getConfig().getURLEncoder()->encode(ex.what()));
+            qctx.getResolvedAttributes().push_back(attr);
+        }
     }
 }
     }
 }
index 2d27a30..573e6ec 100644 (file)
@@ -26,6 +26,7 @@
 #include "ServiceProvider.h"
 #include "SessionCache.h"
 #include "attribute/NameIDAttribute.h"
 #include "ServiceProvider.h"
 #include "SessionCache.h"
 #include "attribute/NameIDAttribute.h"
+#include "attribute/SimpleAttribute.h"
 #include "attribute/filtering/AttributeFilter.h"
 #include "attribute/filtering/BasicFilteringContext.h"
 #include "attribute/resolver/AttributeExtractor.h"
 #include "attribute/filtering/AttributeFilter.h"
 #include "attribute/filtering/BasicFilteringContext.h"
 #include "attribute/resolver/AttributeExtractor.h"
@@ -47,6 +48,7 @@
 #include <xmltooling/XMLToolingConfig.h>
 #include <xmltooling/security/TrustEngine.h>
 #include <xmltooling/util/NDC.h>
 #include <xmltooling/XMLToolingConfig.h>
 #include <xmltooling/security/TrustEngine.h>
 #include <xmltooling/util/NDC.h>
+#include <xmltooling/util/URLEncoder.h>
 #include <xmltooling/util/XMLHelper.h>
 #include <xercesc/util/XMLUniDefs.hpp>
 
 #include <xmltooling/util/XMLHelper.h>
 #include <xercesc/util/XMLUniDefs.hpp>
 
@@ -185,7 +187,7 @@ namespace shibsp {
         }
 
     private:
         }
 
     private:
-        bool doQuery(SimpleAggregationContext& ctx, const char* entityID, const NameID* name) const;
+        void doQuery(SimpleAggregationContext& ctx, const char* entityID, const NameID* name) const;
 
         Category& m_log;
         string m_policyId;
 
         Category& m_log;
         string m_policyId;
@@ -196,6 +198,7 @@ namespace shibsp {
         TrustEngine* m_trust;
         vector<saml2::Attribute*> m_designators;
         vector< pair<string,bool> > m_sources;
         TrustEngine* m_trust;
         vector<saml2::Attribute*> m_designators;
         vector< pair<string,bool> > m_sources;
+        vector<string> m_exceptionId;
     };
 
     AttributeResolver* SHIBSP_DLLLOCAL SimpleAggregationResolverFactory(const DOMElement* const & e)
     };
 
     AttributeResolver* SHIBSP_DLLLOCAL SimpleAggregationResolverFactory(const DOMElement* const & e)
@@ -206,6 +209,7 @@ namespace shibsp {
     static const XMLCh attributeId[] =          UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,d);
     static const XMLCh Entity[] =               UNICODE_LITERAL_6(E,n,t,i,t,y);
     static const XMLCh EntityReference[] =      UNICODE_LITERAL_15(E,n,t,i,t,y,R,e,f,e,r,e,n,c,e);
     static const XMLCh attributeId[] =          UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,d);
     static const XMLCh Entity[] =               UNICODE_LITERAL_6(E,n,t,i,t,y);
     static const XMLCh EntityReference[] =      UNICODE_LITERAL_15(E,n,t,i,t,y,R,e,f,e,r,e,n,c,e);
+    static const XMLCh exceptionId[] =          UNICODE_LITERAL_11(e,x,c,e,p,t,i,o,n,I,d);
     static const XMLCh format[] =               UNICODE_LITERAL_6(f,o,r,m,a,t);
     static const XMLCh _MetadataProvider[] =    UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r);
     static const XMLCh policyId[] =             UNICODE_LITERAL_8(p,o,l,i,c,y,I,d);
     static const XMLCh format[] =               UNICODE_LITERAL_6(f,o,r,m,a,t);
     static const XMLCh _MetadataProvider[] =    UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r);
     static const XMLCh policyId[] =             UNICODE_LITERAL_8(p,o,l,i,c,y,I,d);
@@ -247,6 +251,10 @@ SimpleAggregationResolver::SimpleAggregationResolver(const DOMElement* e)
             m_format = aid;
     }
 
             m_format = aid;
     }
 
+    string exid(XMLHelper::getAttrString(e, nullptr, exceptionId));
+    if (!exid.empty())
+        m_exceptionId.push_back(exid);
+
     DOMElement* child = XMLHelper::getFirstChildElement(e, _MetadataProvider);
     if (child) {
         string t(XMLHelper::getAttrString(child, nullptr, _type));
     DOMElement* child = XMLHelper::getFirstChildElement(e, _MetadataProvider);
     if (child) {
         string t(XMLHelper::getAttrString(child, nullptr, _type));
@@ -306,7 +314,7 @@ SimpleAggregationResolver::SimpleAggregationResolver(const DOMElement* e)
     }
 }
 
     }
 }
 
-bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const char* entityID, const NameID* name) const
+void SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const char* entityID, const NameID* name) const
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("doQuery");
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("doQuery");
@@ -319,11 +327,11 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
         (m_metadata ? m_metadata : application.getMetadataProvider())->getEntityDescriptor(mc);
     if (!mdresult.first) {
         m_log.warn("unable to locate metadata for provider (%s)", entityID);
         (m_metadata ? m_metadata : application.getMetadataProvider())->getEntityDescriptor(mc);
     if (!mdresult.first) {
         m_log.warn("unable to locate metadata for provider (%s)", entityID);
-        return false;
+        return;
     }
     else if (!(AA=dynamic_cast<const AttributeAuthorityDescriptor*>(mdresult.second))) {
         m_log.warn("no SAML 2 AttributeAuthority role found in metadata for (%s)", entityID);
     }
     else if (!(AA=dynamic_cast<const AttributeAuthorityDescriptor*>(mdresult.second))) {
         m_log.warn("no SAML 2 AttributeAuthority role found in metadata for (%s)", entityID);
-        return false;
+        return;
     }
 
     const PropertySet* relyingParty = application.getRelyingParty(mdresult.first);
     }
 
     const PropertySet* relyingParty = application.getRelyingParty(mdresult.first);
@@ -392,7 +400,7 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
 
     if (!srt) {
         m_log.error("unable to obtain a SAML response from attribute authority (%s)", entityID);
 
     if (!srt) {
         m_log.error("unable to obtain a SAML response from attribute authority (%s)", entityID);
-        return false;
+        throw BindingException("Unable to obtain a SAML response from attribute authority.");
     }
 
     auto_ptr<saml2p::StatusResponseType> wrapper(srt);
     }
 
     auto_ptr<saml2p::StatusResponseType> wrapper(srt);
@@ -400,12 +408,12 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
     saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt);
     if (!response) {
         m_log.error("message was not a samlp:Response");
     saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt);
     if (!response) {
         m_log.error("message was not a samlp:Response");
-        return true;
+        throw FatalProfileException("Attribute authority returned an unrecognized message.");
     }
     else if (!response->getStatus() || !response->getStatus()->getStatusCode() ||
             !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
         m_log.error("attribute authority (%s) returned a SAML error", entityID);
     }
     else if (!response->getStatus() || !response->getStatus()->getStatusCode() ||
             !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
         m_log.error("attribute authority (%s) returned a SAML error", entityID);
-        return true;
+        throw FatalProfileException("Attribute authority returned a SAML error.");
     }
 
     saml2::Assertion* newtoken = nullptr;
     }
 
     saml2::Assertion* newtoken = nullptr;
@@ -416,7 +424,7 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
             const_cast<const saml2p::Response*>(response)->getEncryptedAssertions();
         if (encassertions.empty()) {
             m_log.warn("response from attribute authority was empty");
             const_cast<const saml2p::Response*>(response)->getEncryptedAssertions();
         if (encassertions.empty()) {
             m_log.warn("response from attribute authority was empty");
-            return true;
+            return;
         }
         else if (encassertions.size() > 1) {
             m_log.warn("simple resolver only supports one assertion in the query response");
         }
         else if (encassertions.size() > 1) {
             m_log.warn("simple resolver only supports one assertion in the query response");
@@ -425,7 +433,7 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
         CredentialResolver* cr=application.getCredentialResolver();
         if (!cr) {
             m_log.warn("found encrypted assertion, but no CredentialResolver was available");
         CredentialResolver* cr=application.getCredentialResolver();
         if (!cr) {
             m_log.warn("found encrypted assertion, but no CredentialResolver was available");
-            return true;
+            throw FatalProfileException("Assertion was encrypted, but no decryption credentials are available.");
         }
 
         // Attempt to decrypt it.
         }
 
         // Attempt to decrypt it.
@@ -437,18 +445,13 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
                 tokenwrapper.release();
                 if (m_log.isDebugEnabled())
                     m_log.debugStream() << "decrypted Assertion: " << *newtoken << logging::eol;
                 tokenwrapper.release();
                 if (m_log.isDebugEnabled())
                     m_log.debugStream() << "decrypted Assertion: " << *newtoken << logging::eol;
+                // Free the Response now, so we know this is a stand-alone token later.
+                delete wrapper.release();
             }
         }
         catch (exception& ex) {
             m_log.error(ex.what());
             }
         }
         catch (exception& ex) {
             m_log.error(ex.what());
-        }
-        if (newtoken) {
-            // Free the Response now, so we know this is a stand-alone token later.
-            delete wrapper.release();
-        }
-        else {
-            // Nothing decrypted, should already be logged.
-            return true;
+            throw;
         }
     }
     else {
         }
     }
     else {
@@ -461,7 +464,7 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
         m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
         if (!wrapper.get())
             delete newtoken;
         m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
         if (!wrapper.get())
             delete newtoken;
-        return true;
+        throw SecurityPolicyException("Rejected unsigned assertion based on local policy.");
     }
 
     try {
     }
 
     try {
@@ -515,7 +518,7 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
                     m_log.warn("ignoring Assertion without NameID in Subject");
                 if (!wrapper.get())
                     delete newtoken;
                     m_log.warn("ignoring Assertion without NameID in Subject");
                 if (!wrapper.get())
                     delete newtoken;
-                return true;
+                return;
             }
         }
     }
             }
         }
     }
@@ -523,7 +526,7 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
         m_log.error("assertion failed policy validation: %s", ex.what());
         if (!wrapper.get())
             delete newtoken;
         m_log.error("assertion failed policy validation: %s", ex.what());
         if (!wrapper.get())
             delete newtoken;
-        return true;
+        throw;
     }
 
     if (wrapper.get()) {
     }
 
     if (wrapper.get()) {
@@ -551,9 +554,8 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
         for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
         ctx.getResolvedAttributes().clear();
         m_log.error("caught exception extracting/filtering attributes from query result: %s", ex.what());
         for_each(ctx.getResolvedAttributes().begin(), ctx.getResolvedAttributes().end(), xmltooling::cleanup<shibsp::Attribute>());
         ctx.getResolvedAttributes().clear();
+        throw;
     }
     }
-
-    return true;
 }
 
 void SimpleAggregationResolver::resolveAttributes(ResolutionContext& ctx) const
 }
 
 void SimpleAggregationResolver::resolveAttributes(ResolutionContext& ctx) const
@@ -646,13 +648,26 @@ void SimpleAggregationResolver::resolveAttributes(ResolutionContext& ctx) const
     if (qctx.getEntityID())
         history.insert(qctx.getEntityID());
 
     if (qctx.getEntityID())
         history.insert(qctx.getEntityID());
 
+    // Prepare to track exceptions.
+    SimpleAttribute* exceptAttr = nullptr;
+    if (!m_exceptionId.empty()) {
+        exceptAttr = new SimpleAttribute(m_exceptionId);
+    }
+    auto_ptr<Attribute> exceptWrapper(exceptAttr);
+
     // We have a master loop over all the possible sources of material.
     for (vector< pair<string,bool> >::const_iterator source = m_sources.begin(); source != m_sources.end(); ++source) {
         if (source->second) {
             // A literal entityID to query.
             if (history.count(source->first) == 0) {
                 m_log.debug("issuing SAML query to (%s)", source->first.c_str());
     // We have a master loop over all the possible sources of material.
     for (vector< pair<string,bool> >::const_iterator source = m_sources.begin(); source != m_sources.end(); ++source) {
         if (source->second) {
             // A literal entityID to query.
             if (history.count(source->first) == 0) {
                 m_log.debug("issuing SAML query to (%s)", source->first.c_str());
-                doQuery(qctx, source->first.c_str(), n ? n : qctx.getNameID());
+                try {
+                    doQuery(qctx, source->first.c_str(), n ? n : qctx.getNameID());
+                }
+                catch (exception& ex) {
+                    if (exceptAttr)
+                        exceptAttr->getValues().push_back(XMLToolingConfig::getConfig().getURLEncoder()->encode(ex.what()));
+                }
                 history.insert(source->first);
             }
             else {
                 history.insert(source->first);
             }
             else {
@@ -670,7 +685,13 @@ void SimpleAggregationResolver::resolveAttributes(ResolutionContext& ctx) const
                     for (vector<string>::const_iterator link = links.begin(); link != links.end(); ++link) {
                         if (history.count(*link) == 0) {
                             m_log.debug("issuing SAML query to (%s)", link->c_str());
                     for (vector<string>::const_iterator link = links.begin(); link != links.end(); ++link) {
                         if (history.count(*link) == 0) {
                             m_log.debug("issuing SAML query to (%s)", link->c_str());
-                            doQuery(qctx, link->c_str(), n ? n : qctx.getNameID());
+                            try {
+                                doQuery(qctx, link->c_str(), n ? n : qctx.getNameID());
+                            }
+                            catch (exception& ex) {
+                                if (exceptAttr)
+                                    exceptAttr->getValues().push_back(XMLToolingConfig::getConfig().getURLEncoder()->encode(ex.what()));
+                            }
                             history.insert(*link);
                         }
                         else {
                             history.insert(*link);
                         }
                         else {
@@ -688,7 +709,13 @@ void SimpleAggregationResolver::resolveAttributes(ResolutionContext& ctx) const
                         for (vector<string>::const_iterator link = links.begin(); link != links.end(); ++link) {
                             if (history.count(*link) == 0) {
                                 m_log.debug("issuing SAML query to (%s)", link->c_str());
                         for (vector<string>::const_iterator link = links.begin(); link != links.end(); ++link) {
                             if (history.count(*link) == 0) {
                                 m_log.debug("issuing SAML query to (%s)", link->c_str());
-                                doQuery(qctx, link->c_str(), n ? n : qctx.getNameID());
+                                try {
+                                    doQuery(qctx, link->c_str(), n ? n : qctx.getNameID());
+                                }
+                                catch (exception& ex) {
+                                    if (exceptAttr)
+                                        exceptAttr->getValues().push_back(XMLToolingConfig::getConfig().getURLEncoder()->encode(ex.what()));
+                                }
                                 history.insert(*link);
                             }
                             else {
                                 history.insert(*link);
                             }
                             else {
@@ -700,4 +727,8 @@ void SimpleAggregationResolver::resolveAttributes(ResolutionContext& ctx) const
             }
         }
     }
             }
         }
     }
+
+    if (exceptAttr) {
+        qctx.getResolvedAttributes().push_back(exceptWrapper.release());
+    }
 }
 }
index 3511af6..ef1a25c 100644 (file)
@@ -26,6 +26,8 @@
 #include <shibsp/handler/Handler.h>
 #include <shibsp/remoting/ListenerService.h>
 
 #include <shibsp/handler/Handler.h>
 #include <shibsp/remoting/ListenerService.h>
 
+#include <set>
+
 namespace xmltooling {
     class XMLTOOL_API HTTPRequest;
     class XMLTOOL_API HTTPResponse;
 namespace xmltooling {
     class XMLTOOL_API HTTPRequest;
     class XMLTOOL_API HTTPResponse;
@@ -38,9 +40,18 @@ namespace shibsp {
      */
     class SHIBSP_API RemotedHandler : public virtual Handler, public Remoted 
     {
      */
     class SHIBSP_API RemotedHandler : public virtual Handler, public Remoted 
     {
+        static std::set<std::string> m_remotedHeaders;
+
     public:
         virtual ~RemotedHandler();
 
     public:
         virtual ~RemotedHandler();
 
+        /**
+         * Ensures that a request header will be remoted.
+         *
+         * @param header    name of request header to remote
+         */
+        static void addRemotedHeader(const char* header);
+
     protected:
         RemotedHandler();
 
     protected:
         RemotedHandler();
 
@@ -56,7 +67,7 @@ namespace shibsp {
          * to remote the request information.
          *
          * @param request   an SPRequest to remote
          * to remote the request information.
          *
          * @param request   an SPRequest to remote
-         * @param headers   array of request headers to copy to remote request
+         * @param headers   array of additional request headers to copy to remote request
          * @param certs     true iff client certificates should be available for the remote request
          * @return  the input dataflow object
          */
          * @param certs     true iff client certificates should be available for the remote request
          * @return  the input dataflow object
          */
index 7ae1c9d..7cafe7d 100644 (file)
@@ -89,6 +89,7 @@ namespace shibsp {
             delete m_org;
             delete m_entityAttrs;
             for_each(m_contacts.begin(), m_contacts.end(), xmltooling::cleanup<ContactPerson>());
             delete m_org;
             delete m_entityAttrs;
             for_each(m_contacts.begin(), m_contacts.end(), xmltooling::cleanup<ContactPerson>());
+            for_each(m_formats.begin(), m_formats.end(), xmltooling::cleanup<NameIDFormat>());
             for_each(m_reqAttrs.begin(), m_reqAttrs.end(), xmltooling::cleanup<RequestedAttribute>());
             for_each(m_attrConsumers.begin(), m_attrConsumers.end(), xmltooling::cleanup<AttributeConsumingService>());
 #endif
             for_each(m_reqAttrs.begin(), m_reqAttrs.end(), xmltooling::cleanup<RequestedAttribute>());
             for_each(m_attrConsumers.begin(), m_attrConsumers.end(), xmltooling::cleanup<AttributeConsumingService>());
 #endif
@@ -114,6 +115,7 @@ namespace shibsp {
         Organization* m_org;
         EntityAttributes* m_entityAttrs;
         vector<ContactPerson*> m_contacts;
         Organization* m_org;
         EntityAttributes* m_entityAttrs;
         vector<ContactPerson*> m_contacts;
+        vector<NameIDFormat*> m_formats;
         vector<RequestedAttribute*> m_reqAttrs;
         vector<AttributeConsumingService*> m_attrConsumers;
 #endif
         vector<RequestedAttribute*> m_reqAttrs;
         vector<AttributeConsumingService*> m_attrConsumers;
 #endif
@@ -184,48 +186,55 @@ MetadataGenerator::MetadataGenerator(const DOMElement* e, const char* appId)
                 m_contacts.push_back(cp);
             }
             else {
                 m_contacts.push_back(cp);
             }
             else {
-                RequestedAttribute* req = dynamic_cast<RequestedAttribute*>(child.get());
-                if (req) {
+                NameIDFormat* nif = dynamic_cast<NameIDFormat*>(child.get());
+                if (nif) {
                     child.release();
                     child.release();
-                    m_reqAttrs.push_back(req);
+                    m_formats.push_back(nif);
                 }
                 else {
                 }
                 else {
-                    AttributeConsumingService* acs = dynamic_cast<AttributeConsumingService*>(child.get());
-                    if (acs) {
+                    RequestedAttribute* req = dynamic_cast<RequestedAttribute*>(child.get());
+                    if (req) {
                         child.release();
                         child.release();
-                        m_attrConsumers.push_back(acs);
+                        m_reqAttrs.push_back(req);
                     }
                     else {
                     }
                     else {
-                        UIInfo* info = dynamic_cast<UIInfo*>(child.get());
-                        if (info) {
-                            if (!m_uiinfo) {
-                                child.release();
-                                m_uiinfo = info;
-                            }
-                            else {
-                                m_log.warn("skipping duplicate UIInfo element");
-                            }
+                        AttributeConsumingService* acs = dynamic_cast<AttributeConsumingService*>(child.get());
+                        if (acs) {
+                            child.release();
+                            m_attrConsumers.push_back(acs);
                         }
                         else {
                         }
                         else {
-                            Organization* org = dynamic_cast<Organization*>(child.get());
-                            if (org) {
-                                if (!m_org) {
+                            UIInfo* info = dynamic_cast<UIInfo*>(child.get());
+                            if (info) {
+                                if (!m_uiinfo) {
                                     child.release();
                                     child.release();
-                                    m_org = org;
+                                    m_uiinfo = info;
                                 }
                                 else {
                                 }
                                 else {
-                                    m_log.warn("skipping duplicate Organization element");
+                                    m_log.warn("skipping duplicate UIInfo element");
                                 }
                             }
                             else {
                                 }
                             }
                             else {
-                                EntityAttributes* ea = dynamic_cast<EntityAttributes*>(child.get());
-                                if (ea) {
-                                    if (!m_entityAttrs) {
+                                Organization* org = dynamic_cast<Organization*>(child.get());
+                                if (org) {
+                                    if (!m_org) {
                                         child.release();
                                         child.release();
-                                        m_entityAttrs = ea;
+                                        m_org = org;
                                     }
                                     else {
                                     }
                                     else {
-                                        m_log.warn("skipping duplicate EntityAttributes element");
+                                        m_log.warn("skipping duplicate Organization element");
+                                    }
+                                }
+                                else {
+                                    EntityAttributes* ea = dynamic_cast<EntityAttributes*>(child.get());
+                                    if (ea) {
+                                        if (!m_entityAttrs) {
+                                            child.release();
+                                            m_entityAttrs = ea;
+                                        }
+                                        else {
+                                            m_log.warn("skipping duplicate EntityAttributes element");
+                                        }
                                     }
                                 }
                             }
                                     }
                                 }
                             }
@@ -363,7 +372,7 @@ pair<bool,long> MetadataGenerator::processMessage(
         entity->setOrganization(m_org->cloneOrganization());
 
     for (vector<ContactPerson*>::const_iterator cp = m_contacts.begin(); cp != m_contacts.end(); ++cp)
         entity->setOrganization(m_org->cloneOrganization());
 
     for (vector<ContactPerson*>::const_iterator cp = m_contacts.begin(); cp != m_contacts.end(); ++cp)
-        entity->getContactPersons().push_back((*cp)->cloneContactPerson());    
+        entity->getContactPersons().push_back((*cp)->cloneContactPerson());
 
     if (m_entityAttrs) {
         if (!entity->getExtensions())
 
     if (m_entityAttrs) {
         if (!entity->getExtensions())
@@ -380,6 +389,9 @@ pair<bool,long> MetadataGenerator::processMessage(
         role = entity->getSPSSODescriptors().front();
     }
 
         role = entity->getSPSSODescriptors().front();
     }
 
+    for (vector<NameIDFormat*>::const_iterator nif = m_formats.begin(); nif != m_formats.end(); ++nif)
+        role->getNameIDFormats().push_back((*nif)->cloneNameIDFormat());
+
     if (m_uiinfo) {
         if (!role->getExtensions())
             role->setExtensions(ExtensionsBuilder::buildExtensions());
     if (m_uiinfo) {
         if (!role->getExtensions())
             role->setExtensions(ExtensionsBuilder::buildExtensions());
index e7ca6d7..272f667 100644 (file)
  */
 
 #include "internal.h"
  */
 
 #include "internal.h"
-#include "Application.h"
 #include "exceptions.h"
 #include "exceptions.h"
+#include "Application.h"
+#include "GSSRequest.h"
 #include "ServiceProvider.h"
 #include "SPRequest.h"
 #include "handler/RemotedHandler.h"
 
 #include <algorithm>
 #include <xmltooling/unicode.h>
 #include "ServiceProvider.h"
 #include "SPRequest.h"
 #include "handler/RemotedHandler.h"
 
 #include <algorithm>
 #include <xmltooling/unicode.h>
+#include <xercesc/util/Base64.hpp>
 
 #ifndef SHIBSP_LITE
 # include "util/CGIParser.h"
 
 #ifndef SHIBSP_LITE
 # include "util/CGIParser.h"
@@ -46,22 +48,44 @@ using namespace std;
 
 #ifndef SHIBSP_LITE
 namespace shibsp {
 
 #ifndef SHIBSP_LITE
 namespace shibsp {
-    class SHIBSP_DLLLOCAL RemotedRequest : public virtual HTTPRequest 
+    class SHIBSP_DLLLOCAL RemotedRequest : 
+#ifdef HAVE_GSSAPI
+        public GSSRequest,
+#endif
+        public HTTPRequest
     {
         DDF& m_input;
         mutable CGIParser* m_parser;
         mutable vector<XSECCryptoX509*> m_certs;
     {
         DDF& m_input;
         mutable CGIParser* m_parser;
         mutable vector<XSECCryptoX509*> m_certs;
+#ifdef HAVE_GSSAPI
+        mutable gss_ctx_id_t m_gss;
+#endif
     public:
     public:
-        RemotedRequest(DDF& input) : m_input(input), m_parser(nullptr) {}
+        RemotedRequest(DDF& input) : m_input(input), m_parser(nullptr)
+#ifdef HAVE_GSSAPI
+            , m_gss(GSS_C_NO_CONTEXT)
+#endif
+        {
+        }
+
         virtual ~RemotedRequest() {
             for_each(m_certs.begin(), m_certs.end(), xmltooling::cleanup<XSECCryptoX509>());
             delete m_parser;
         virtual ~RemotedRequest() {
             for_each(m_certs.begin(), m_certs.end(), xmltooling::cleanup<XSECCryptoX509>());
             delete m_parser;
+#ifdef HAVE_GSSAPI
+            if (m_gss != GSS_C_NO_CONTEXT) {
+                OM_uint32 minor;
+                gss_delete_sec_context(&minor, &m_gss, GSS_C_NO_BUFFER);
+            }
+#endif
         }
 
         // GenericRequest
         const char* getScheme() const {
             return m_input["scheme"].string();
         }
         }
 
         // GenericRequest
         const char* getScheme() const {
             return m_input["scheme"].string();
         }
+        bool isSecure() const {
+            return HTTPRequest::isSecure();
+        }
         const char* getHostname() const {
             return m_input["hostname"].string();
         }
         const char* getHostname() const {
             return m_input["hostname"].string();
         }
@@ -93,6 +117,11 @@ namespace shibsp {
 
         const std::vector<XSECCryptoX509*>& getClientCertificates() const;
         
 
         const std::vector<XSECCryptoX509*>& getClientCertificates() const;
         
+#ifdef HAVE_GSSAPI
+        // GSSRequest
+        gss_ctx_id_t getGSSContext() const;
+#endif
+
         // HTTPRequest
         const char* getMethod() const {
             return m_input["method"].string();
         // HTTPRequest
         const char* getMethod() const {
             return m_input["method"].string();
@@ -177,6 +206,34 @@ const std::vector<XSECCryptoX509*>& RemotedRequest::getClientCertificates() cons
     return m_certs;
 }
 
     return m_certs;
 }
 
+#ifdef HAVE_GSSAPI
+gss_ctx_id_t RemotedRequest::getGSSContext() const
+{
+    if (m_gss == GSS_C_NO_CONTEXT) {
+        const char* encoded = m_input["gss_context"].string();
+        if (encoded) {
+            xsecsize_t x;
+            XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(encoded), &x);
+            if (decoded) {
+                gss_buffer_desc importbuf;
+                importbuf.length = x;
+                importbuf.value = decoded;
+                OM_uint32 minor;
+                OM_uint32 major = gss_import_sec_context(&minor, &importbuf, &m_gss);
+                if (major != GSS_S_COMPLETE)
+                    m_gss = GSS_C_NO_CONTEXT;
+#ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
+                XMLString::release(&decoded);
+#else
+                XMLString::release((char**)&decoded);
+#endif
+            }
+        }
+    }
+    return m_gss;
+}
+#endif
+
 long RemotedResponse::sendResponse(std::istream& in, long status)
 {
     string msg;
 long RemotedResponse::sendResponse(std::istream& in, long status)
 {
     string msg;
@@ -228,6 +285,8 @@ void RemotedHandler::setAddress(const char* address)
     }
 }
 
     }
 }
 
+set<string> RemotedHandler::m_remotedHeaders;
+
 RemotedHandler::RemotedHandler()
 {
 }
 RemotedHandler::RemotedHandler()
 {
 }
@@ -240,6 +299,11 @@ RemotedHandler::~RemotedHandler()
         listener->unregListener(m_address.c_str(),this);
 }
 
         listener->unregListener(m_address.c_str(),this);
 }
 
+void RemotedHandler::addRemotedHeader(const char* header)
+{
+    m_remotedHeaders.insert(header);
+}
+
 DDF RemotedHandler::wrap(const SPRequest& request, const vector<string>* headers, bool certs) const
 {
     DDF in = DDF(m_address.c_str()).structure();
 DDF RemotedHandler::wrap(const SPRequest& request, const vector<string>* headers, bool certs) const
 {
     DDF in = DDF(m_address.c_str()).structure();
@@ -257,13 +321,20 @@ DDF RemotedHandler::wrap(const SPRequest& request, const vector<string>* headers
     in.addmember("url").unsafe_string(request.getRequestURL());
     in.addmember("query").string(request.getQueryString());
 
     in.addmember("url").unsafe_string(request.getRequestURL());
     in.addmember("query").string(request.getQueryString());
 
-    if (headers) {
+    if (headers || !m_remotedHeaders.empty()) {
         string hdr;
         DDF hin = in.addmember("headers").structure();
         string hdr;
         DDF hin = in.addmember("headers").structure();
-        for (vector<string>::const_iterator h = headers->begin(); h!=headers->end(); ++h) {
-            hdr = request.getHeader(h->c_str());
+        if (headers) {
+            for (vector<string>::const_iterator h = headers->begin(); h!=headers->end(); ++h) {
+                hdr = request.getHeader(h->c_str());
+                if (!hdr.empty())
+                    hin.addmember(h->c_str()).unsafe_string(hdr.c_str());
+            }
+        }
+        for (set<string>::const_iterator hh = m_remotedHeaders.begin(); hh != m_remotedHeaders.end(); ++hh) {
+            hdr = request.getHeader(hh->c_str());
             if (!hdr.empty())
             if (!hdr.empty())
-                hin.addmember(h->c_str()).unsafe_string(hdr.c_str());
+                hin.addmember(hh->c_str()).unsafe_string(hdr.c_str());
         }
     }
 
         }
     }
 
@@ -289,6 +360,40 @@ DDF RemotedHandler::wrap(const SPRequest& request, const vector<string>* headers
 #endif
     }
 
 #endif
     }
 
+#ifdef HAVE_GSSAPI
+    const GSSRequest* gss = dynamic_cast<const GSSRequest*>(&request);
+    if (gss) {
+        gss_ctx_id_t ctx = gss->getGSSContext();
+        if (ctx != GSS_C_NO_CONTEXT) {
+            OM_uint32 minor;
+            gss_buffer_desc contextbuf;
+            contextbuf.length = 0;
+            contextbuf.value = nullptr;
+            OM_uint32 major = gss_export_sec_context(&minor, &ctx, &contextbuf);
+            if (major == GSS_S_COMPLETE) {
+                xsecsize_t len=0;
+                XMLByte* out=Base64::encode(reinterpret_cast<const XMLByte*>(contextbuf.value), contextbuf.length, &len);
+                if (out) {
+                    string ctx;
+                    ctx.append(reinterpret_cast<char*>(out), len);
+#ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
+                    XMLString::release(&out);
+#else
+                    XMLString::release((char**)&out);
+#endif
+                    in.addmember("gss_context").string(ctx.c_str());
+                }
+                else {
+                    request.log(SPRequest::SPError, "error while base64-encoding GSS context");
+                }
+            }
+            else {
+                request.log(SPRequest::SPError, "error while exporting GSS context");
+            }
+        }
+    }
+#endif
+
     return in;
 }
 
     return in;
 }
 
index f2cbd7f..3ef824e 100644 (file)
 #include "handler/RemotedHandler.h"
 #include "util/CGIParser.h"
 
 #include "handler/RemotedHandler.h"
 #include "util/CGIParser.h"
 
+#include <xmltooling/version.h>
+#include <xmltooling/util/DateTime.h>
+
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>
+#endif
+
 using namespace shibsp;
 #ifndef SHIBSP_LITE
 # include "SessionCache.h"
 using namespace shibsp;
 #ifndef SHIBSP_LITE
 # include "SessionCache.h"
@@ -77,6 +84,7 @@ namespace shibsp {
 
     private:
         pair<bool,long> processMessage(const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse) const;
 
     private:
         pair<bool,long> processMessage(const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse) const;
+        ostream& systemInfo(ostream& os) const;
 
         set<string> m_acl;
     };
 
         set<string> m_acl;
     };
@@ -293,16 +301,20 @@ pair<bool,long> StatusHandler::run(SPRequest& request, bool isHandler) const
         map<string,const char*> props;
         settings.first->getAll(props);
 
         map<string,const char*> props;
         settings.first->getAll(props);
 
+        DateTime now(time(nullptr));
+        now.parseDateTime();
+        auto_ptr_char timestamp(now.getFormattedString());
         request.setContentType("text/xml");
         stringstream msg;
         request.setContentType("text/xml");
         stringstream msg;
-        msg << "<StatusHandler>";
+        msg << "<StatusHandler time='" << timestamp.get() << "'>";
             msg << "<Version Xerces-C='" << XERCES_FULLVERSIONDOT
             msg << "<Version Xerces-C='" << XERCES_FULLVERSIONDOT
+                << "' XML-Tooling-C='" << XMLTOOLING_FULLVERSIONDOT
 #ifndef SHIBSP_LITE
                 << "' XML-Security-C='" << XSEC_FULLVERSIONDOT
                 << "' OpenSAML-C='" << OPENSAML_FULLVERSIONDOT
 #endif
                 << "' Shibboleth='" << PACKAGE_VERSION << "'/>";
 #ifndef SHIBSP_LITE
                 << "' XML-Security-C='" << XSEC_FULLVERSIONDOT
                 << "' OpenSAML-C='" << OPENSAML_FULLVERSIONDOT
 #endif
                 << "' Shibboleth='" << PACKAGE_VERSION << "'/>";
-            msg << "<RequestSettings";
+            systemInfo(msg) << "<RequestSettings";
             for (map<string,const char*>::const_iterator p = props.begin(); p != props.end(); ++p)
                 msg << ' ' << p->first << "='" << p->second << "'";
             msg << '>' << target << "</RequestSettings>";
             for (map<string,const char*>::const_iterator p = props.begin(); p != props.end(); ++p)
                 msg << ' ' << p->first << "='" << p->second << "'";
             msg << '>' << target << "</RequestSettings>";
@@ -326,31 +338,39 @@ pair<bool,long> StatusHandler::run(SPRequest& request, bool isHandler) const
     }
     catch (XMLToolingException& ex) {
         m_log.error("error while processing request: %s", ex.what());
     }
     catch (XMLToolingException& ex) {
         m_log.error("error while processing request: %s", ex.what());
+        DateTime now(time(nullptr));
+        now.parseDateTime();
+        auto_ptr_char timestamp(now.getFormattedString());
         request.setContentType("text/xml");
         stringstream msg;
         request.setContentType("text/xml");
         stringstream msg;
-        msg << "<StatusHandler>";
+        msg << "<StatusHandler time='" << timestamp.get() << "'>";
             msg << "<Version Xerces-C='" << XERCES_FULLVERSIONDOT
             msg << "<Version Xerces-C='" << XERCES_FULLVERSIONDOT
+                << "' XML-Tooling-C='" << XMLTOOLING_FULLVERSIONDOT
 #ifndef SHIBSP_LITE
                 << "' XML-Security-C='" << XSEC_FULLVERSIONDOT
                 << "' OpenSAML-C='" << OPENSAML_FULLVERSIONDOT
 #endif
                 << "' Shibboleth='" << PACKAGE_VERSION << "'/>";
 #ifndef SHIBSP_LITE
                 << "' XML-Security-C='" << XSEC_FULLVERSIONDOT
                 << "' OpenSAML-C='" << OPENSAML_FULLVERSIONDOT
 #endif
                 << "' Shibboleth='" << PACKAGE_VERSION << "'/>";
-            msg << "<Status><Exception type='" << ex.getClassName() << "'>" << ex.what() << "</Exception></Status>";
+            systemInfo(msg) << "<Status><Exception type='" << ex.getClassName() << "'>" << ex.what() << "</Exception></Status>";
         msg << "</StatusHandler>";
         return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
     }
     catch (exception& ex) {
         m_log.error("error while processing request: %s", ex.what());
         msg << "</StatusHandler>";
         return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
     }
     catch (exception& ex) {
         m_log.error("error while processing request: %s", ex.what());
+        DateTime now(time(nullptr));
+        now.parseDateTime();
+        auto_ptr_char timestamp(now.getFormattedString());
         request.setContentType("text/xml");
         stringstream msg;
         request.setContentType("text/xml");
         stringstream msg;
-        msg << "<StatusHandler>";
+        msg << "<StatusHandler time='" << timestamp.get() << "'>";
             msg << "<Version Xerces-C='" << XERCES_FULLVERSIONDOT
             msg << "<Version Xerces-C='" << XERCES_FULLVERSIONDOT
+                << "' XML-Tooling-C='" << XMLTOOLING_FULLVERSIONDOT
 #ifndef SHIBSP_LITE
                 << "' XML-Security-C='" << XSEC_FULLVERSIONDOT
                 << "' OpenSAML-C='" << OPENSAML_FULLVERSIONDOT
 #endif
                 << "' Shibboleth='" << PACKAGE_VERSION << "'/>";
 #ifndef SHIBSP_LITE
                 << "' XML-Security-C='" << XSEC_FULLVERSIONDOT
                 << "' OpenSAML-C='" << OPENSAML_FULLVERSIONDOT
 #endif
                 << "' Shibboleth='" << PACKAGE_VERSION << "'/>";
-            msg << "<Status><Exception type='std::exception'>" << ex.what() << "</Exception></Status>";
+            systemInfo(msg) << "<Status><Exception type='std::exception'>" << ex.what() << "</Exception></Status>";
         msg << "</StatusHandler>";
         return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
     }
         msg << "</StatusHandler>";
         return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
     }
@@ -387,15 +407,22 @@ pair<bool,long> StatusHandler::processMessage(
 #ifndef SHIBSP_LITE
     m_log.debug("processing status request");
 
 #ifndef SHIBSP_LITE
     m_log.debug("processing status request");
 
+    DateTime now(time(nullptr));
+    now.parseDateTime();
+    auto_ptr_char timestamp(now.getFormattedString());
+
     stringstream s;
     stringstream s;
-    s << "<StatusHandler>";
+    s << "<StatusHandler time='" << timestamp.get() << "'>";
     const char* status = "<OK/>";
 
     s << "<Version Xerces-C='" << XERCES_FULLVERSIONDOT
     const char* status = "<OK/>";
 
     s << "<Version Xerces-C='" << XERCES_FULLVERSIONDOT
+        << "' XML-Tooling-C='" << XMLTOOLING_FULLVERSIONDOT
         << "' XML-Security-C='" << XSEC_FULLVERSIONDOT
         << "' OpenSAML-C='" << OPENSAML_FULLVERSIONDOT
         << "' Shibboleth='" << PACKAGE_VERSION << "'/>";
 
         << "' XML-Security-C='" << XSEC_FULLVERSIONDOT
         << "' OpenSAML-C='" << OPENSAML_FULLVERSIONDOT
         << "' Shibboleth='" << PACKAGE_VERSION << "'/>";
 
+    systemInfo(s);
+
     const char* param = nullptr;
     if (param) {
     }
     const char* param = nullptr;
     if (param) {
     }
@@ -488,3 +515,78 @@ pair<bool,long> StatusHandler::processMessage(
     return make_pair(false,0L);
 #endif
 }
     return make_pair(false,0L);
 #endif
 }
+
+#ifdef WIN32
+typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
+#endif
+
+ostream& StatusHandler::systemInfo(ostream& os) const
+{
+#if defined(HAVE_SYS_UTSNAME_H)
+    struct utsname sysinfo;
+    if (uname(&sysinfo) == 0) {
+        os << "<NonWindows";
+        if (*sysinfo.sysname)
+            os << " sysname='" << sysinfo.sysname << "'";
+        if (*sysinfo.nodename)
+            os << " nodename='" << sysinfo.nodename << "'";
+        if (*sysinfo.release)
+            os << " release='" << sysinfo.release << "'";
+        if (*sysinfo.version)
+            os << " version='" << sysinfo.version << "'";
+        if (*sysinfo.machine)
+            os << " machine='" << sysinfo.machine << "'";
+        os << "/>";
+    }
+#elif defined(WIN32)
+    OSVERSIONINFOEX osvi;
+    memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+    if(GetVersionEx((OSVERSIONINFO*)&osvi)) {
+        os << "<Windows"
+           << " version='" << osvi.dwMajorVersion << "." << osvi.dwMinorVersion << "'"
+           << " build='" << osvi.dwBuildNumber << "'";
+        if (osvi.wServicePackMajor > 0)
+            os << " servicepack='" << osvi.wServicePackMajor << "." << osvi.wServicePackMinor << "'";
+        switch (osvi.wProductType) {
+            case VER_NT_WORKSTATION:
+                os << " producttype='Workstation'";
+                break;
+            case VER_NT_SERVER:
+            case VER_NT_DOMAIN_CONTROLLER:
+                os << " producttype='Server'";
+                break;
+        }
+
+        SYSTEM_INFO si;
+        memset(&si, 0, sizeof(SYSTEM_INFO));
+        PGNSI pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo");
+        if(pGNSI)
+            pGNSI(&si);
+        else
+            GetSystemInfo(&si);
+        switch (si.dwProcessorType) {
+            case PROCESSOR_ARCHITECTURE_INTEL:
+                os << " arch='i386'";
+                break;
+            case PROCESSOR_ARCHITECTURE_AMD64:
+                os << " arch='x86_64'";
+                break;
+            case PROCESSOR_ARCHITECTURE_IA64:
+                os << " arch='IA64'";
+                break;
+        }
+        os << " cpucount='" << si.dwNumberOfProcessors << "'";
+
+        MEMORYSTATUSEX ms;
+        memset(&ms, 0, sizeof(MEMORYSTATUSEX));
+        ms.dwLength = sizeof(MEMORYSTATUSEX);
+        if (GlobalMemoryStatusEx(&ms)) {
+            os << " memory='" << (ms.ullTotalPhys / (1024 * 1024)) << "M'";
+        }
+
+        os << "/>";
+    }
+#endif
+    return os;
+}
index ca3f50a..3641be9 100644 (file)
@@ -35,6 +35,7 @@
 #include "SessionCacheEx.h"
 #include "TransactionLog.h"
 #include "attribute/Attribute.h"
 #include "SessionCacheEx.h"
 #include "TransactionLog.h"
 #include "attribute/Attribute.h"
+#include "handler/RemotedHandler.h"
 #include "remoting/ListenerService.h"
 #include "util/SPConstants.h"
 
 #include "remoting/ListenerService.h"
 #include "util/SPConstants.h"
 
@@ -106,7 +107,7 @@ namespace shibsp {
             );
         bool matches(
             const Application& app,
             );
         bool matches(
             const Application& app,
-            const xmltooling::HTTPRequest& request,
+            const HTTPRequest& request,
             const saml2md::EntityDescriptor* issuer,
             const saml2::NameID& nameid,
             const set<string>* indexes
             const saml2md::EntityDescriptor* issuer,
             const saml2::NameID& nameid,
             const set<string>* indexes
@@ -116,7 +117,12 @@ namespace shibsp {
         void remove(const Application& app, const char* key);
         void test();
 
         void remove(const Application& app, const char* key);
         void test();
 
-        string active(const Application& app, const xmltooling::HTTPRequest& request) {
+        string active(const Application& app, const HTTPRequest& request) {
+            if (!m_inboundHeader.empty()) {
+                string session_id = request.getHeader(m_inboundHeader.c_str());
+                if (!session_id.empty())
+                    return session_id;
+            }
             pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
             const char* session_id = request.getCookie(shib_cookie.first.c_str());
             return (session_id ? session_id : "");
             pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
             const char* session_id = request.getCookie(shib_cookie.first.c_str());
             return (session_id ? session_id : "");
@@ -129,47 +135,8 @@ namespace shibsp {
             return nullptr;
         }
 
             return nullptr;
         }
 
-        Session* find(const Application& app, HTTPRequest& request, const char* client_addr=nullptr, time_t* timeout=nullptr) {
-            string id = active(app, request);
-            if (id.empty())
-                return nullptr;
-            try {
-                Session* session = find(app, id.c_str(), client_addr, timeout);
-                if (session)
-                    return session;
-                HTTPResponse* response = dynamic_cast<HTTPResponse*>(&request);
-                if (response) {
-                    pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
-                    string exp(shib_cookie.second);
-                    exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
-                    response->setCookie(shib_cookie.first.c_str(), exp.c_str());
-                }
-            }
-            catch (exception&) {
-                HTTPResponse* response = dynamic_cast<HTTPResponse*>(&request);
-                if (response) {
-                    pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
-                    string exp(shib_cookie.second);
-                    exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
-                    response->setCookie(shib_cookie.first.c_str(), exp.c_str());
-                }
-                throw;
-            }
-            return nullptr;
-        }
-
-        void remove(const Application& app, const HTTPRequest& request, HTTPResponse* response=nullptr) {
-            pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
-            const char* session_id = request.getCookie(shib_cookie.first.c_str());
-            if (session_id && *session_id) {
-                if (response) {
-                    string exp(shib_cookie.second);
-                    exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
-                    response->setCookie(shib_cookie.first.c_str(), exp.c_str());
-                }
-                remove(app, session_id);
-            }
-        }
+        Session* find(const Application& app, HTTPRequest& request, const char* client_addr=nullptr, time_t* timeout=nullptr);
+        void remove(const Application& app, const HTTPRequest& request, HTTPResponse* response=nullptr);
 
         unsigned long getCacheTimeout(const Application& app) {
             // Computes offset for adjusting expiration of sessions.
 
         unsigned long getCacheTimeout(const Application& app) {
             // Computes offset for adjusting expiration of sessions.
@@ -203,6 +170,7 @@ namespace shibsp {
 #endif
         const DOMElement* m_root;         // Only valid during initialization
         unsigned long m_inprocTimeout,m_cacheTimeout,m_cacheAllowance;
 #endif
         const DOMElement* m_root;         // Only valid during initialization
         unsigned long m_inprocTimeout,m_cacheTimeout,m_cacheAllowance;
+        string m_inboundHeader,m_outboundHeader;
 
         // inproc means we buffer sessions in memory
         RWLock* m_lock;
 
         // inproc means we buffer sessions in memory
         RWLock* m_lock;
@@ -775,6 +743,8 @@ SSCache::SSCache(const DOMElement* e)
     static const XMLCh cacheAssertions[] =  UNICODE_LITERAL_15(c,a,c,h,e,A,s,s,e,r,t,i,o,n,s);
     static const XMLCh cacheTimeout[] =     UNICODE_LITERAL_12(c,a,c,h,e,T,i,m,e,o,u,t);
     static const XMLCh inprocTimeout[] =    UNICODE_LITERAL_13(i,n,p,r,o,c,T,i,m,e,o,u,t);
     static const XMLCh cacheAssertions[] =  UNICODE_LITERAL_15(c,a,c,h,e,A,s,s,e,r,t,i,o,n,s);
     static const XMLCh cacheTimeout[] =     UNICODE_LITERAL_12(c,a,c,h,e,T,i,m,e,o,u,t);
     static const XMLCh inprocTimeout[] =    UNICODE_LITERAL_13(i,n,p,r,o,c,T,i,m,e,o,u,t);
+    static const XMLCh inboundHeader[] =    UNICODE_LITERAL_13(i,n,b,o,u,n,d,H,e,a,d,e,r);
+    static const XMLCh outboundHeader[] =   UNICODE_LITERAL_14(o,u,t,b,o,u,n,d,H,e,a,d,e,r);
     static const XMLCh _StorageService[] =  UNICODE_LITERAL_14(S,t,o,r,a,g,e,S,e,r,v,i,c,e);
     static const XMLCh _StorageServiceLite[] = UNICODE_LITERAL_18(S,t,o,r,a,g,e,S,e,r,v,i,c,e,L,i,t,e);
 
     static const XMLCh _StorageService[] =  UNICODE_LITERAL_14(S,t,o,r,a,g,e,S,e,r,v,i,c,e);
     static const XMLCh _StorageServiceLite[] = UNICODE_LITERAL_18(S,t,o,r,a,g,e,S,e,r,v,i,c,e,L,i,t,e);
 
@@ -782,6 +752,10 @@ SSCache::SSCache(const DOMElement* e)
     m_cacheAllowance = XMLHelper::getAttrInt(e, 0, cacheAllowance);
     if (inproc)
         m_inprocTimeout = XMLHelper::getAttrInt(e, 900, inprocTimeout);
     m_cacheAllowance = XMLHelper::getAttrInt(e, 0, cacheAllowance);
     if (inproc)
         m_inprocTimeout = XMLHelper::getAttrInt(e, 900, inprocTimeout);
+    m_inboundHeader = XMLHelper::getAttrString(e, nullptr, inboundHeader);
+    if (!m_inboundHeader.empty())
+        RemotedHandler::addRemotedHeader(m_inboundHeader.c_str());
+    m_outboundHeader = XMLHelper::getAttrString(e, nullptr, outboundHeader);
 
 #ifndef SHIBSP_LITE
     if (conf.isEnabled(SPConfig::OutOfProcess)) {
 
 #ifndef SHIBSP_LITE
     if (conf.isEnabled(SPConfig::OutOfProcess)) {
@@ -1127,6 +1101,9 @@ void SSCache::insert(
         xlog->log.info("}");
     }
 
         xlog->log.info("}");
     }
 
+    if (!m_outboundHeader.empty())
+        httpResponse.setResponseHeader(m_outboundHeader.c_str(), key.get());
+
     time_t cookieLifetime = 0;
     pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_", &cookieLifetime);
     string k(key.get());
     time_t cookieLifetime = 0;
     pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_", &cookieLifetime);
     string k(key.get());
@@ -1525,6 +1502,65 @@ Session* SSCache::find(const Application& app, const char* key, const char* clie
     return session;
 }
 
     return session;
 }
 
+Session* SSCache::find(const Application& app, HTTPRequest& request, const char* client_addr, time_t* timeout)
+{
+    string id = active(app, request);
+    if (id.empty())
+        return nullptr;
+    try {
+        Session* session = find(app, id.c_str(), client_addr, timeout);
+        if (session)
+            return session;
+        HTTPResponse* response = dynamic_cast<HTTPResponse*>(&request);
+        if (response) {
+            if (!m_outboundHeader.empty())
+                response->setResponseHeader(m_outboundHeader.c_str(), nullptr);
+            pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
+            string exp(shib_cookie.second);
+            exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
+            response->setCookie(shib_cookie.first.c_str(), exp.c_str());
+        }
+    }
+    catch (exception&) {
+        HTTPResponse* response = dynamic_cast<HTTPResponse*>(&request);
+        if (response) {
+            if (!m_outboundHeader.empty())
+                response->setResponseHeader(m_outboundHeader.c_str(), nullptr);
+            pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
+            string exp(shib_cookie.second);
+            exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
+            response->setCookie(shib_cookie.first.c_str(), exp.c_str());
+        }
+        throw;
+    }
+    return nullptr;
+}
+
+void SSCache::remove(const Application& app, const HTTPRequest& request, HTTPResponse* response)
+{
+    string session_id;
+    pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
+
+    if (!m_inboundHeader.empty())
+        session_id = request.getHeader(m_inboundHeader.c_str());
+    if (session_id.empty()) {
+        const char* c = request.getCookie(shib_cookie.first.c_str());
+        if (c && *c)
+            session_id = c;
+    }
+
+    if (!session_id.empty()) {
+        if (response) {
+            if (!m_outboundHeader.empty())
+                response->setResponseHeader(m_outboundHeader.c_str(), nullptr);
+            string exp(shib_cookie.second);
+            exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
+            response->setCookie(shib_cookie.first.c_str(), exp.c_str());
+        }
+        remove(app, session_id.c_str());
+    }
+}
+
 void SSCache::remove(const Application& app, const char* key)
 {
 #ifdef _DEBUG
 void SSCache::remove(const Application& app, const char* key)
 {
 #ifdef _DEBUG
index 27153bd..9059491 100644 (file)
@@ -479,8 +479,6 @@ XMLRequestMapperImpl::XMLRequestMapperImpl(const DOMElement* e, Category& log) :
 #ifdef _DEBUG
     xmltooling::NDC ndc("XMLRequestMapperImpl");
 #endif
 #ifdef _DEBUG
     xmltooling::NDC ndc("XMLRequestMapperImpl");
 #endif
-    static const XMLCh _default[] =     UNICODE_LITERAL_7(d,e,f,a,u,l,t);
-    static const XMLCh _id[] =          UNICODE_LITERAL_2(i,d);
     static const XMLCh _RequestMap[] =  UNICODE_LITERAL_10(R,e,q,u,e,s,t,M,a,p);
 
     if (e && !XMLHelper::isNodeNamed(e, SHIB2SPCONFIG_NS, _RequestMap))
     static const XMLCh _RequestMap[] =  UNICODE_LITERAL_10(R,e,q,u,e,s,t,M,a,p);
 
     if (e && !XMLHelper::isNodeNamed(e, SHIB2SPCONFIG_NS, _RequestMap))
index 3179637..1c1d9f4 100644 (file)
@@ -270,7 +270,7 @@ namespace {
     class SHIBSP_DLLLOCAL XMLConfigImpl : public DOMPropertySet, public DOMNodeFilter
     {
     public:
     class SHIBSP_DLLLOCAL XMLConfigImpl : public DOMPropertySet, public DOMNodeFilter
     {
     public:
-        XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer, Category& log);
+        XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, Category& log);
         ~XMLConfigImpl();
 
         RequestMapper* m_requestMapper;
         ~XMLConfigImpl();
 
         RequestMapper* m_requestMapper;
@@ -293,12 +293,11 @@ namespace {
         }
 
     private:
         }
 
     private:
-        void doExtensions(const DOMElement* e, const char* label, Category& log);
-        void doListener(const DOMElement* e, Category& log);
-        void doCaching(const DOMElement* e, Category& log);
+        void doExtensions(const DOMElement*, const char*, Category&);
+        void doListener(const DOMElement*, XMLConfig*, Category&);
+        void doCaching(const DOMElement*, XMLConfig*, Category&);
         void cleanup();
 
         void cleanup();
 
-        const XMLConfig* m_outer;
         DOMDocument* m_document;
     };
 
         DOMDocument* m_document;
     };
 
@@ -440,11 +439,11 @@ namespace {
     private:
         friend class XMLConfigImpl;
         XMLConfigImpl* m_impl;
     private:
         friend class XMLConfigImpl;
         XMLConfigImpl* m_impl;
-        mutable ListenerService* m_listener;
-        mutable SessionCache* m_sessionCache;
+        ListenerService* m_listener;
+        SessionCache* m_sessionCache;
 #ifndef SHIBSP_LITE
 #ifndef SHIBSP_LITE
-        mutable TransactionLog* m_tranLog;
-        mutable map<string,StorageService*> m_storage;
+        TransactionLog* m_tranLog;
+        map<string,StorageService*> m_storage;
 #endif
     };
 
 #endif
     };
 
@@ -1698,7 +1697,7 @@ void XMLConfigImpl::doExtensions(const DOMElement* e, const char* label, Categor
     }
 }
 
     }
 }
 
-void XMLConfigImpl::doListener(const DOMElement* e, Category& log)
+void XMLConfigImpl::doListener(const DOMElement* e, XMLConfig* conf, Category& log)
 {
 #ifdef WIN32
     string plugtype(TCP_LISTENER_SERVICE);
 {
 #ifdef WIN32
     string plugtype(TCP_LISTENER_SERVICE);
@@ -1723,19 +1722,19 @@ void XMLConfigImpl::doListener(const DOMElement* e, Category& log)
     }
 
     log.info("building ListenerService of type %s...", plugtype.c_str());
     }
 
     log.info("building ListenerService of type %s...", plugtype.c_str());
-    m_outer->m_listener = SPConfig::getConfig().ListenerServiceManager.newPlugin(plugtype.c_str(), child);
+    conf->m_listener = SPConfig::getConfig().ListenerServiceManager.newPlugin(plugtype.c_str(), child);
 }
 
 }
 
-void XMLConfigImpl::doCaching(const DOMElement* e, Category& log)
+void XMLConfigImpl::doCaching(const DOMElement* e, XMLConfig* conf, Category& log)
 {
 {
-    SPConfig& conf = SPConfig::getConfig();
+    SPConfig& spConf = SPConfig::getConfig();
 #ifndef SHIBSP_LITE
     SAMLConfig& samlConf = SAMLConfig::getConfig();
 #endif
 
     DOMElement* child;
 #ifndef SHIBSP_LITE
 #ifndef SHIBSP_LITE
     SAMLConfig& samlConf = SAMLConfig::getConfig();
 #endif
 
     DOMElement* child;
 #ifndef SHIBSP_LITE
-    if (conf.isEnabled(SPConfig::OutOfProcess)) {
+    if (spConf.isEnabled(SPConfig::OutOfProcess)) {
         XMLToolingConfig& xmlConf = XMLToolingConfig::getConfig();
         // First build any StorageServices.
         child = XMLHelper::getFirstChildElement(e, _StorageService);
         XMLToolingConfig& xmlConf = XMLToolingConfig::getConfig();
         // First build any StorageServices.
         child = XMLHelper::getFirstChildElement(e, _StorageService);
@@ -1745,7 +1744,7 @@ void XMLConfigImpl::doCaching(const DOMElement* e, Category& log)
             if (!t.empty()) {
                 try {
                     log.info("building StorageService (%s) of type %s...", id.c_str(), t.c_str());
             if (!t.empty()) {
                 try {
                     log.info("building StorageService (%s) of type %s...", id.c_str(), t.c_str());
-                    m_outer->m_storage[id] = xmlConf.StorageServiceManager.newPlugin(t.c_str(), child);
+                    conf->m_storage[id] = xmlConf.StorageServiceManager.newPlugin(t.c_str(), child);
                 }
                 catch (exception& ex) {
                     log.crit("failed to instantiate StorageService (%s): %s", id.c_str(), ex.what());
                 }
                 catch (exception& ex) {
                     log.crit("failed to instantiate StorageService (%s): %s", id.c_str(), ex.what());
@@ -1754,9 +1753,9 @@ void XMLConfigImpl::doCaching(const DOMElement* e, Category& log)
             child = XMLHelper::getNextSiblingElement(child, _StorageService);
         }
 
             child = XMLHelper::getNextSiblingElement(child, _StorageService);
         }
 
-        if (m_outer->m_storage.empty()) {
+        if (conf->m_storage.empty()) {
             log.info("no StorageService plugin(s) installed, using (mem) in-memory instance");
             log.info("no StorageService plugin(s) installed, using (mem) in-memory instance");
-            m_outer->m_storage["mem"] = xmlConf.StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE, nullptr);
+            conf->m_storage["mem"] = xmlConf.StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE, nullptr);
         }
 
         // Replay cache.
         }
 
         // Replay cache.
@@ -1765,23 +1764,23 @@ void XMLConfigImpl::doCaching(const DOMElement* e, Category& log)
         if (child) {
             string ssid(XMLHelper::getAttrString(child, nullptr, _StorageService));
             if (!ssid.empty()) {
         if (child) {
             string ssid(XMLHelper::getAttrString(child, nullptr, _StorageService));
             if (!ssid.empty()) {
-                if (m_outer->m_storage.count(ssid)) {
+                if (conf->m_storage.count(ssid)) {
                     log.info("building ReplayCache on top of StorageService (%s)...", ssid.c_str());
                     log.info("building ReplayCache on top of StorageService (%s)...", ssid.c_str());
-                    replaySS = m_outer->m_storage[ssid];
+                    replaySS = conf->m_storage[ssid];
                 }
                 else {
                     log.error("unable to locate StorageService (%s), using arbitrary instance for ReplayCache", ssid.c_str());
                 }
                 else {
                     log.error("unable to locate StorageService (%s), using arbitrary instance for ReplayCache", ssid.c_str());
-                    replaySS = m_outer->m_storage.begin()->second;
+                    replaySS = conf->m_storage.begin()->second;
                 }
             }
             else {
                 log.info("no StorageService specified for ReplayCache, using arbitrary instance");
                 }
             }
             else {
                 log.info("no StorageService specified for ReplayCache, using arbitrary instance");
-                replaySS = m_outer->m_storage.begin()->second;
+                replaySS = conf->m_storage.begin()->second;
             }
         }
         else {
             log.info("no ReplayCache specified, using arbitrary StorageService instance");
             }
         }
         else {
             log.info("no ReplayCache specified, using arbitrary StorageService instance");
-            replaySS = m_outer->m_storage.begin()->second;
+            replaySS = conf->m_storage.begin()->second;
         }
         xmlConf.setReplayCache(new ReplayCache(replaySS));
 
         }
         xmlConf.setReplayCache(new ReplayCache(replaySS));
 
@@ -1790,9 +1789,9 @@ void XMLConfigImpl::doCaching(const DOMElement* e, Category& log)
         if (child) {
             string ssid(XMLHelper::getAttrString(child, nullptr, _StorageService));
             if (!ssid.empty()) {
         if (child) {
             string ssid(XMLHelper::getAttrString(child, nullptr, _StorageService));
             if (!ssid.empty()) {
-                if (m_outer->m_storage.count(ssid)) {
+                if (conf->m_storage.count(ssid)) {
                     log.info("building ArtifactMap on top of StorageService (%s)...", ssid.c_str());
                     log.info("building ArtifactMap on top of StorageService (%s)...", ssid.c_str());
-                    samlConf.setArtifactMap(new ArtifactMap(child, m_outer->m_storage[ssid]));
+                    samlConf.setArtifactMap(new ArtifactMap(child, conf->m_storage[ssid]));
                 }
                 else {
                     log.error("unable to locate StorageService (%s), using in-memory ArtifactMap", ssid.c_str());
                 }
                 else {
                     log.error("unable to locate StorageService (%s), using in-memory ArtifactMap", ssid.c_str());
@@ -1816,21 +1815,21 @@ void XMLConfigImpl::doCaching(const DOMElement* e, Category& log)
         string t(XMLHelper::getAttrString(child, nullptr, _type));
         if (!t.empty()) {
             log.info("building SessionCache of type %s...", t.c_str());
         string t(XMLHelper::getAttrString(child, nullptr, _type));
         if (!t.empty()) {
             log.info("building SessionCache of type %s...", t.c_str());
-            m_outer->m_sessionCache = conf.SessionCacheManager.newPlugin(t.c_str(), child);
+            conf->m_sessionCache = spConf.SessionCacheManager.newPlugin(t.c_str(), child);
         }
     }
         }
     }
-    if (!m_outer->m_sessionCache) {
+    if (!conf->m_sessionCache) {
         log.info("no SessionCache specified, using StorageService-backed instance");
         log.info("no SessionCache specified, using StorageService-backed instance");
-        m_outer->m_sessionCache = conf.SessionCacheManager.newPlugin(STORAGESERVICE_SESSION_CACHE, nullptr);
+        conf->m_sessionCache = spConf.SessionCacheManager.newPlugin(STORAGESERVICE_SESSION_CACHE, nullptr);
     }
 }
 
     }
 }
 
-XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer, Category& log)
+XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, Category& log)
     : m_requestMapper(nullptr),
 #ifndef SHIBSP_LITE
         m_policy(nullptr),
 #endif
     : m_requestMapper(nullptr),
 #ifndef SHIBSP_LITE
         m_policy(nullptr),
 #endif
-        m_outer(outer), m_document(nullptr)
+        m_document(nullptr)
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("XMLConfigImpl");
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("XMLConfigImpl");
@@ -1868,7 +1867,7 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
 
 #ifndef SHIBSP_LITE
             if (first)
 
 #ifndef SHIBSP_LITE
             if (first)
-                m_outer->m_tranLog = new TransactionLog();
+                outer->m_tranLog = new TransactionLog();
 #endif
         }
 
 #endif
         }
 
@@ -1940,18 +1939,18 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
 
             // Instantiate the ListenerService and SessionCache objects.
             if (conf.isEnabled(SPConfig::Listener))
 
             // Instantiate the ListenerService and SessionCache objects.
             if (conf.isEnabled(SPConfig::Listener))
-                doListener(e, log);
+                doListener(e, outer, log);
 
 #ifndef SHIBSP_LITE
 
 #ifndef SHIBSP_LITE
-            if (m_outer->m_listener && conf.isEnabled(SPConfig::OutOfProcess) && !conf.isEnabled(SPConfig::InProcess)) {
-                m_outer->m_listener->regListener("set::RelayState", const_cast<XMLConfig*>(m_outer));
-                m_outer->m_listener->regListener("get::RelayState", const_cast<XMLConfig*>(m_outer));
-                m_outer->m_listener->regListener("set::PostData", const_cast<XMLConfig*>(m_outer));
-                m_outer->m_listener->regListener("get::PostData", const_cast<XMLConfig*>(m_outer));
+            if (outer->m_listener && conf.isEnabled(SPConfig::OutOfProcess) && !conf.isEnabled(SPConfig::InProcess)) {
+                outer->m_listener->regListener("set::RelayState", outer);
+                outer->m_listener->regListener("get::RelayState", outer);
+                outer->m_listener->regListener("set::PostData", outer);
+                outer->m_listener->regListener("get::PostData", outer);
             }
 #endif
             if (conf.isEnabled(SPConfig::Caching))
             }
 #endif
             if (conf.isEnabled(SPConfig::Caching))
-                doCaching(e, log);
+                doCaching(e, outer, log);
         } // end of first-time-only stuff
 
         // Back to the fully dynamic stuff...next up is the RequestMapper.
         } // end of first-time-only stuff
 
         // Back to the fully dynamic stuff...next up is the RequestMapper.
@@ -2050,13 +2049,13 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
             log.fatal("can't build default Application object, missing conf:ApplicationDefaults element?");
             throw ConfigurationException("can't build default Application object, missing conf:ApplicationDefaults element?");
         }
             log.fatal("can't build default Application object, missing conf:ApplicationDefaults element?");
             throw ConfigurationException("can't build default Application object, missing conf:ApplicationDefaults element?");
         }
-        XMLApplication* defapp = new XMLApplication(m_outer, pp, child);
+        XMLApplication* defapp = new XMLApplication(outer, pp, child);
         m_appmap[defapp->getId()] = defapp;
 
         // Load any overrides.
         child = XMLHelper::getFirstChildElement(child, ApplicationOverride);
         while (child) {
         m_appmap[defapp->getId()] = defapp;
 
         // Load any overrides.
         child = XMLHelper::getFirstChildElement(child, ApplicationOverride);
         while (child) {
-            auto_ptr<XMLApplication> iapp(new XMLApplication(m_outer, pp, child, defapp));
+            auto_ptr<XMLApplication> iapp(new XMLApplication(outer, pp, child, defapp));
             if (m_appmap.count(iapp->getId()))
                 log.crit("found conf:ApplicationOverride element with duplicate id attribute (%s), skipping it", iapp->getId());
             else {
             if (m_appmap.count(iapp->getId()))
                 log.crit("found conf:ApplicationOverride element with duplicate id attribute (%s), skipping it", iapp->getId());
             else {
@@ -2066,6 +2065,25 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
 
             child = XMLHelper::getNextSiblingElement(child, ApplicationOverride);
         }
 
             child = XMLHelper::getNextSiblingElement(child, ApplicationOverride);
         }
+
+        // Check for extra AuthTypes to recognize.
+        if (conf.isEnabled(SPConfig::InProcess)) {
+            const PropertySet* inprocs = getPropertySet("InProcess");
+            if (inprocs) {
+                pair<bool,const char*> extraAuthTypes = inprocs->getString("extraAuthTypes");
+                if (extraAuthTypes.first) {
+                    string types=extraAuthTypes.second;
+                    unsigned int j_types=0;
+                    for (unsigned int i_types=0;  i_types < types.length();  i_types++) {
+                        if (types.at(i_types) == ' ') {
+                            outer->m_authTypes.insert(types.substr(j_types, i_types - j_types));
+                            j_types = i_types + 1;
+                        }
+                    }
+                    outer->m_authTypes.insert(types.substr(j_types, types.length() - j_types));
+                }
+            }
+        }
     }
     catch (exception&) {
         cleanup();
     }
     catch (exception&) {
         cleanup();
index 81a331c..ade8cb9 100644 (file)
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="binding\ProtocolProvider.h" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="binding\ProtocolProvider.h" />\r
+    <ClInclude Include="GSSRequest.h" />\r
     <ClInclude Include="handler\LogoutInitiator.h" />\r
     <ClInclude Include="remoting\impl\SocketListener.h" />\r
     <ClInclude Include="AbstractSPRequest.h" />\r
     <ClInclude Include="handler\LogoutInitiator.h" />\r
     <ClInclude Include="remoting\impl\SocketListener.h" />\r
     <ClInclude Include="AbstractSPRequest.h" />\r
index 2eff898..654a364 100644 (file)
     <ClInclude Include="binding\ProtocolProvider.h">\r
       <Filter>Header Files\binding</Filter>\r
     </ClInclude>\r
     <ClInclude Include="binding\ProtocolProvider.h">\r
       <Filter>Header Files\binding</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="GSSRequest.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ResourceCompile Include="shibsp.rc">\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ResourceCompile Include="shibsp.rc">\r
index cd56309..8839b82 100644 (file)
   <ItemGroup>\r
     <ClCompile Include="AbstractSPRequest.cpp" />\r
     <ClCompile Include="Application.cpp" />\r
   <ItemGroup>\r
     <ClCompile Include="AbstractSPRequest.cpp" />\r
     <ClCompile Include="Application.cpp" />\r
+    <ClCompile Include="attribute\Base64AttributeDecoder.cpp" />\r
     <ClCompile Include="binding\impl\XMLProtocolProvider.cpp" />\r
     <ClCompile Include="handler\impl\DiscoveryFeed.cpp" />\r
     <ClCompile Include="handler\impl\LogoutInitiator.cpp" />\r
     <ClCompile Include="binding\impl\XMLProtocolProvider.cpp" />\r
     <ClCompile Include="handler\impl\DiscoveryFeed.cpp" />\r
     <ClCompile Include="handler\impl\LogoutInitiator.cpp" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="binding\ProtocolProvider.h" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="binding\ProtocolProvider.h" />\r
+    <ClInclude Include="GSSRequest.h" />\r
     <ClInclude Include="handler\LogoutInitiator.h" />\r
     <ClInclude Include="remoting\impl\SocketListener.h" />\r
     <ClInclude Include="AbstractSPRequest.h" />\r
     <ClInclude Include="handler\LogoutInitiator.h" />\r
     <ClInclude Include="remoting\impl\SocketListener.h" />\r
     <ClInclude Include="AbstractSPRequest.h" />\r
index f1da19e..b52f78e 100644 (file)
     <ClCompile Include="handler\impl\DiscoveryFeed.cpp">\r
       <Filter>Source Files\handler\impl</Filter>\r
     </ClCompile>\r
     <ClCompile Include="handler\impl\DiscoveryFeed.cpp">\r
       <Filter>Source Files\handler\impl</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="attribute\Base64AttributeDecoder.cpp">\r
+      <Filter>Source Files\attribute</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="remoting\impl\SocketListener.h">\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="remoting\impl\SocketListener.h">\r
     <ClInclude Include="binding\ProtocolProvider.h">\r
       <Filter>Header Files\binding</Filter>\r
     </ClInclude>\r
     <ClInclude Include="binding\ProtocolProvider.h">\r
       <Filter>Header Files\binding</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="GSSRequest.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ResourceCompile Include="shibsp.rc">\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ResourceCompile Include="shibsp.rc">\r