Imported Upstream version 2.3.1+dfsg
authorRuss Allbery <rra@debian.org>
Fri, 18 Dec 2009 00:52:52 +0000 (16:52 -0800)
committerRuss Allbery <rra@debian.org>
Fri, 18 Dec 2009 00:52:52 +0000 (16:52 -0800)
41 files changed:
Portfile
Portfile.in
adfs/adfs.rc
apache/mod_shib_13.rc
apache/mod_shib_20.rc
apache/mod_shib_22.rc
config_win32.h
configs/shibboleth2.xml
configs/shibd-redhat.in
configs/shibd-suse.in
configure
configure.ac
doc/README.txt
doc/RELEASE.txt
fastcgi/shibauthorizer.rc
fastcgi/shibresponder.rc
isapi_shib/isapi_shib.rc
memcache-store/memcache-store.rc
nsapi_shib/nsapi_shib.rc
odbc-store/odbc-store.rc
pkginfo
schemas/shibboleth-2.0-native-sp-config.xsd
shibboleth.spec
shibboleth.spec.in
shibd/shibd.rc
shibd/shibd_win32.cpp
shibsp/Makefile.am
shibsp/Makefile.in
shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp
shibsp/attribute/resolver/impl/SimpleAggregationAttributeResolver.cpp
shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp
shibsp/handler/impl/AbstractHandler.cpp
shibsp/handler/impl/AssertionConsumerService.cpp
shibsp/handler/impl/SAML2ArtifactResolution.cpp
shibsp/handler/impl/SAML2Logout.cpp
shibsp/handler/impl/SAML2LogoutInitiator.cpp
shibsp/handler/impl/SAMLDSSessionInitiator.cpp
shibsp/impl/XMLServiceProvider.cpp
shibsp/paths.h
shibsp/shibsp.rc
shibsp/version.h

index 6a37645..7e6f657 100644 (file)
--- a/Portfile
+++ b/Portfile
@@ -1,7 +1,7 @@
 PortSystem 1.0
 
 name               shibboleth
-version            2.3
+version            2.3.1
 categories         security www shibboleth
 maintainers        scantor snc
 description        Shibboleth Native Service Provider
@@ -60,6 +60,18 @@ post-destroot {
        eval file delete [glob ${destroot}${prefix}/lib/${name}/*.la]
 }
 
+post-activate {
+    # Make sure initial conf files are present and set up correctly
+    set confDir ${prefix}/etc/${name}
+    foreach f [glob -tails -directory ${confDir} *.dist] {
+        regexp {(.+)\.dist} $f ign destname
+        if {![file exists ${confDir}/${destname}]} {
+            file copy ${confDir}/${f} ${confDir}/${destname}
+        }
+    }
+    system "cd ${prefix}/etc/${name} && ./keygen.sh -b"
+}
+
 startupitem.create      yes
 startupitem.name        shibd
 startupitem.executable  ${prefix}/sbin/shibd -F -f -p ${prefix}/var/run/${name}/shibd.pid
index 2408f92..3adab00 100644 (file)
@@ -60,6 +60,18 @@ post-destroot {
        eval file delete [glob ${destroot}${prefix}/lib/${name}/*.la]
 }
 
+post-activate {
+    # Make sure initial conf files are present and set up correctly
+    set confDir ${prefix}/etc/${name}
+    foreach f [glob -tails -directory ${confDir} *.dist] {
+        regexp {(.+)\.dist} $f ign destname
+        if {![file exists ${confDir}/${destname}]} {
+            file copy ${confDir}/${f} ${confDir}/${destname}
+        }
+    }
+    system "cd ${prefix}/etc/${name} && ./keygen.sh -b"
+}
+
 startupitem.create      yes
 startupitem.name        shibd
 startupitem.executable  ${prefix}/sbin/shibd -F -f -p ${prefix}/var/run/${name}/shibd.pid
index 9e46d04..c3a45fe 100644 (file)
@@ -54,8 +54,8 @@ END
 //\r
 \r
 VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION 2,3,0,0\r
- PRODUCTVERSION 2,3,0,0\r
+ FILEVERSION 2,3,1,0\r
+ PRODUCTVERSION 2,3,1,0\r
  FILEFLAGSMASK 0x3fL\r
 #ifdef _DEBUG\r
  FILEFLAGS 0x1L\r
@@ -73,7 +73,7 @@ BEGIN
             VALUE "Comments", "\0"\r
             VALUE "CompanyName", "Internet2\0"\r
             VALUE "FileDescription", "Shibboleth ADFSv1 Plugin\0"\r
-            VALUE "FileVersion", "2, 3, 0, 0\0"\r
+            VALUE "FileVersion", "2, 3, 1, 0\0"\r
 #ifdef SHIBSP_LITE\r
             VALUE "InternalName", "adfs-lite\0"\r
 #else\r
@@ -87,8 +87,8 @@ BEGIN
             VALUE "OriginalFilename", "adfs.so\0"\r
 #endif\r
             VALUE "PrivateBuild", "\0"\r
-            VALUE "ProductName", "Shibboleth 2.3\0"\r
-            VALUE "ProductVersion", "2, 3, 0, 0\0"\r
+            VALUE "ProductName", "Shibboleth 2.3.1\0"\r
+            VALUE "ProductVersion", "2, 3, 1, 0\0"\r
             VALUE "SpecialBuild", "\0"\r
         END\r
     END\r
index 1ef85b6..2bff418 100644 (file)
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,3,0,0
- PRODUCTVERSION 2,3,0,0
+ FILEVERSION 2,3,1,0
+ PRODUCTVERSION 2,3,1,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -47,14 +47,14 @@ BEGIN
             VALUE "Comments", "\0"
             VALUE "CompanyName", "Internet2\0"
             VALUE "FileDescription", "Shibboleth Apache 1.3 Module\0"
-            VALUE "FileVersion", "2, 3, 0, 0\0"
+            VALUE "FileVersion", "2, 3, 1, 0\0"
             VALUE "InternalName", "mod_shib_13\0"
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "mod_shib_13.so\0"
             VALUE "PrivateBuild", "\0"
-            VALUE "ProductName", "Shibboleth 2.3\0"
-            VALUE "ProductVersion", "2, 3, 0, 0\0"
+            VALUE "ProductName", "Shibboleth 2.3.1\0"
+            VALUE "ProductVersion", "2, 3, 1, 0\0"
             VALUE "SpecialBuild", "\0"
         END
     END
index 79dd05e..bffa8f8 100644 (file)
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,3,0,0
- PRODUCTVERSION 2,3,0,0
+ FILEVERSION 2,3,1,0
+ PRODUCTVERSION 2,3,1,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -47,14 +47,14 @@ BEGIN
             VALUE "Comments", "\0"
             VALUE "CompanyName", "Internet2\0"
             VALUE "FileDescription", "Shibboleth Apache 2.0 Module\0"
-            VALUE "FileVersion", "2, 3, 0, 0\0"
+            VALUE "FileVersion", "2, 3, 1, 0\0"
             VALUE "InternalName", "mod_shib_20\0"
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "mod_shib_20.so\0"
             VALUE "PrivateBuild", "\0"
-            VALUE "ProductName", "Shibboleth 2.3\0"
-            VALUE "ProductVersion", "2, 3, 0, 0\0"
+            VALUE "ProductName", "Shibboleth 2.3.1\0"
+            VALUE "ProductVersion", "2, 3, 1, 0\0"
             VALUE "SpecialBuild", "\0"
         END
     END
index 24182bd..2864f5c 100644 (file)
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,3,0,0
- PRODUCTVERSION 2,3,0,0
+ FILEVERSION 2,3,1,0
+ PRODUCTVERSION 2,3,1,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -47,14 +47,14 @@ BEGIN
             VALUE "Comments", "\0"
             VALUE "CompanyName", "Internet2\0"
             VALUE "FileDescription", "Shibboleth Apache 2.2 Module\0"
-            VALUE "FileVersion", "2, 3, 0, 0\0"
+            VALUE "FileVersion", "2, 3, 1, 0\0"
             VALUE "InternalName", "mod_shib_22\0"
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "mod_shib_22.so\0"
             VALUE "PrivateBuild", "\0"
-            VALUE "ProductName", "Shibboleth 2.3\0"
-            VALUE "ProductVersion", "2, 3, 0, 0\0"
+            VALUE "ProductName", "Shibboleth 2.3.1\0"
+            VALUE "ProductVersion", "2, 3, 1, 0\0"
             VALUE "SpecialBuild", "\0"
         END
     END
index 9778d65..ec6787b 100644 (file)
 #define PACKAGE_NAME "shibboleth"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "shibboleth 2.3"
+#define PACKAGE_STRING "shibboleth 2.3.1"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "shibboleth"
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "2.3"
+#define PACKAGE_VERSION "2.3.1"
 
 /* Define to the necessary symbol if this constant uses a non-standard name on
    your system. */
 /* #undef TM_IN_SYS_TIME */
 
 /* Version number of package */
-#define VERSION "2.3"
+#define VERSION "2.3.1"
 
 /* Define to empty if `const' does not conform to ANSI C. */
 /* #undef const */
index d935c7f..8ed5938 100644 (file)
         <AttributeExtractor type="XML" validate="true" path="attribute-map.xml"/>
         
         <!-- Use a SAML query if no attributes are supplied during SSO. -->
-        <AttributeResolver type="Query"/>
+        <AttributeResolver type="Query" subjectMatch="true"/>
 
         <!-- Default filtering policy for recognized attributes, lets other data pass. -->
         <AttributeFilter type="XML" validate="true" path="attribute-policy.xml"/>
index fd80ee5..a526cbd 100644 (file)
@@ -14,7 +14,7 @@ shibd="@-PREFIX-@/sbin/shibd"
 SHIBD_USER=root
 pidfile=@-PKGRUNDIR-@/shibd.pid
 prog=shibd
-VER=`cat /etc/redhat-release | awk '{print $3}' | awk -F . '{print $1}'`
+#VER=`cat /etc/redhat-release | awk '{print $3}' | awk -F . '{print $1}'`
 RETVAL=0
 
 start() {
@@ -37,11 +37,7 @@ start() {
        if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
                /sbin/restorecon $pidfile
        fi
-       if [ 5 -le $VER ] ; then
-               daemon --user $SHIBD_USER --pidfile $pidfile $shibd -p $pidfile -f -w 30
-       else
-               daemon --user $SHIBD_USER $shibd -p $pidfile -f -w 30
-       fi
+       daemon --user $SHIBD_USER $shibd -p $pidfile -f -w 30
 
        RETVAL=$?
        echo
@@ -51,11 +47,7 @@ start() {
 
 stop() {
        echo -n $"Stopping $prog: "
-       if [ -f $pidfile -a 5 -le $VER ] ; then
-               killproc -p $pidfile shibd
-       else
-               killproc shibd
-       fi
+       killproc shibd
 
        RETVAL=$?
        echo
index 62a1619..0be3acf 100644 (file)
@@ -7,9 +7,12 @@
 #
 ### BEGIN INIT INFO
 # Provides: shibd
-# Required-Start: network
-# Required-Stop: $null
+# Required-Start: $local_fs $remote_fs $network
+# Should-Start: $time
+# Should-Stop: $time
+# Required-Stop: $local_fs $remote_fs $network
 # 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.
index 1471e1e..2f64d93 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for shibboleth 2.3.
+# Generated by GNU Autoconf 2.59 for shibboleth 2.3.1.
 #
 # Report bugs to <shibboleth-users@internet2.edu>.
 #
@@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='shibboleth'
 PACKAGE_TARNAME='shibboleth'
-PACKAGE_VERSION='2.3'
-PACKAGE_STRING='shibboleth 2.3'
+PACKAGE_VERSION='2.3.1'
+PACKAGE_STRING='shibboleth 2.3.1'
 PACKAGE_BUGREPORT='shibboleth-users@internet2.edu'
 
 # Factoring default headers for most tests.
@@ -957,7 +957,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures shibboleth 2.3 to adapt to many kinds of systems.
+\`configure' configures shibboleth 2.3.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1023,7 +1023,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of shibboleth 2.3:";;
+     short | recursive ) echo "Configuration of shibboleth 2.3.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1199,7 +1199,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-shibboleth configure 2.3
+shibboleth configure 2.3.1
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1213,7 +1213,7 @@ cat >&5 <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by shibboleth $as_me 2.3, which was
+It was created by shibboleth $as_me 2.3.1, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1858,7 +1858,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE=shibboleth
- VERSION=2.3
+ VERSION=2.3.1
 
 
 cat >>confdefs.h <<_ACEOF
@@ -27092,7 +27092,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by shibboleth $as_me 2.3, which was
+This file was extended by shibboleth $as_me 2.3.1, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -27155,7 +27155,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-shibboleth config.status 2.3
+shibboleth config.status 2.3.1
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
index 7265638..0326aba 100644 (file)
@@ -1,7 +1,7 @@
 AC_PREREQ([2.50])
-AC_INIT([shibboleth], [2.3], [shibboleth-users@internet2.edu], [shibboleth])
+AC_INIT([shibboleth], [2.3.1], [shibboleth-users@internet2.edu], [shibboleth])
 AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE([shibboleth],[2.3])
+AM_INIT_AUTOMAKE([shibboleth],[2.3.1])
 
 sinclude(doxygen.m4)
 sinclude(acx_pthread.m4)
index e21e018..3d8f7a0 100644 (file)
@@ -1,4 +1,4 @@
-Version 2.3
+Version 2.3.1
 
 Welcome to Internet2's Shibboleth
 
index 51a97cc..19132fc 100644 (file)
@@ -1,14 +1,14 @@
 Release Notes
 
 Shibboleth Native SP
-2.3
+2.3.1
 
 NOTE: The shibboleth2.xml configuration format in this release
-is fully compatible with the 2.1 release, but there are some small
+is fully compatible with the 2.1 and 2.2 releases, but there are some small
 changes required to eliminate various warnings about deprecated options.
 
 List of issues addressed by this release:
-https://bugs.internet2.edu/jira/browse/SSPCPP/fixforversion/10261
+https://bugs.internet2.edu/jira/browse/SSPCPP/fixforversion/10271
 
 Fully Supported
 
index 37258c9..e1f7b95 100644 (file)
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //\r
 \r
 VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION 2,3,0,0\r
- PRODUCTVERSION 2,3,0,0\r
+ FILEVERSION 2,3,1,0\r
+ PRODUCTVERSION 2,3,1,0\r
  FILEFLAGSMASK 0x3fL\r
 #ifdef _DEBUG\r
  FILEFLAGS 0x1L\r
@@ -47,14 +47,14 @@ BEGIN
             VALUE "Comments", "\0"\r
             VALUE "CompanyName", "Internet2\0"\r
             VALUE "FileDescription", "Shibboleth FastCGI Authorizer\0"\r
-            VALUE "FileVersion", "2, 3, 0, 0\0"\r
+            VALUE "FileVersion", "2, 3, 1, 0\0"\r
             VALUE "InternalName", "shibauthorizer\0"\r
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"\r
             VALUE "LegalTrademarks", "\0"\r
             VALUE "OriginalFilename", "shibauthorizer.exe\0"\r
             VALUE "PrivateBuild", "\0"\r
-            VALUE "ProductName", "Shibboleth 2.3\0"\r
-            VALUE "ProductVersion", "2, 3, 0, 0\0"\r
+            VALUE "ProductName", "Shibboleth 2.3.1\0"\r
+            VALUE "ProductVersion", "2, 3, 1, 0\0"\r
             VALUE "SpecialBuild", "\0"\r
         END\r
     END\r
index f95c347..c41b96c 100644 (file)
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //\r
 \r
 VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION 2,3,0,0\r
- PRODUCTVERSION 2,3,0,0\r
+ FILEVERSION 2,3,1,0\r
+ PRODUCTVERSION 2,3,1,0\r
  FILEFLAGSMASK 0x3fL\r
 #ifdef _DEBUG\r
  FILEFLAGS 0x1L\r
@@ -47,14 +47,14 @@ BEGIN
             VALUE "Comments", "\0"\r
             VALUE "CompanyName", "Internet2\0"\r
             VALUE "FileDescription", "Shibboleth FastCGI Responder\0"\r
-            VALUE "FileVersion", "2, 3, 0, 0\0"\r
+            VALUE "FileVersion", "2, 3, 1, 0\0"\r
             VALUE "InternalName", "shibresponder\0"\r
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"\r
             VALUE "LegalTrademarks", "\0"\r
             VALUE "OriginalFilename", "shibresponder.exe\0"\r
             VALUE "PrivateBuild", "\0"\r
-            VALUE "ProductName", "Shibboleth 2.3\0"\r
-            VALUE "ProductVersion", "2, 3, 0, 0\0"\r
+            VALUE "ProductName", "Shibboleth 2.3.1\0"\r
+            VALUE "ProductVersion", "2, 3, 1, 0\0"\r
             VALUE "SpecialBuild", "\0"\r
         END\r
     END\r
index 116438f..63c0d2f 100644 (file)
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,3,0,0
- PRODUCTVERSION 2,3,0,0
+ FILEVERSION 2,3,1,0
+ PRODUCTVERSION 2,3,1,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -47,14 +47,14 @@ BEGIN
             VALUE "Comments", "\0"
             VALUE "CompanyName", "Internet2\0"
             VALUE "FileDescription", "Shibboleth ISAPI Filter / Extension\0"
-            VALUE "FileVersion", "2, 3, 0, 0\0"
+            VALUE "FileVersion", "2, 3, 1, 0\0"
             VALUE "InternalName", "isapi_shib\0"
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "isapi_shib.dll\0"
             VALUE "PrivateBuild", "\0"
-            VALUE "ProductName", "Shibboleth 2.3\0"
-            VALUE "ProductVersion", "2, 3, 0, 0\0"
+            VALUE "ProductName", "Shibboleth 2.3.1\0"
+            VALUE "ProductVersion", "2, 3, 1, 0\0"
             VALUE "SpecialBuild", "\0"
         END
     END
index 5edb5b1..fb78af6 100644 (file)
@@ -53,8 +53,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,3,0,0
- PRODUCTVERSION 2,3,0,0
+ FILEVERSION 2,3,1,0
+ PRODUCTVERSION 2,3,1,0
  FILEFLAGSMASK 0x17L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -71,12 +71,12 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "Internet2\0"
             VALUE "FileDescription", "Shibboleth Memcache Storage Service Plugin\0"
-            VALUE "FileVersion", "2, 3, 0, 0\0"
+            VALUE "FileVersion", "2, 3, 1, 0\0"
             VALUE "InternalName", "memcache-store\0"
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"
             VALUE "OriginalFilename", "memcache-store.so\0"
-            VALUE "ProductName", "Shibboleth 2.3\0"
-            VALUE "ProductVersion", "2, 3, 0, 0\0"
+            VALUE "ProductName", "Shibboleth 2.3.1\0"
+            VALUE "ProductVersion", "2, 3, 1, 0\0"
         END
     END
     BLOCK "VarFileInfo"
index a551403..c4004f5 100644 (file)
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,3,0,0
- PRODUCTVERSION 2,3,0,0
+ FILEVERSION 2,3,1,0
+ PRODUCTVERSION 2,3,1,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -47,14 +47,14 @@ BEGIN
             VALUE "Comments", "\0"
             VALUE "CompanyName", "Internet2\0"
             VALUE "FileDescription", "Shibboleth NSAPI Extension\0"
-            VALUE "FileVersion", "2, 3, 0, 0\0"
+            VALUE "FileVersion", "2, 3, 1, 0\0"
             VALUE "InternalName", "nsapi_shib\0"
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "nsapi_shib.dll\0"
             VALUE "PrivateBuild", "\0"
-            VALUE "ProductName", "Shibboleth 2.3\0"
-            VALUE "ProductVersion", "2, 3, 0, 0\0"
+            VALUE "ProductName", "Shibboleth 2.3.1\0"
+            VALUE "ProductVersion", "2, 3, 1, 0\0"
             VALUE "SpecialBuild", "\0"
         END
     END
index 0190222..bfcbae5 100644 (file)
@@ -53,8 +53,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,3,0,0
- PRODUCTVERSION 2,3,0,0
+ FILEVERSION 2,3,1,0
+ PRODUCTVERSION 2,3,1,0
  FILEFLAGSMASK 0x17L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -71,12 +71,12 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "Internet2\0"
             VALUE "FileDescription", "Shibboleth ODBC Storage Service Plugin\0"
-            VALUE "FileVersion", "2, 3, 0, 0\0"
+            VALUE "FileVersion", "2, 3, 1, 0\0"
             VALUE "InternalName", "odbc-store\0"
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"
             VALUE "OriginalFilename", "odbc-store.so\0"
-            VALUE "ProductName", "Shibboleth 2.3\0"
-            VALUE "ProductVersion", "2, 3, 0, 0\0"
+            VALUE "ProductName", "Shibboleth 2.3.1\0"
+            VALUE "ProductVersion", "2, 3, 1, 0\0"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/pkginfo b/pkginfo
index 6184208..8511d13 100644 (file)
--- a/pkginfo
+++ b/pkginfo
@@ -1,5 +1,5 @@
 PKG=SHIBsp
-VERSION=2.3
+VERSION=2.3.1
 BASEDIR=/
 NAME=shibboleth-sp
 CATEGORY=application,security
index 411b037..7b54585 100644 (file)
-<?xml version="1.0" encoding="US-ASCII"?>\r
-<schema targetNamespace="urn:mace:shibboleth:2.0:native:sp:config"\r
-       xmlns="http://www.w3.org/2001/XMLSchema"\r
-       xmlns:conf="urn:mace:shibboleth:2.0:native:sp:config"\r
-       xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"\r
-       xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"\r
-       xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"\r
-       elementFormDefault="qualified"\r
-       attributeFormDefault="unqualified"\r
-       blockDefault="substitution"\r
-       version="2.3">\r
-\r
-       <import namespace="urn:oasis:names:tc:SAML:2.0:assertion" schemaLocation="saml-schema-assertion-2.0.xsd"/>\r
-       <import namespace="urn:oasis:names:tc:SAML:2.0:protocol" schemaLocation="saml-schema-protocol-2.0.xsd"/>\r
-       <import namespace="urn:oasis:names:tc:SAML:2.0:metadata" schemaLocation="saml-schema-metadata-2.0.xsd"/>\r
-\r
-       <annotation>\r
-               <documentation>\r
-               2.0 schema for XML-based configuration of Shibboleth Native SP instances.\r
-               First appearing in Shibboleth 2.0 release.\r
-               </documentation>\r
-       </annotation>\r
-\r
-       <simpleType name="string">\r
-               <restriction base="string">\r
-                       <minLength value="1"/>\r
-               </restriction>\r
-       </simpleType>\r
-\r
-       <simpleType name="listOfStrings">\r
-               <list itemType="conf:string"/>\r
-       </simpleType>\r
-\r
-       <simpleType name="listOfURIs">\r
-               <list itemType="anyURI"/>\r
-       </simpleType>\r
-\r
-       <simpleType name="bindingBoolean">\r
-               <restriction base="string">\r
-                       <enumeration value="true"/>\r
-                       <enumeration value="false"/>\r
-                       <enumeration value="front"/>\r
-                       <enumeration value="back"/>\r
-               </restriction>\r
-       </simpleType>\r
-       \r
-       <complexType name="PluggableType">\r
-               <sequence>\r
-                       <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>\r
-               </sequence>\r
-               <attribute name="type" type="conf:string" use="required"/>\r
-               <anyAttribute namespace="##any" processContents="skip"/>\r
-       </complexType>\r
-\r
-       <element name="SPConfig">\r
-               <complexType>\r
-                       <annotation>\r
-                               <documentation>Root of configuration</documentation>\r
-                       </annotation>\r
-                       <sequence>\r
-                               <element ref="conf:Extensions" minOccurs="0"/>\r
-                               <element ref="conf:OutOfProcess"/>\r
-                               <element ref="conf:InProcess"/>\r
-                <choice minOccurs="0">\r
-                    <element name="UnixListener">\r
-                        <complexType>\r
-                            <attribute name="address" type="conf:string" use="required"/>\r
-                        </complexType>\r
-                    </element>\r
-                    <element name="TCPListener">\r
-                        <complexType>\r
-                            <attribute name="address" type="conf:string" use="required"/>\r
-                            <attribute name="port" type="unsignedInt" use="required"/>\r
-                            <attribute name="acl" type="conf:listOfStrings"/>\r
-                        </complexType>\r
-                    </element>\r
-                    <element name="Listener" type="conf:PluggableType"/>\r
-                </choice>\r
-                <element ref="conf:StorageService" minOccurs="0" maxOccurs="unbounded"/>\r
-                <element ref="conf:SessionCache" minOccurs="0"/>\r
-                <element ref="conf:ReplayCache" minOccurs="0"/>\r
-                <element ref="conf:ArtifactMap" minOccurs="0"/>\r
-                <element name="RequestMapper" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element ref="conf:ApplicationDefaults"/>\r
-                               <element ref="conf:SecurityPolicies"/>\r
-                <element ref="conf:TransportOption" minOccurs="0" maxOccurs="unbounded"/>\r
-                       </sequence>\r
-                       <attribute name="logger" type="anyURI"/>\r
-                       <attribute name="clockSkew" type="unsignedInt"/>\r
-            <attribute name="unsafeChars" type="conf:string"/>\r
-            <attribute name="allowedSchemes" type="conf:listOfStrings"/>\r
-                       <anyAttribute namespace="##other" processContents="lax"/>\r
-               </complexType>\r
-       </element>\r
-\r
-       <element name="Extensions">\r
-               <annotation>\r
-                       <documentation>Container for extension libraries and custom configuration</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence>\r
-                               <element name="Library" minOccurs="0" maxOccurs="unbounded">\r
-                                       <complexType>\r
-                                               <sequence>\r
-                                                       <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>\r
-                                               </sequence>\r
-                                               <attribute name="path" type="anyURI" use="required"/>\r
-                                               <attribute name="fatal" type="boolean"/>\r
-                                               <anyAttribute namespace="##any" processContents="skip"/>\r
-                                       </complexType>\r
-                               </element>\r
-                               <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
-                       </sequence>\r
-               </complexType>\r
-       </element>\r
-\r
-       <element name="StorageService">\r
-               <annotation>\r
-                       <documentation>References StorageService plugins</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <complexContent>\r
-                               <restriction base="conf:PluggableType">\r
-                                       <sequence>\r
-                                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>\r
-                                       </sequence>\r
-                                       <attribute name="id" type="ID" use="required"/>\r
-                                       <attribute name="cleanupInterval" type="unsignedInt"/>\r
-                                       <anyAttribute namespace="##any" processContents="skip"/>\r
-                               </restriction>\r
-                       </complexContent>\r
-               </complexType>\r
-       </element>\r
-\r
-       <element name="SessionCache">\r
-               <annotation>\r
-                       <documentation>References SessionCache plugins</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <complexContent>\r
-                               <restriction base="conf:PluggableType">\r
-                                       <sequence>\r
-                                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>\r
-                                       </sequence>\r
-                                       <attribute name="StorageService" type="IDREF"/>\r
-                                       <attribute name="cacheTimeout" type="unsignedInt"/>\r
-                                       <anyAttribute namespace="##any" processContents="skip"/>\r
-                               </restriction>\r
-                       </complexContent>\r
-               </complexType>\r
-       </element>\r
-       \r
-       <element name="ReplayCache">\r
-               <annotation>\r
-                       <documentation>Ties ReplayCache to a custom StorageService</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence/>\r
-                       <attribute name="StorageService" type="IDREF" use="required"/>\r
-               </complexType>\r
-       </element>\r
-       \r
-       <element name="ArtifactMap">\r
-               <annotation>\r
-                       <documentation>Customizes an ArtifactMap</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence/>\r
-                       <attribute name="StorageService" type="IDREF"/>\r
-                       <attribute name="context" type="conf:string"/>\r
-                       <attribute name="artifactTTL" type="unsignedInt"/>\r
-               </complexType>\r
-       </element>\r
-       \r
-       <element name="OutOfProcess">\r
-               <annotation>\r
-                       <documentation>Container for out-of-process (shibd) configuration</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence>\r
-                               <element ref="conf:Extensions" minOccurs="0"/>\r
-                               <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
-                       </sequence>\r
-                       <attribute name="logger" type="anyURI"/>\r
-                   <attribute name="catchAll" type="boolean"/>\r
-                       <anyAttribute namespace="##other" processContents="lax"/>\r
-               </complexType>\r
-       </element>\r
-\r
-       <element name="InProcess">\r
-               <annotation>\r
-                       <documentation>\r
-                       Container for configuration of locally integrated or platform-specific\r
-                       features (e.g. web server filters)\r
-                       </documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence>\r
-                               <element ref="conf:Extensions" minOccurs="0"/>\r
-                               <element ref="conf:ISAPI" minOccurs="0"/>\r
-                               <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
-                       </sequence>\r
-                       <attribute name="logger" type="anyURI"/>\r
-                       <attribute name="unsetHeaderValue" type="conf:string"/>\r
-                       <attribute name="checkSpoofing" type="boolean"/>\r
-                       <attribute name="spoofKey" type="conf:string"/>\r
-                       <attribute name="catchAll" type="boolean"/>\r
-                       <anyAttribute namespace="##other" processContents="lax"/>\r
-               </complexType>\r
-       </element>\r
-       \r
-       <element name="ISAPI">\r
-               <complexType>\r
-                       <sequence>\r
-                               <element name="Site" maxOccurs="unbounded">\r
-                                       <complexType>\r
-                                               <sequence>\r
-                                                       <element name="Alias" type="string" minOccurs="0" maxOccurs="unbounded"/>\r
-                                               </sequence>\r
-                                               <attribute name="id" type="unsignedInt" use="required"/>\r
-                                               <attribute name="name" type="conf:string" use="required"/>\r
-                                               <attribute name="port" type="unsignedInt"/>\r
-                                               <attribute name="sslport" type="unsignedInt"/>\r
-                                               <attribute name="scheme" type="conf:string"/>\r
-                                       </complexType>\r
-                               </element>\r
-                               <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
-                       </sequence>\r
-                       <attribute name="normalizeRequest" type="boolean"/>\r
-                       <attribute name="safeHeaderNames" type="boolean"/>\r
-                       <anyAttribute namespace="##other" processContents="lax"/>\r
-               </complexType>\r
-       </element>\r
-\r
-       <element name="AccessControl" type="conf:UniOperatorType">\r
-               <annotation>\r
-                       <documentation>\r
-                       A simple example access policy language extension that supersedes Apache .htaccess\r
-                       </documentation>\r
-               </annotation>\r
-       </element>\r
-       <element name="OR" type="conf:MultiOperatorType"/>\r
-       <element name="AND" type="conf:MultiOperatorType"/>\r
-       <element name="NOT" type="conf:UniOperatorType"/>\r
-       <complexType name="UniOperatorType">\r
-               <choice>\r
-                       <element ref="conf:AND"/>\r
-                       <element ref="conf:OR"/>\r
-                       <element ref="conf:NOT"/>\r
-                       <element ref="conf:Rule"/>\r
-                   <element ref="conf:RuleRegex"/>\r
-               </choice>\r
-       </complexType>\r
-       <complexType name="MultiOperatorType">\r
-               <choice minOccurs="2" maxOccurs="unbounded">\r
-                       <element ref="conf:AND"/>\r
-                       <element ref="conf:OR"/>\r
-                       <element ref="conf:NOT"/>\r
-                       <element ref="conf:Rule"/>\r
-                   <element ref="conf:RuleRegex"/>\r
-               </choice>\r
-       </complexType>\r
-       <element name="Rule">\r
-               <complexType>\r
-                       <simpleContent>\r
-                               <extension base="conf:listOfStrings">\r
-                                       <attribute name="require" type="conf:string" use="required"/>\r
-                                   <attribute name="list" type="boolean"/>\r
-                               </extension>\r
-                       </simpleContent>\r
-               </complexType>\r
-       </element>\r
-    <element name="RuleRegex">\r
-        <complexType>\r
-            <simpleContent>\r
-                <extension base="conf:string">\r
-                    <attribute name="require" type="conf:string" use="required"/>\r
-                    <attribute name="ignoreCase" type="boolean"/>\r
-                </extension>\r
-            </simpleContent>\r
-        </complexType>\r
-    </element>\r
-       \r
-       <attributeGroup name="ContentSettings">\r
-               <attribute name="authType" type="conf:string"/>\r
-               <attribute name="requireSession" type="boolean"/>\r
-               <attribute name="requireSessionWith" type="conf:string"/>\r
-               <attribute name="exportAssertion" type="boolean"/>\r
-               <attribute name="redirectToSSL" type="unsignedInt"/>\r
-               <attribute name="entityID" type="anyURI"/>\r
-        <attribute name="discoveryURL" type="anyURI"/>\r
-               <attribute name="isPassive" type="boolean"/>\r
-               <attribute name="forceAuthn" type="boolean"/>\r
-               <attribute name="authnContextClassRef" type="anyURI"/>\r
-               <attribute name="authnContextComparison" type="samlp:AuthnContextComparisonType"/>\r
-        <attribute name="NameIDFormat" type="anyURI"/>\r
-        <attribute name="SPNameQualifier" type="conf:string"/>\r
-        <attribute name="redirectErrors" type="anyURI"/>\r
-               <attribute name="sessionError" type="anyURI"/>\r
-               <attribute name="metadataError" type="anyURI"/>\r
-               <attribute name="accessError" type="anyURI"/>\r
-               <attribute name="sslError" type="anyURI"/>\r
-        <attribute name="REMOTE_ADDR" type="conf:string"/>\r
-               <anyAttribute namespace="##other" processContents="lax"/>\r
-       </attributeGroup>\r
-       <element name="AccessControlProvider" type="conf:PluggableType"/>\r
-       <element name="htaccess" type="conf:PluggableType"/>\r
-\r
-    <element name="RequestMap">\r
-               <annotation>\r
-                       <documentation>\r
-                       Built-in request mapping syntax, decomposes URLs into Host/Path/Path/...\r
-                       </documentation>\r
-               </annotation>\r
-        <complexType>\r
-            <sequence>\r
-               <choice minOccurs="0">\r
-                       <element ref="conf:htaccess"/>\r
-                                       <element ref="conf:AccessControl"/>\r
-                       <element ref="conf:AccessControlProvider"/>\r
-                   </choice>\r
-               <choice minOccurs="0" maxOccurs="unbounded">\r
-                                       <element ref="conf:Host"/>\r
-                       <element ref="conf:HostRegex"/>\r
-               </choice>\r
-            </sequence>\r
-            <attribute name="applicationId" type="conf:string" fixed="default"/>\r
-               <attributeGroup ref="conf:ContentSettings"/>\r
-        </complexType>\r
-    </element>\r
-\r
-    <element name="Host">\r
-       <complexType>\r
-               <sequence>\r
-               <choice minOccurs="0">\r
-                       <element ref="conf:htaccess"/>\r
-                                       <element ref="conf:AccessControl"/>\r
-                       <element ref="conf:AccessControlProvider"/>\r
-                   </choice>\r
-                       <choice minOccurs="0" maxOccurs="unbounded">\r
-                               <element ref="conf:Path"/>\r
-                               <element ref="conf:PathRegex"/>\r
-                               <element ref="conf:Query"/>\r
-                       </choice>\r
-               </sequence>\r
-               <attribute name="scheme">\r
-                           <simpleType>\r
-                               <restriction base="conf:string">\r
-                                   <enumeration value="http"/>\r
-                                   <enumeration value="https"/>\r
-                                   <enumeration value="ftp"/>\r
-                                   <enumeration value="ldap"/>\r
-                                   <enumeration value="ldaps"/>\r
-                               </restriction>\r
-                           </simpleType>\r
-               </attribute>\r
-               <attribute name="name" type="conf:string" use="required"/>\r
-               <attribute name="port" type="unsignedInt"/>\r
-                       <attribute name="applicationId" type="conf:string"/>\r
-               <attributeGroup ref="conf:ContentSettings"/>\r
-       </complexType>\r
-    </element>\r
-       \r
-       <element name="HostRegex">\r
-               <complexType>\r
-                       <sequence>\r
-                               <choice minOccurs="0">\r
-                                       <element ref="conf:htaccess"/>\r
-                                       <element ref="conf:AccessControl"/>\r
-                                       <element ref="conf:AccessControlProvider"/>\r
-                               </choice>\r
-                               <choice minOccurs="0" maxOccurs="unbounded">\r
-                                       <element ref="conf:Path"/>\r
-                                       <element ref="conf:PathRegex"/>\r
-                                       <element ref="conf:Query"/>\r
-                               </choice>\r
-                       </sequence>\r
-                       <attribute name="regex" type="conf:string" use="required"/>\r
-                       <attribute name="ignoreCase" type="boolean"/>\r
-                       <attribute name="applicationId" type="conf:string"/>\r
-                       <attributeGroup ref="conf:ContentSettings"/>\r
-               </complexType>\r
-       </element>\r
-\r
-    <element name="Path">\r
-        <complexType>\r
-               <sequence>\r
-               <choice minOccurs="0">\r
-                       <element ref="conf:htaccess"/>\r
-                                       <element ref="conf:AccessControl"/>\r
-                       <element ref="conf:AccessControlProvider"/>\r
-                   </choice>\r
-                       <choice minOccurs="0" maxOccurs="unbounded">\r
-                               <element ref="conf:Path"/>\r
-                               <element ref="conf:PathRegex"/>\r
-                               <element ref="conf:Query"/>\r
-                       </choice>\r
-               </sequence>\r
-                       <attribute name="name" type="conf:string" use="required"/>\r
-                       <attribute name="applicationId" type="conf:string"/>\r
-                       <attributeGroup ref="conf:ContentSettings"/>\r
-        </complexType>\r
-    </element>\r
-\r
-       <element name="PathRegex">\r
-               <complexType>\r
-                       <sequence>\r
-                               <choice minOccurs="0">\r
-                                       <element ref="conf:htaccess"/>\r
-                                       <element ref="conf:AccessControl"/>\r
-                                       <element ref="conf:AccessControlProvider"/>\r
-                               </choice>\r
-                               <element ref="conf:Query" minOccurs="0" maxOccurs="unbounded"/>\r
-                       </sequence>\r
-                       <attribute name="regex" type="conf:string" use="required"/>\r
-                       <attribute name="ignoreCase" type="boolean"/>\r
-                       <attribute name="applicationId" type="conf:string"/>\r
-                       <attributeGroup ref="conf:ContentSettings"/>\r
-               </complexType>\r
-       </element>\r
-       \r
-       <element name="Query">\r
-               <complexType>\r
-                       <sequence>\r
-                               <choice minOccurs="0">\r
-                                       <element ref="conf:htaccess"/>\r
-                                       <element ref="conf:AccessControl"/>\r
-                                       <element ref="conf:AccessControlProvider"/>\r
-                               </choice>\r
-                               <element ref="conf:Query" minOccurs="0" maxOccurs="unbounded"/>\r
-                       </sequence>\r
-                       <attribute name="name" type="conf:string" use="required"/>\r
-                       <attribute name="regex" type="conf:string"/>\r
-                       <attributeGroup ref="conf:ContentSettings"/>\r
-               </complexType>\r
-       </element>\r
-       \r
-       <element name="ApplicationDefaults">\r
-               <annotation>\r
-                       <documentation>Container for default settings and application-specific overrides</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence>\r
-                               <element ref="conf:Sessions"/>\r
-                               <element ref="conf:Errors" minOccurs="0"/>\r
-                               <element ref="conf:RelyingParty" minOccurs="0" maxOccurs="unbounded"/>\r
-                               <element ref="conf:Notify" minOccurs="0" maxOccurs="unbounded"/>\r
-                               <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>\r
-                <element name="MetadataProvider" type="conf:PluggableType"/>\r
-                               <element name="TrustEngine" type="conf:PluggableType"/>\r
-                               <element name="AttributeExtractor" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element name="AttributeFilter" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element ref="conf:ApplicationOverride" minOccurs="0" maxOccurs="unbounded"/>\r
-                       </sequence>\r
-                       <attribute name="id" type="conf:string" fixed="default"/>\r
-                       <attribute name="entityID" type="anyURI" use="required"/>\r
-                       <attribute name="policyId" type="conf:string" use="required"/>\r
-                       <attributeGroup ref="conf:ApplicationGroup"/>\r
-                   <attributeGroup ref="conf:RelyingPartyGroup"/>\r
-                       <anyAttribute namespace="##other" processContents="lax"/>\r
-               </complexType>\r
-       </element>\r
-       \r
-       <element name="ApplicationOverride">\r
-               <annotation>\r
-                       <documentation>Container for application-specific overrides</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence>\r
-                               <element ref="conf:Sessions" minOccurs="0"/>\r
-                               <element ref="conf:Errors" minOccurs="0"/>\r
-                               <element ref="conf:RelyingParty" minOccurs="0" maxOccurs="unbounded"/>\r
-                               <element ref="conf:Notify" minOccurs="0" maxOccurs="unbounded"/>\r
-                               <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>\r
-                               <element name="MetadataProvider" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element name="TrustEngine" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element name="AttributeExtractor" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element name="AttributeFilter" type="conf:PluggableType" minOccurs="0"/>\r
-                               <element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>\r
-                       </sequence>\r
-                       <attribute name="id" type="conf:string" use="required"/>\r
-                       <attribute name="entityID" type="anyURI"/>\r
-                       <attribute name="policyId" type="conf:string"/>\r
-                       <attributeGroup ref="conf:ApplicationGroup"/>\r
-                   <attributeGroup ref="conf:RelyingPartyGroup"/>\r
-                       <anyAttribute namespace="##other" processContents="lax"/>\r
-               </complexType>\r
-       </element>\r
-\r
-       <attributeGroup name="ApplicationGroup">\r
-               <attribute name="homeURL" type="anyURI"/>\r
-               <attribute name="REMOTE_USER" type="conf:listOfStrings"/>\r
-               <attribute name="unsetHeaders" type="conf:listOfStrings"/>\r
-               <attribute name="metadataAttributePrefix" type="conf:string"/>\r
-           <attribute name="attributePrefix" type="conf:string"/>\r
-       </attributeGroup>\r
-\r
-    <attributeGroup name="RelyingPartyGroup">\r
-        <attribute name="authType" type="conf:string"/>\r
-        <attribute name="authUsername" type="conf:string"/>\r
-        <attribute name="authPassword" type="conf:string"/>\r
-        <attribute name="signing" type="conf:bindingBoolean"/>\r
-        <attribute name="signingAlg" type="anyURI"/>\r
-        <attribute name="digestAlg" type="anyURI"/>\r
-        <attribute name="encryption" type="conf:bindingBoolean"/>\r
-        <attribute name="encryptionAlg" type="anyURI"/>\r
-        <attribute name="keyName" type="conf:string"/>\r
-        <attribute name="artifactEndpointIndex" type="unsignedShort"/>\r
-        <attribute name="chunkedEncoding" type="boolean"/>\r
-        <attribute name="connectTimeout" type="unsignedShort"/>\r
-        <attribute name="timeout" type="unsignedShort"/>\r
-        <attribute name="requireConfidentiality" type="boolean"/>\r
-        <attribute name="requireTransportAuth" type="boolean"/>\r
-        <attribute name="requireSignedAssertions" type="boolean"/>\r
-    </attributeGroup>\r
-    \r
-       <element name="Sessions">\r
-               <annotation>\r
-                       <documentation>Container for specifying protocol handlers and session policy</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <choice minOccurs="0" maxOccurs="unbounded">\r
-                               <element ref="conf:SessionInitiator"/>\r
-                               <element ref="conf:LogoutInitiator"/>\r
-                               <element ref="md:AssertionConsumerService"/>\r
-                               <element ref="md:ArtifactResolutionService"/>\r
-                               <element ref="md:SingleLogoutService"/>\r
-                               <element ref="md:ManageNameIDService"/>\r
-                               <element name="Handler">\r
-                                       <complexType>\r
-                                               <complexContent>\r
-                                                       <restriction base="conf:PluggableType">\r
-                                                               <sequence>\r
-                                                                       <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>\r
-                                                               </sequence>\r
-                                                               <attribute name="Location" type="anyURI" use="required"/>\r
-                                                           <attribute name="acl" type="conf:listOfStrings"/>\r
-                                                               <anyAttribute namespace="##any" processContents="skip"/>\r
-                                                       </restriction>\r
-                                               </complexContent>\r
-                                       </complexType>\r
-                               </element>\r
-                       </choice>\r
-                       <attribute name="handlerURL" type="anyURI" use="required"/>\r
-                       <attribute name="handlerSSL" type="boolean"/>\r
-                       <attribute name="exportLocation" type="conf:string"/>\r
-                       <attribute name="exportACL" type="conf:listOfStrings"/>\r
-                       <attribute name="cookieName" type="conf:string"/>\r
-                       <attribute name="cookieProps" type="conf:string"/>\r
-            <attribute name="cookieLifetime" type="unsignedInt"/>\r
-                       <attribute name="idpHistory" type="boolean"/>\r
-                       <attribute name="idpHistoryDays" type="unsignedInt"/>\r
-                       <attribute name="lifetime" type="unsignedInt"/>\r
-                       <attribute name="timeout" type="unsignedInt"/>\r
-                   <attribute name="maxTimeSinceAuthn" type="unsignedInt"/>\r
-                       <attribute name="checkAddress" type="boolean"/>\r
-                       <attribute name="consistentAddress" type="boolean"/>\r
-                       <attribute name="postData" type="conf:string"/>\r
-            <attribute name="postLimit" type="positiveInteger"/>\r
-                       <attribute name="postTemplate" type="conf:string"/>\r
-            <attribute name="postExpire" type="boolean"/>\r
-                       <anyAttribute namespace="##other" processContents="lax"/>\r
-               </complexType>\r
-       </element>\r
-\r
-       <attribute name="policyId" type="conf:string">\r
-               <annotation>\r
-                       <documentation>Used to reference Policy elements from profile endpoints.</documentation>\r
-               </annotation>\r
-       </attribute>\r
-\r
-       <element name="SessionInitiator">\r
-               <annotation>\r
-                       <documentation>Used to specify handlers that can issue AuthnRequests or perform discovery</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <complexContent>\r
-                               <restriction base="conf:PluggableType">\r
-                                       <sequence>\r
-                                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>\r
-                                       </sequence>\r
-                                       <attribute name="Location" type="anyURI"/>\r
-                                       <attribute name="id" type="conf:string"/>\r
-                                       <attribute name="isDefault" type="boolean"/>\r
-                                       <attribute name="relayState" type="conf:string"/>\r
-                                       <attribute name="entityIDParam" type="conf:string"/>\r
-                                       <attribute name="entityID" type="anyURI"/>\r
-                                       <attribute name="URL" type="anyURI"/>\r
-                                       <attribute name="outgoingBindings" type="conf:listOfURIs"/>\r
-                                       <attribute name="template" type="anyURI"/>\r
-                                       <attribute name="postArtifact" type="boolean"/>\r
-                                       <attribute name="acsByIndex" type="boolean"/>\r
-                    <attribute name="acsIndex" type="unsignedShort"/>\r
-                                       <attribute name="defaultACSIndex" type="unsignedShort"/>   <!-- deprecated -->\r
-                    <attribute name="isPassive" type="boolean"/>\r
-                    <attribute name="forceAuthn" type="boolean"/>\r
-                    <attribute name="authnContextClassRef" type="anyURI"/>\r
-                    <attribute name="authnContextComparison" type="samlp:AuthnContextComparisonType"/>\r
-                    <attribute name="NameIDFormat" type="anyURI"/>\r
-                    <attribute name="SPNameQualifier" type="conf:string"/>\r
-                    <attribute name="requestDelegation" type="boolean"/>\r
-                                       <anyAttribute namespace="##any" processContents="skip"/>\r
-                               </restriction>\r
-                       </complexContent>\r
-               </complexType>\r
-       </element>\r
-\r
-       <element name="LogoutInitiator">\r
-               <annotation>\r
-                       <documentation>Used to specify handlers that can issue LogoutRequests</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <complexContent>\r
-                               <restriction base="conf:PluggableType">\r
-                                       <sequence>\r
-                                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>\r
-                                       </sequence>\r
-                                       <attribute name="Location" type="anyURI"/>\r
-                                   <attribute name="relayState" type="conf:string"/>\r
-                                       <attribute name="outgoingBindings" type="conf:listOfURIs"/>\r
-                                       <attribute name="template" type="anyURI"/>\r
-                                       <attribute name="postArtifact" type="boolean"/>\r
-                                       <anyAttribute namespace="##any" processContents="skip"/>\r
-                               </restriction>\r
-                       </complexContent>\r
-               </complexType>\r
-       </element>\r
-       \r
-       <element name="Errors">\r
-               <annotation>\r
-                       <documentation>Container for error templates and associated details</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence>\r
-                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>\r
-                       </sequence>\r
-            <attribute name="redirectErrors" type="anyURI"/>\r
-                       <attribute name="session" type="anyURI"/>\r
-                       <attribute name="metadata" type="anyURI"/>\r
-                       <attribute name="access" type="anyURI"/>\r
-                       <attribute name="ssl" type="anyURI"/>\r
-            <attribute name="localLogout" type="anyURI"/>\r
-            <attribute name="globalLogout" type="anyURI"/>\r
-            <attribute name="partialLogout" type="anyURI"/>\r
-                       <attribute name="supportContact" type="conf:string"/>\r
-                       <attribute name="logoLocation" type="anyURI"/>\r
-                       <attribute name="styleSheet" type="anyURI"/>\r
-                       <anyAttribute namespace="##any" processContents="skip"/>\r
-               </complexType>\r
-       </element>\r
-\r
-    <element name="RelyingParty">\r
-        <annotation>\r
-            <documentation>Container for specifying settings to use with particular peers</documentation>\r
-        </annotation>\r
-        <complexType>\r
-            <sequence/>\r
-            <attribute name="Name" type="conf:string" use="required"/>\r
-            <attributeGroup ref="conf:RelyingPartyGroup"/>\r
-            <attribute name="entityID" type="anyURI"/>\r
-            <anyAttribute namespace="##other" processContents="lax"/>\r
-        </complexType>\r
-    </element>\r
-    \r
-       <element name="Notify">\r
-               <annotation>\r
-                       <documentation>Used to specify locations to receive application notifications</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence/>\r
-                       <attribute name="Channel" use="required">\r
-                               <simpleType>\r
-                                       <restriction base="string">\r
-                                               <enumeration value="front"/>\r
-                                               <enumeration value="back"/>\r
-                                       </restriction>\r
-                               </simpleType>\r
-                       </attribute>\r
-                       <attribute name="Location" type="anyURI" use="required"/>\r
-                       <anyAttribute namespace="##any" processContents="skip"/>\r
-               </complexType>\r
-       </element>\r
-       \r
-       <element name="SecurityPolicies">\r
-               <annotation>\r
-                       <documentation>Container for specifying sets of policy rules to apply to incoming messages</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <sequence>\r
-                               <element name="Policy" minOccurs="1" maxOccurs="unbounded">\r
-                                       <annotation>\r
-                                               <documentation>Specifies a set of SecurityPolicyRule plugins</documentation>\r
-                                       </annotation>\r
-                                       <complexType>\r
-                                               <choice>\r
-                                                       <element name="Rule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>\r
-                            <element name="PolicyRule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>\r
-                                               </choice>\r
-                                               <attribute name="id" type="conf:string" use="required"/>\r
-                                               <attribute name="validate" type="boolean"/>\r
-                                               <anyAttribute namespace="##any" processContents="skip"/>\r
-                                       </complexType>\r
-                               </element>\r
-                       </sequence>\r
-               </complexType>\r
-       </element>\r
-\r
-       <element name="TransportOption">\r
-               <annotation>\r
-                       <documentation>Implementation-specific option to pass to SOAPTransport provider.</documentation>\r
-               </annotation>\r
-               <complexType>\r
-                       <simpleContent>\r
-                               <extension base="anySimpleType">\r
-                                       <attribute name="provider" type="conf:string" use="required"/>\r
-                                       <attribute name="option" type="conf:string" use="required"/>\r
-                               </extension>\r
-                       </simpleContent>\r
-               </complexType>\r
-       </element>\r
-       \r
-</schema>\r
+<?xml version="1.0" encoding="US-ASCII"?>
+<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: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"
+       elementFormDefault="qualified"
+       attributeFormDefault="unqualified"
+       blockDefault="substitution"
+       version="2.3">
+
+       <import namespace="urn:oasis:names:tc:SAML:2.0:assertion" schemaLocation="saml-schema-assertion-2.0.xsd"/>
+       <import namespace="urn:oasis:names:tc:SAML:2.0:protocol" schemaLocation="saml-schema-protocol-2.0.xsd"/>
+       <import namespace="urn:oasis:names:tc:SAML:2.0:metadata" schemaLocation="saml-schema-metadata-2.0.xsd"/>
+
+       <annotation>
+               <documentation>
+               2.0 schema for XML-based configuration of Shibboleth Native SP instances.
+               First appearing in Shibboleth 2.0 release.
+               </documentation>
+       </annotation>
+
+       <simpleType name="string">
+               <restriction base="string">
+                       <minLength value="1"/>
+               </restriction>
+       </simpleType>
+
+       <simpleType name="listOfStrings">
+               <list itemType="conf:string"/>
+       </simpleType>
+
+       <simpleType name="listOfURIs">
+               <list itemType="anyURI"/>
+       </simpleType>
+
+       <simpleType name="bindingBoolean">
+               <restriction base="string">
+                       <enumeration value="true"/>
+                       <enumeration value="false"/>
+                       <enumeration value="front"/>
+                       <enumeration value="back"/>
+               </restriction>
+       </simpleType>
+       
+       <complexType name="PluggableType">
+               <sequence>
+                       <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+               </sequence>
+               <attribute name="type" type="conf:string" use="required"/>
+               <anyAttribute namespace="##any" processContents="skip"/>
+       </complexType>
+
+       <element name="SPConfig">
+               <complexType>
+                       <annotation>
+                               <documentation>Root of configuration</documentation>
+                       </annotation>
+                       <sequence>
+                               <element ref="conf:Extensions" minOccurs="0"/>
+                               <element ref="conf:OutOfProcess"/>
+                               <element ref="conf:InProcess"/>
+                <choice minOccurs="0">
+                    <element name="UnixListener">
+                        <complexType>
+                            <attribute name="address" type="conf:string" use="required"/>
+                        </complexType>
+                    </element>
+                    <element name="TCPListener">
+                        <complexType>
+                            <attribute name="address" type="conf:string" use="required"/>
+                            <attribute name="port" type="unsignedInt" use="required"/>
+                            <attribute name="acl" type="conf:listOfStrings"/>
+                        </complexType>
+                    </element>
+                    <element name="Listener" type="conf:PluggableType"/>
+                </choice>
+                <element ref="conf:StorageService" minOccurs="0" maxOccurs="unbounded"/>
+                <element ref="conf:SessionCache" minOccurs="0"/>
+                <element ref="conf:ReplayCache" minOccurs="0"/>
+                <element ref="conf:ArtifactMap" minOccurs="0"/>
+                <element name="RequestMapper" type="conf:PluggableType" minOccurs="0"/>
+                               <element ref="conf:ApplicationDefaults"/>
+                               <element ref="conf:SecurityPolicies"/>
+                <element ref="conf:TransportOption" minOccurs="0" maxOccurs="unbounded"/>
+                       </sequence>
+                       <attribute name="logger" type="anyURI"/>
+                       <attribute name="clockSkew" type="unsignedInt"/>
+            <attribute name="unsafeChars" type="conf:string"/>
+            <attribute name="allowedSchemes" type="conf:listOfStrings"/>
+                       <anyAttribute namespace="##other" processContents="lax"/>
+               </complexType>
+       </element>
+
+       <element name="Extensions">
+               <annotation>
+                       <documentation>Container for extension libraries and custom configuration</documentation>
+               </annotation>
+               <complexType>
+                       <sequence>
+                               <element name="Library" minOccurs="0" maxOccurs="unbounded">
+                                       <complexType>
+                                               <sequence>
+                                                       <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+                                               </sequence>
+                                               <attribute name="path" type="anyURI" use="required"/>
+                                               <attribute name="fatal" type="boolean"/>
+                                               <anyAttribute namespace="##any" processContents="skip"/>
+                                       </complexType>
+                               </element>
+                               <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+                       </sequence>
+               </complexType>
+       </element>
+
+       <element name="StorageService">
+               <annotation>
+                       <documentation>References StorageService plugins</documentation>
+               </annotation>
+               <complexType>
+                       <complexContent>
+                               <restriction base="conf:PluggableType">
+                                       <sequence>
+                                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+                                       </sequence>
+                                       <attribute name="id" type="ID" use="required"/>
+                                       <attribute name="cleanupInterval" type="unsignedInt"/>
+                                       <anyAttribute namespace="##any" processContents="skip"/>
+                               </restriction>
+                       </complexContent>
+               </complexType>
+       </element>
+
+       <element name="SessionCache">
+               <annotation>
+                       <documentation>References SessionCache plugins</documentation>
+               </annotation>
+               <complexType>
+                       <complexContent>
+                               <restriction base="conf:PluggableType">
+                                       <sequence>
+                                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+                                       </sequence>
+                                       <attribute name="StorageService" type="IDREF"/>
+                                       <attribute name="cacheTimeout" type="unsignedInt"/>
+                                       <anyAttribute namespace="##any" processContents="skip"/>
+                               </restriction>
+                       </complexContent>
+               </complexType>
+       </element>
+       
+       <element name="ReplayCache">
+               <annotation>
+                       <documentation>Ties ReplayCache to a custom StorageService</documentation>
+               </annotation>
+               <complexType>
+                       <sequence/>
+                       <attribute name="StorageService" type="IDREF" use="required"/>
+               </complexType>
+       </element>
+       
+       <element name="ArtifactMap">
+               <annotation>
+                       <documentation>Customizes an ArtifactMap</documentation>
+               </annotation>
+               <complexType>
+                       <sequence/>
+                       <attribute name="StorageService" type="IDREF"/>
+                       <attribute name="context" type="conf:string"/>
+                       <attribute name="artifactTTL" type="unsignedInt"/>
+               </complexType>
+       </element>
+       
+       <element name="OutOfProcess">
+               <annotation>
+                       <documentation>Container for out-of-process (shibd) configuration</documentation>
+               </annotation>
+               <complexType>
+                       <sequence>
+                               <element ref="conf:Extensions" minOccurs="0"/>
+                               <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+                       </sequence>
+                       <attribute name="logger" type="anyURI"/>
+                   <attribute name="catchAll" type="boolean"/>
+                       <anyAttribute namespace="##other" processContents="lax"/>
+               </complexType>
+       </element>
+
+       <element name="InProcess">
+               <annotation>
+                       <documentation>
+                       Container for configuration of locally integrated or platform-specific
+                       features (e.g. web server filters)
+                       </documentation>
+               </annotation>
+               <complexType>
+                       <sequence>
+                               <element ref="conf:Extensions" minOccurs="0"/>
+                               <element ref="conf:ISAPI" minOccurs="0"/>
+                               <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+                       </sequence>
+                       <attribute name="logger" type="anyURI"/>
+                       <attribute name="unsetHeaderValue" type="conf:string"/>
+                       <attribute name="checkSpoofing" type="boolean"/>
+                       <attribute name="spoofKey" type="conf:string"/>
+                       <attribute name="catchAll" type="boolean"/>
+                       <anyAttribute namespace="##other" processContents="lax"/>
+               </complexType>
+       </element>
+       
+       <element name="ISAPI">
+               <complexType>
+                       <sequence>
+                               <element name="Site" maxOccurs="unbounded">
+                                       <complexType>
+                                               <sequence>
+                                                       <element name="Alias" type="string" minOccurs="0" maxOccurs="unbounded"/>
+                                               </sequence>
+                                               <attribute name="id" type="unsignedInt" use="required"/>
+                                               <attribute name="name" type="conf:string" use="required"/>
+                                               <attribute name="port" type="unsignedInt"/>
+                                               <attribute name="sslport" type="unsignedInt"/>
+                                               <attribute name="scheme" type="conf:string"/>
+                                       </complexType>
+                               </element>
+                               <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+                       </sequence>
+                       <attribute name="normalizeRequest" type="boolean"/>
+                       <attribute name="safeHeaderNames" type="boolean"/>
+                       <anyAttribute namespace="##other" processContents="lax"/>
+               </complexType>
+       </element>
+
+       <element name="AccessControl" type="conf:UniOperatorType">
+               <annotation>
+                       <documentation>
+                       A simple example access policy language extension that supersedes Apache .htaccess
+                       </documentation>
+               </annotation>
+       </element>
+       <element name="OR" type="conf:MultiOperatorType"/>
+       <element name="AND" type="conf:MultiOperatorType"/>
+       <element name="NOT" type="conf:UniOperatorType"/>
+       <complexType name="UniOperatorType">
+               <choice>
+                       <element ref="conf:AND"/>
+                       <element ref="conf:OR"/>
+                       <element ref="conf:NOT"/>
+                       <element ref="conf:Rule"/>
+                   <element ref="conf:RuleRegex"/>
+               </choice>
+       </complexType>
+       <complexType name="MultiOperatorType">
+               <choice minOccurs="2" maxOccurs="unbounded">
+                       <element ref="conf:AND"/>
+                       <element ref="conf:OR"/>
+                       <element ref="conf:NOT"/>
+                       <element ref="conf:Rule"/>
+                   <element ref="conf:RuleRegex"/>
+               </choice>
+       </complexType>
+       <element name="Rule">
+               <complexType>
+                       <simpleContent>
+                               <extension base="conf:listOfStrings">
+                                       <attribute name="require" type="conf:string" use="required"/>
+                                   <attribute name="list" type="boolean"/>
+                               </extension>
+                       </simpleContent>
+               </complexType>
+       </element>
+    <element name="RuleRegex">
+        <complexType>
+            <simpleContent>
+                <extension base="conf:string">
+                    <attribute name="require" type="conf:string" use="required"/>
+                    <attribute name="ignoreCase" type="boolean"/>
+                </extension>
+            </simpleContent>
+        </complexType>
+    </element>
+       
+       <attributeGroup name="ContentSettings">
+               <attribute name="authType" type="conf:string"/>
+               <attribute name="requireSession" type="boolean"/>
+               <attribute name="requireSessionWith" type="conf:string"/>
+               <attribute name="exportAssertion" type="boolean"/>
+               <attribute name="redirectToSSL" type="unsignedInt"/>
+               <attribute name="entityID" type="anyURI"/>
+        <attribute name="discoveryURL" type="anyURI"/>
+               <attribute name="isPassive" type="boolean"/>
+               <attribute name="forceAuthn" type="boolean"/>
+               <attribute name="authnContextClassRef" type="anyURI"/>
+               <attribute name="authnContextComparison" type="samlp:AuthnContextComparisonType"/>
+        <attribute name="NameIDFormat" type="anyURI"/>
+        <attribute name="SPNameQualifier" type="conf:string"/>
+        <attribute name="redirectErrors" type="anyURI"/>
+               <attribute name="sessionError" type="anyURI"/>
+               <attribute name="metadataError" type="anyURI"/>
+               <attribute name="accessError" type="anyURI"/>
+               <attribute name="sslError" type="anyURI"/>
+        <attribute name="REMOTE_ADDR" type="conf:string"/>
+               <anyAttribute namespace="##other" processContents="lax"/>
+       </attributeGroup>
+       <element name="AccessControlProvider" type="conf:PluggableType"/>
+       <element name="htaccess" type="conf:PluggableType"/>
+
+    <element name="RequestMap">
+               <annotation>
+                       <documentation>
+                       Built-in request mapping syntax, decomposes URLs into Host/Path/Path/...
+                       </documentation>
+               </annotation>
+        <complexType>
+            <sequence>
+               <choice minOccurs="0">
+                       <element ref="conf:htaccess"/>
+                                       <element ref="conf:AccessControl"/>
+                       <element ref="conf:AccessControlProvider"/>
+                   </choice>
+               <choice minOccurs="0" maxOccurs="unbounded">
+                                       <element ref="conf:Host"/>
+                       <element ref="conf:HostRegex"/>
+               </choice>
+            </sequence>
+            <attribute name="applicationId" type="conf:string" fixed="default"/>
+               <attributeGroup ref="conf:ContentSettings"/>
+        </complexType>
+    </element>
+
+    <element name="Host">
+       <complexType>
+               <sequence>
+               <choice minOccurs="0">
+                       <element ref="conf:htaccess"/>
+                                       <element ref="conf:AccessControl"/>
+                       <element ref="conf:AccessControlProvider"/>
+                   </choice>
+                       <choice minOccurs="0" maxOccurs="unbounded">
+                               <element ref="conf:Path"/>
+                               <element ref="conf:PathRegex"/>
+                               <element ref="conf:Query"/>
+                       </choice>
+               </sequence>
+               <attribute name="scheme">
+                           <simpleType>
+                               <restriction base="conf:string">
+                                   <enumeration value="http"/>
+                                   <enumeration value="https"/>
+                                   <enumeration value="ftp"/>
+                                   <enumeration value="ldap"/>
+                                   <enumeration value="ldaps"/>
+                               </restriction>
+                           </simpleType>
+               </attribute>
+               <attribute name="name" type="conf:string" use="required"/>
+               <attribute name="port" type="unsignedInt"/>
+                       <attribute name="applicationId" type="conf:string"/>
+               <attributeGroup ref="conf:ContentSettings"/>
+       </complexType>
+    </element>
+       
+       <element name="HostRegex">
+               <complexType>
+                       <sequence>
+                               <choice minOccurs="0">
+                                       <element ref="conf:htaccess"/>
+                                       <element ref="conf:AccessControl"/>
+                                       <element ref="conf:AccessControlProvider"/>
+                               </choice>
+                               <choice minOccurs="0" maxOccurs="unbounded">
+                                       <element ref="conf:Path"/>
+                                       <element ref="conf:PathRegex"/>
+                                       <element ref="conf:Query"/>
+                               </choice>
+                       </sequence>
+                       <attribute name="regex" type="conf:string" use="required"/>
+                       <attribute name="ignoreCase" type="boolean"/>
+                       <attribute name="applicationId" type="conf:string"/>
+                       <attributeGroup ref="conf:ContentSettings"/>
+               </complexType>
+       </element>
+
+    <element name="Path">
+        <complexType>
+               <sequence>
+               <choice minOccurs="0">
+                       <element ref="conf:htaccess"/>
+                                       <element ref="conf:AccessControl"/>
+                       <element ref="conf:AccessControlProvider"/>
+                   </choice>
+                       <choice minOccurs="0" maxOccurs="unbounded">
+                               <element ref="conf:Path"/>
+                               <element ref="conf:PathRegex"/>
+                               <element ref="conf:Query"/>
+                       </choice>
+               </sequence>
+                       <attribute name="name" type="conf:string" use="required"/>
+                       <attribute name="applicationId" type="conf:string"/>
+                       <attributeGroup ref="conf:ContentSettings"/>
+        </complexType>
+    </element>
+
+       <element name="PathRegex">
+               <complexType>
+                       <sequence>
+                               <choice minOccurs="0">
+                                       <element ref="conf:htaccess"/>
+                                       <element ref="conf:AccessControl"/>
+                                       <element ref="conf:AccessControlProvider"/>
+                               </choice>
+                               <element ref="conf:Query" minOccurs="0" maxOccurs="unbounded"/>
+                       </sequence>
+                       <attribute name="regex" type="conf:string" use="required"/>
+                       <attribute name="ignoreCase" type="boolean"/>
+                       <attribute name="applicationId" type="conf:string"/>
+                       <attributeGroup ref="conf:ContentSettings"/>
+               </complexType>
+       </element>
+       
+       <element name="Query">
+               <complexType>
+                       <sequence>
+                               <choice minOccurs="0">
+                                       <element ref="conf:htaccess"/>
+                                       <element ref="conf:AccessControl"/>
+                                       <element ref="conf:AccessControlProvider"/>
+                               </choice>
+                               <element ref="conf:Query" minOccurs="0" maxOccurs="unbounded"/>
+                       </sequence>
+                       <attribute name="name" type="conf:string" use="required"/>
+                       <attribute name="regex" type="conf:string"/>
+                       <attributeGroup ref="conf:ContentSettings"/>
+               </complexType>
+       </element>
+       
+       <element name="ApplicationDefaults">
+               <annotation>
+                       <documentation>Container for default settings and application-specific overrides</documentation>
+               </annotation>
+               <complexType>
+                       <sequence>
+                               <element ref="conf:Sessions"/>
+                               <element ref="conf:Errors" minOccurs="0"/>
+                               <element ref="conf:RelyingParty" minOccurs="0" maxOccurs="unbounded"/>
+                               <element ref="conf:Notify" minOccurs="0" maxOccurs="unbounded"/>
+                               <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
+                <element name="MetadataProvider" type="conf:PluggableType"/>
+                               <element name="TrustEngine" type="conf:PluggableType"/>
+                               <element name="AttributeExtractor" type="conf:PluggableType" minOccurs="0"/>
+                               <element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>
+                               <element name="AttributeFilter" type="conf:PluggableType" minOccurs="0"/>
+                               <element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>
+                               <element ref="conf:ApplicationOverride" minOccurs="0" maxOccurs="unbounded"/>
+                       </sequence>
+                       <attribute name="id" type="conf:string" fixed="default"/>
+                       <attribute name="entityID" type="anyURI" use="required"/>
+                       <attribute name="policyId" type="conf:string" use="required"/>
+                       <attributeGroup ref="conf:ApplicationGroup"/>
+                   <attributeGroup ref="conf:RelyingPartyGroup"/>
+                       <anyAttribute namespace="##other" processContents="lax"/>
+               </complexType>
+       </element>
+       
+       <element name="ApplicationOverride">
+               <annotation>
+                       <documentation>Container for application-specific overrides</documentation>
+               </annotation>
+               <complexType>
+                       <sequence>
+                               <element ref="conf:Sessions" minOccurs="0"/>
+                               <element ref="conf:Errors" minOccurs="0"/>
+                               <element ref="conf:RelyingParty" minOccurs="0" maxOccurs="unbounded"/>
+                               <element ref="conf:Notify" minOccurs="0" maxOccurs="unbounded"/>
+                               <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
+                               <element name="MetadataProvider" type="conf:PluggableType" minOccurs="0"/>
+                               <element name="TrustEngine" type="conf:PluggableType" minOccurs="0"/>
+                               <element name="AttributeExtractor" type="conf:PluggableType" minOccurs="0"/>
+                               <element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>
+                               <element name="AttributeFilter" type="conf:PluggableType" minOccurs="0"/>
+                               <element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>
+                       </sequence>
+                       <attribute name="id" type="conf:string" use="required"/>
+                       <attribute name="entityID" type="anyURI"/>
+                       <attribute name="policyId" type="conf:string"/>
+                       <attributeGroup ref="conf:ApplicationGroup"/>
+                   <attributeGroup ref="conf:RelyingPartyGroup"/>
+                       <anyAttribute namespace="##other" processContents="lax"/>
+               </complexType>
+       </element>
+
+       <attributeGroup name="ApplicationGroup">
+               <attribute name="homeURL" type="anyURI"/>
+               <attribute name="REMOTE_USER" type="conf:listOfStrings"/>
+               <attribute name="unsetHeaders" type="conf:listOfStrings"/>
+               <attribute name="metadataAttributePrefix" type="conf:string"/>
+           <attribute name="attributePrefix" type="conf:string"/>
+       </attributeGroup>
+
+    <attributeGroup name="RelyingPartyGroup">
+        <attribute name="authType" type="conf:string"/>
+        <attribute name="authUsername" type="conf:string"/>
+        <attribute name="authPassword" type="conf:string"/>
+        <attribute name="signing" type="conf:bindingBoolean"/>
+        <attribute name="signingAlg" type="anyURI"/>
+        <attribute name="digestAlg" type="anyURI"/>
+        <attribute name="encryption" type="conf:bindingBoolean"/>
+        <attribute name="encryptionAlg" type="anyURI"/>
+        <attribute name="keyName" type="conf:string"/>
+        <attribute name="artifactEndpointIndex" type="unsignedShort"/>
+        <attribute name="chunkedEncoding" type="boolean"/>
+        <attribute name="connectTimeout" type="unsignedShort"/>
+        <attribute name="timeout" type="unsignedShort"/>
+        <attribute name="requireConfidentiality" type="boolean"/>
+        <attribute name="requireTransportAuth" type="boolean"/>
+        <attribute name="requireSignedAssertions" type="boolean"/>
+    </attributeGroup>
+    
+       <element name="Sessions">
+               <annotation>
+                       <documentation>Container for specifying protocol handlers and session policy</documentation>
+               </annotation>
+               <complexType>
+                       <choice minOccurs="0" maxOccurs="unbounded">
+                               <element ref="conf:SessionInitiator"/>
+                               <element ref="conf:LogoutInitiator"/>
+                               <element ref="md:AssertionConsumerService"/>
+                               <element ref="md:ArtifactResolutionService"/>
+                               <element ref="md:SingleLogoutService"/>
+                               <element ref="md:ManageNameIDService"/>
+                               <element name="Handler">
+                                       <complexType>
+                                               <complexContent>
+                                                       <restriction base="conf:PluggableType">
+                                                               <sequence>
+                                                                       <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+                                                               </sequence>
+                                                               <attribute name="Location" type="anyURI" use="required"/>
+                                                           <attribute name="acl" type="conf:listOfStrings"/>
+                                                               <anyAttribute namespace="##any" processContents="skip"/>
+                                                       </restriction>
+                                               </complexContent>
+                                       </complexType>
+                               </element>
+                       </choice>
+                       <attribute name="handlerURL" type="anyURI" use="required"/>
+                       <attribute name="handlerSSL" type="boolean"/>
+                       <attribute name="exportLocation" type="conf:string"/>
+                       <attribute name="exportACL" type="conf:listOfStrings"/>
+                       <attribute name="cookieName" type="conf:string"/>
+                       <attribute name="cookieProps" type="conf:string"/>
+            <attribute name="cookieLifetime" type="unsignedInt"/>
+                       <attribute name="idpHistory" type="boolean"/>
+                       <attribute name="idpHistoryDays" type="unsignedInt"/>
+                       <attribute name="lifetime" type="unsignedInt"/>
+                       <attribute name="timeout" type="unsignedInt"/>
+                   <attribute name="maxTimeSinceAuthn" type="unsignedInt"/>
+                       <attribute name="checkAddress" type="boolean"/>
+                       <attribute name="consistentAddress" type="boolean"/>
+                       <attribute name="postData" type="conf:string"/>
+            <attribute name="postLimit" type="positiveInteger"/>
+                       <attribute name="postTemplate" type="conf:string"/>
+            <attribute name="postExpire" type="boolean"/>
+                       <anyAttribute namespace="##other" processContents="lax"/>
+               </complexType>
+       </element>
+
+       <attribute name="policyId" type="conf:string">
+               <annotation>
+                       <documentation>Used to reference Policy elements from profile endpoints.</documentation>
+               </annotation>
+       </attribute>
+
+       <element name="SessionInitiator">
+               <annotation>
+                       <documentation>Used to specify handlers that can issue AuthnRequests or perform discovery</documentation>
+               </annotation>
+               <complexType>
+                       <complexContent>
+                               <restriction base="conf:PluggableType">
+                                       <sequence>
+                                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+                                       </sequence>
+                                       <attribute name="Location" type="anyURI"/>
+                                       <attribute name="id" type="conf:string"/>
+                                       <attribute name="isDefault" type="boolean"/>
+                                       <attribute name="relayState" type="conf:string"/>
+                                       <attribute name="entityIDParam" type="conf:string"/>
+                                       <attribute name="entityID" type="anyURI"/>
+                                       <attribute name="URL" type="anyURI"/>
+                                       <attribute name="outgoingBindings" type="conf:listOfURIs"/>
+                                       <attribute name="template" type="anyURI"/>
+                                       <attribute name="postArtifact" type="boolean"/>
+                                       <attribute name="acsByIndex" type="boolean"/>
+                    <attribute name="acsIndex" type="unsignedShort"/>
+                                       <attribute name="defaultACSIndex" type="unsignedShort"/>   <!-- deprecated -->
+                    <attribute name="isPassive" type="boolean"/>
+                    <attribute name="forceAuthn" type="boolean"/>
+                    <attribute name="authnContextClassRef" type="anyURI"/>
+                    <attribute name="authnContextComparison" type="samlp:AuthnContextComparisonType"/>
+                    <attribute name="NameIDFormat" type="anyURI"/>
+                    <attribute name="SPNameQualifier" type="conf:string"/>
+                    <attribute name="requestDelegation" type="boolean"/>
+                                       <anyAttribute namespace="##any" processContents="skip"/>
+                               </restriction>
+                       </complexContent>
+               </complexType>
+       </element>
+
+       <element name="LogoutInitiator">
+               <annotation>
+                       <documentation>Used to specify handlers that can issue LogoutRequests</documentation>
+               </annotation>
+               <complexType>
+                       <complexContent>
+                               <restriction base="conf:PluggableType">
+                                       <sequence>
+                                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+                                       </sequence>
+                                       <attribute name="Location" type="anyURI"/>
+                                   <attribute name="relayState" type="conf:string"/>
+                                       <attribute name="outgoingBindings" type="conf:listOfURIs"/>
+                                       <attribute name="template" type="anyURI"/>
+                                       <attribute name="postArtifact" type="boolean"/>
+                                       <anyAttribute namespace="##any" processContents="skip"/>
+                               </restriction>
+                       </complexContent>
+               </complexType>
+       </element>
+       
+       <element name="Errors">
+               <annotation>
+                       <documentation>Container for error templates and associated details</documentation>
+               </annotation>
+               <complexType>
+                       <sequence>
+                               <any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+                       </sequence>
+            <attribute name="redirectErrors" type="anyURI"/>
+                       <attribute name="session" type="anyURI"/>
+                       <attribute name="metadata" type="anyURI"/>
+                       <attribute name="access" type="anyURI"/>
+                       <attribute name="ssl" type="anyURI"/>
+            <attribute name="localLogout" type="anyURI"/>
+            <attribute name="globalLogout" type="anyURI"/>
+            <attribute name="partialLogout" type="anyURI"/>
+                       <attribute name="supportContact" type="conf:string"/>
+                       <attribute name="logoLocation" type="anyURI"/>
+                       <attribute name="styleSheet" type="anyURI"/>
+                       <anyAttribute namespace="##any" processContents="skip"/>
+               </complexType>
+       </element>
+
+    <element name="RelyingParty">
+        <annotation>
+            <documentation>Container for specifying settings to use with particular peers</documentation>
+        </annotation>
+        <complexType>
+            <sequence/>
+            <attribute name="Name" type="conf:string" use="required"/>
+            <attributeGroup ref="conf:RelyingPartyGroup"/>
+            <attribute name="entityID" type="anyURI"/>
+            <anyAttribute namespace="##other" processContents="lax"/>
+        </complexType>
+    </element>
+    
+       <element name="Notify">
+               <annotation>
+                       <documentation>Used to specify locations to receive application notifications</documentation>
+               </annotation>
+               <complexType>
+                       <sequence/>
+                       <attribute name="Channel" use="required">
+                               <simpleType>
+                                       <restriction base="string">
+                                               <enumeration value="front"/>
+                                               <enumeration value="back"/>
+                                       </restriction>
+                               </simpleType>
+                       </attribute>
+                       <attribute name="Location" type="anyURI" use="required"/>
+                       <anyAttribute namespace="##any" processContents="skip"/>
+               </complexType>
+       </element>
+       
+       <element name="SecurityPolicies">
+               <annotation>
+                       <documentation>Container for specifying sets of policy rules to apply to incoming messages</documentation>
+               </annotation>
+               <complexType>
+                       <sequence>
+                               <element name="Policy" minOccurs="1" maxOccurs="unbounded">
+                                       <annotation>
+                                               <documentation>Specifies a set of SecurityPolicyRule plugins</documentation>
+                                       </annotation>
+                                       <complexType>
+                                               <choice>
+                                                       <element name="Rule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>
+                            <element name="PolicyRule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>
+                                               </choice>
+                                               <attribute name="id" type="conf:string" use="required"/>
+                                               <attribute name="validate" type="boolean"/>
+                                               <anyAttribute namespace="##any" processContents="skip"/>
+                                       </complexType>
+                               </element>
+                       </sequence>
+               </complexType>
+       </element>
+
+       <element name="TransportOption">
+               <annotation>
+                       <documentation>Implementation-specific option to pass to SOAPTransport provider.</documentation>
+               </annotation>
+               <complexType>
+                       <simpleContent>
+                               <extension base="anySimpleType">
+                                       <attribute name="provider" type="conf:string" use="required"/>
+                                       <attribute name="option" type="conf:string" use="required"/>
+                               </extension>
+                       </simpleContent>
+               </complexType>
+       </element>
+       
+</schema>
index b5bb7c8..81c64fa 100644 (file)
@@ -1,6 +1,6 @@
 Name:          shibboleth
-Version:       2.3
-Release:       2
+Version:       2.3.1
+Release:       1
 Summary:    Open source system for attribute-based Web SSO
 Group:         System Environment/Libraries
 Vendor:     Internet2
@@ -244,6 +244,9 @@ cd /
 %doc %{pkgdocdir}/api
 
 %changelog
+* Mon Nov 23 2009 Scott Cantor  <cantor.2@osu.edu>  - 2.3.1-1
+- Reset revision for 2.3.1 release
+
 * Wed Aug 19 2009 Scott Cantor  <cantor.2@osu.edu>  - 2.2.1-2
 - SuSE init script changes
 - Restart Apache on removal, not just upgrade
index a6c612f..21cadbc 100644 (file)
@@ -1,6 +1,6 @@
 Name:          @PACKAGE@
 Version:       @PACKAGE_VERSION@
-Release:       2
+Release:       1
 Summary:    Open source system for attribute-based Web SSO
 Group:         System Environment/Libraries
 Vendor:     Internet2
@@ -244,6 +244,9 @@ cd /
 %doc %{pkgdocdir}/api
 
 %changelog
+* Mon Nov 23 2009 Scott Cantor  <cantor.2@osu.edu>  - 2.3.1-1
+- Reset revision for 2.3.1 release
+
 * Wed Aug 19 2009 Scott Cantor  <cantor.2@osu.edu>  - 2.2.1-2
 - SuSE init script changes
 - Restart Apache on removal, not just upgrade
index 264fc0c..a2ce8b1 100644 (file)
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //\r
 \r
 VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION 2,3,0,0\r
- PRODUCTVERSION 2,3,0,0\r
+ FILEVERSION 2,3,1,0\r
+ PRODUCTVERSION 2,3,1,0\r
  FILEFLAGSMASK 0x3fL\r
 #ifdef _DEBUG\r
  FILEFLAGS 0x1L\r
@@ -47,14 +47,14 @@ BEGIN
             VALUE "Comments", "\0"\r
             VALUE "CompanyName", "Internet2\0"\r
             VALUE "FileDescription", "Shibboleth Daemon Service\0"\r
-            VALUE "FileVersion", "2, 3, 0, 0\0"\r
+            VALUE "FileVersion", "2, 3, 1, 0\0"\r
             VALUE "InternalName", "shibd\0"\r
             VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"\r
             VALUE "LegalTrademarks", "\0"\r
             VALUE "OriginalFilename", "shibd.exe\0"\r
             VALUE "PrivateBuild", "\0"\r
-            VALUE "ProductName", "Shibboleth 2.3\0"\r
-            VALUE "ProductVersion", "2, 3, 0, 0\0"\r
+            VALUE "ProductName", "Shibboleth 2.3.1\0"\r
+            VALUE "ProductVersion", "2, 3, 1, 0\0"\r
             VALUE "SpecialBuild", "\0"\r
         END\r
     END\r
index 7a9a602..7069a91 100644 (file)
@@ -360,7 +360,7 @@ void CmdInstallService(LPCSTR name)
         return;
     }
     
-    string dispName = string("Shibboleth ") + PACKAGE_VERSION + " Daemon (" + name + ")";
+    string dispName = string("Shibboleth 2 Daemon (") + name + ")";
     string realName = string("shibd_") + name;
     string cmd(szPath);
     if (shar_prefix)
index dea7654..213f834 100644 (file)
@@ -206,8 +206,8 @@ libshibsp_la_SOURCES = \
 
 # this is different from the project version
 # http://sources.redhat.com/autobook/autobook/autobook_91.html
-libshibsp_la_LDFLAGS = $(XMLSEC_LIBS) -version-info 4:0:0
-libshibsp_lite_la_LDFLAGS = $(LITE_LIBS) -version-info 4:0:0
+libshibsp_la_LDFLAGS = $(XMLSEC_LIBS) -version-info 4:1:0
+libshibsp_lite_la_LDFLAGS = $(LITE_LIBS) -version-info 4:1:0
 libshibsp_lite_la_CPPFLAGS = -DSHIBSP_LITE
 
 pkgsysconfdir = $(sysconfdir)/@PACKAGE@
index 6e3bd9c..8040d75 100644 (file)
@@ -598,8 +598,8 @@ libshibsp_la_SOURCES = \
 
 # this is different from the project version
 # http://sources.redhat.com/autobook/autobook/autobook_91.html
-libshibsp_la_LDFLAGS = $(XMLSEC_LIBS) -version-info 4:0:0
-libshibsp_lite_la_LDFLAGS = $(LITE_LIBS) -version-info 4:0:0
+libshibsp_la_LDFLAGS = $(XMLSEC_LIBS) -version-info 4:1:0
+libshibsp_lite_la_LDFLAGS = $(LITE_LIBS) -version-info 4:1:0
 libshibsp_lite_la_CPPFLAGS = -DSHIBSP_LITE
 pkgsysconfdir = $(sysconfdir)/@PACKAGE@
 pkgxmldir = $(datadir)/xml/@PACKAGE@
index 2c9c8fc..f080088 100644 (file)
@@ -205,6 +205,7 @@ namespace shibsp {
 
         Category& m_log;
         string m_policyId;
+        bool m_subjectMatch;
         vector<AttributeDesignator*> m_SAML1Designators;
         vector<saml2::Attribute*> m_SAML2Designators;
     };
@@ -214,20 +215,24 @@ namespace shibsp {
         return new QueryResolver(e);
     }
 
-    static const XMLCh _policyId[] = UNICODE_LITERAL_8(p,o,l,i,c,y,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);
 };
 
-QueryResolver::QueryResolver(const DOMElement* e) : m_log(Category::getInstance(SHIBSP_LOGCAT".AttributeResolver.Query"))
+QueryResolver::QueryResolver(const DOMElement* e) : m_log(Category::getInstance(SHIBSP_LOGCAT".AttributeResolver.Query")), m_subjectMatch(false)
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("QueryResolver");
 #endif
 
-    const XMLCh* pid = e ? e->getAttributeNS(NULL, _policyId) : NULL;
+    const XMLCh* pid = e ? e->getAttributeNS(NULL, policyId) : NULL;
     if (pid && *pid) {
         auto_ptr_char temp(pid);
         m_policyId = temp.get();
     }
+    pid = e ? e->getAttributeNS(NULL, subjectMatch) : NULL;
+    if (pid && (*pid == chLatin_t || *pid == chDigit_1))
+        m_subjectMatch = true;
 
     DOMElement* child = XMLHelper::getFirstChildElement(e);
     while (child) {
@@ -366,7 +371,7 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
     }
 
     newtoken->detach();
-    wrapper.release();
+    wrapper.release();  // detach blows away the Response
     ctx.getResolvedAssertions().push_back(newtoken);
 
     // Finally, extract and filter the result.
@@ -374,7 +379,24 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
         AttributeExtractor* extractor = application.getAttributeExtractor();
         if (extractor) {
             Locker extlocker(extractor);
-            extractor->extractAttributes(application, AA, *newtoken, ctx.getResolvedAttributes());
+            const vector<saml1::AttributeStatement*>& statements = const_cast<const saml1::Assertion*>(newtoken)->getAttributeStatements();
+            for (vector<saml1::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {
+                if (m_subjectMatch) {
+                    // Check for subject match.
+                    const NameIdentifier* respName = (*s)->getSubject() ? (*s)->getSubject()->getNameIdentifier() : NULL;
+                    if (!respName || !XMLString::equals(respName->getName(), ctx.getNameID()->getName()) ||
+                        !XMLString::equals(respName->getFormat(), ctx.getNameID()->getFormat()) ||
+                        !XMLString::equals(respName->getNameQualifier(), ctx.getNameID()->getNameQualifier())) {
+                        if (respName)
+                            m_log.warnStream() << "ignoring AttributeStatement without strongly matching NameIdentifier in Subject: " <<
+                                *respName << logging::eol;
+                        else
+                            m_log.warn("ignoring AttributeStatement without NameIdentifier in Subject");
+                        continue;
+                    }
+                }
+                extractor->extractAttributes(application, AA, *(*s), ctx.getResolvedAttributes());
+            }
         }
 
         AttributeFilter* filter = application.getAttributeFilter();
@@ -437,7 +459,6 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
             // Encrypt the NameID?
             if (encryption.first && (!strcmp(encryption.second, "true") || !strcmp(encryption.second, "back"))) {
                 auto_ptr<EncryptedID> encrypted(EncryptedIDBuilder::buildEncryptedID());
-                MetadataCredentialCriteria mcc(*AA);
                 encrypted->encrypt(
                     *ctx.getNameID(),
                     *(application.getMetadataProvider()),
@@ -473,33 +494,72 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
         m_log.error("unable to obtain a SAML response from attribute authority");
         return false;
     }
+
+    auto_ptr<saml2p::StatusResponseType> wrapper(srt);
+
     saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt);
     if (!response) {
-        delete srt;
         m_log.error("message was not a samlp:Response");
         return true;
     }
     else if (!response->getStatus() || !response->getStatus()->getStatusCode() ||
             !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
-        delete srt;
         m_log.error("attribute authority returned a SAML error");
         return true;
     }
 
+    saml2::Assertion* newtoken = NULL;
     const vector<saml2::Assertion*>& assertions = const_cast<const saml2p::Response*>(response)->getAssertions();
     if (assertions.empty()) {
-        delete srt;
-        m_log.warn("response from attribute authority was empty");
-        return true;
-    }
-    else if (assertions.size()>1)
-        m_log.warn("simple resolver only supports one assertion in the query response");
+        // Check for encryption.
+        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;
+        }
+        else if (encassertions.size() > 1) {
+            m_log.warn("simple resolver only supports one assertion in the query response");
+        }
 
-    auto_ptr<saml2p::StatusResponseType> wrapper(srt);
-    saml2::Assertion* newtoken = assertions.front();
+        CredentialResolver* cr=application.getCredentialResolver();
+        if (!cr) {
+            m_log.warn("found encrypted assertion, but no CredentialResolver was available");
+            return true;
+        }
+
+        // Attempt to decrypt it.
+        try {
+            Locker credlocker(cr);
+            auto_ptr<XMLObject> tokenwrapper(encassertions.front()->decrypt(*cr, relyingParty->getXMLString("entityID").second, &mcc));
+            newtoken = dynamic_cast<saml2::Assertion*>(tokenwrapper.get());
+            if (newtoken) {
+                tokenwrapper.release();
+                if (m_log.isDebugEnabled())
+                    m_log.debugStream() << "decrypted Assertion: " << *newtoken << logging::eol;
+            }
+        }
+        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;
+        }
+    }
+    else {
+        if (assertions.size() > 1)
+            m_log.warn("simple resolver only supports one assertion in the query response");
+        newtoken = assertions.front();
+    }
 
     if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
         m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
+        if (!wrapper.get())
+            delete newtoken;
         return true;
     }
 
@@ -515,14 +575,60 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
         // Now we can check the security status of the policy.
         if (!policy.isAuthenticated())
             throw SecurityPolicyException("Security of SAML 2.0 query result not established.");
+
+        if (m_subjectMatch) {
+            // Check for subject match.
+            bool ownedName = false;
+            NameID* respName = newtoken->getSubject() ? newtoken->getSubject()->getNameID() : NULL;
+            if (!respName) {
+                // Check for encryption.
+                EncryptedID* encname = newtoken->getSubject() ? newtoken->getSubject()->getEncryptedID() : NULL;
+                if (encname) {
+                    CredentialResolver* cr=application.getCredentialResolver();
+                    if (!cr)
+                        m_log.warn("found EncryptedID, but no CredentialResolver was available");
+                    else {
+                        Locker credlocker(cr);
+                        auto_ptr<XMLObject> decryptedID(encname->decrypt(*cr, relyingParty->getXMLString("entityID").second, &mcc));
+                        respName = dynamic_cast<NameID*>(decryptedID.get());
+                        if (respName) {
+                            ownedName = true;
+                            decryptedID.release();
+                            if (m_log.isDebugEnabled())
+                                m_log.debugStream() << "decrypted NameID: " << *respName << logging::eol;
+                        }
+                    }
+                }
+            }
+
+            auto_ptr<NameID> nameIDwrapper(ownedName ? respName : NULL);
+
+            if (!respName || !XMLString::equals(respName->getName(), ctx.getNameID()->getName()) ||
+                !XMLString::equals(respName->getFormat(), ctx.getNameID()->getFormat()) ||
+                !XMLString::equals(respName->getNameQualifier(), ctx.getNameID()->getNameQualifier()) ||
+                !XMLString::equals(respName->getSPNameQualifier(), ctx.getNameID()->getSPNameQualifier())) {
+                if (respName)
+                    m_log.warnStream() << "ignoring Assertion without strongly matching NameID in Subject: " <<
+                        *respName << logging::eol;
+                else
+                    m_log.warn("ignoring Assertion without NameID in Subject");
+                if (!wrapper.get())
+                    delete newtoken;
+                return true;
+            }
+        }
     }
     catch (exception& ex) {
         m_log.error("assertion failed policy validation: %s", ex.what());
+        if (!wrapper.get())
+            delete newtoken;
         return true;
     }
 
-    newtoken->detach();
-    wrapper.release();
+    if (wrapper.get()) {
+        newtoken->detach();
+        wrapper.release();  // detach blows away the Response
+    }
     ctx.getResolvedAssertions().push_back(newtoken);
 
     // Finally, extract and filter the result.
@@ -571,9 +677,11 @@ void QueryResolver::resolveAttributes(ResolutionContext& ctx) const
             m_log.debug("attempting SAML 1.x attribute query");
             SAML1Query(qctx);
         }
-        else
-            m_log.warn("SSO protocol does not allow for attribute query");
+        else {
+            m_log.info("SSO protocol does not allow for attribute query");
+        }
     }
-    else
+    else {
         m_log.warn("can't attempt attribute query, either no NameID or no metadata to use");
+    }
 }
index c4d3336..f3d9f79 100644 (file)
@@ -178,6 +178,7 @@ namespace shibsp {
 
         Category& m_log;
         string m_policyId;
+        bool m_subjectMatch;
         vector<string> m_attributeIds;
         xstring m_format;
         MetadataProvider* m_metadata;
@@ -197,12 +198,13 @@ namespace shibsp {
     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 subjectMatch[] =         UNICODE_LITERAL_12(s,u,b,j,e,c,t,M,a,t,c,h);
     static const XMLCh _TrustEngine[] =         UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e);
     static const XMLCh _type[] =                UNICODE_LITERAL_4(t,y,p,e);
 };
 
 SimpleAggregationResolver::SimpleAggregationResolver(const DOMElement* e)
-    : m_log(Category::getInstance(SHIBSP_LOGCAT".AttributeResolver.SimpleAggregation")), m_metadata(NULL), m_trust(NULL)
+    : m_log(Category::getInstance(SHIBSP_LOGCAT".AttributeResolver.SimpleAggregation")), m_subjectMatch(false), m_metadata(NULL), m_trust(NULL)
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("SimpleAggregationResolver");
@@ -214,6 +216,10 @@ SimpleAggregationResolver::SimpleAggregationResolver(const DOMElement* e)
         m_policyId = temp.get();
     }
 
+    pid = e ? e->getAttributeNS(NULL, subjectMatch) : NULL;
+    if (pid && (*pid == chLatin_t || *pid == chDigit_1))
+        m_subjectMatch = true;
+
     pid = e ? e->getAttributeNS(NULL, attributeId) : NULL;
     if (pid && *pid) {
         char* dup = XMLString::transcode(pid);
@@ -235,7 +241,6 @@ SimpleAggregationResolver::SimpleAggregationResolver(const DOMElement* e)
         pid = e->getAttributeNS(NULL, format);
         if (pid && *pid)
             m_format = pid;
-
     }
 
     DOMElement* child = XMLHelper::getFirstChildElement(e, _MetadataProvider);
@@ -295,7 +300,6 @@ SimpleAggregationResolver::SimpleAggregationResolver(const DOMElement* e)
         }
         child = XMLHelper::getNextSiblingElement(child);
     }
-
 }
 
 bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const char* entityID, const NameID* name) const
@@ -353,7 +357,6 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
             // Encrypt the NameID?
             if (encryption.first && (!strcmp(encryption.second, "true") || !strcmp(encryption.second, "back"))) {
                 auto_ptr<EncryptedID> encrypted(EncryptedIDBuilder::buildEncryptedID());
-                MetadataCredentialCriteria mcc(*AA);
                 encrypted->encrypt(
                     *name,
                     *(policy.getMetadataProvider()),
@@ -389,33 +392,73 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
         m_log.error("unable to obtain a SAML response from attribute authority (%s)", entityID);
         return false;
     }
+
+    auto_ptr<saml2p::StatusResponseType> wrapper(srt);
+
     saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt);
     if (!response) {
-        delete srt;
         m_log.error("message was not a samlp:Response");
         return true;
     }
     else if (!response->getStatus() || !response->getStatus()->getStatusCode() ||
             !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) {
-        delete srt;
         m_log.error("attribute authority (%s) returned a SAML error", entityID);
         return true;
     }
 
+    saml2::Assertion* newtoken = NULL;
     const vector<saml2::Assertion*>& assertions = const_cast<const saml2p::Response*>(response)->getAssertions();
     if (assertions.empty()) {
-        delete srt;
-        m_log.warn("response from attribute authority (%s) was empty", entityID);
-        return true;
-    }
-    else if (assertions.size()>1)
-        m_log.warn("resolver only supports one assertion in the query response");
+        // Check for encryption.
+        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;
+        }
+        else if (encassertions.size() > 1) {
+            m_log.warn("simple resolver only supports one assertion in the query response");
+        }
 
-    auto_ptr<saml2p::StatusResponseType> wrapper(srt);
-    saml2::Assertion* newtoken = assertions.front();
+        CredentialResolver* cr=application.getCredentialResolver();
+        if (!cr) {
+            m_log.warn("found encrypted assertion, but no CredentialResolver was available");
+            return true;
+        }
+
+        // Attempt to decrypt it.
+        try {
+            Locker credlocker(cr);
+            auto_ptr<XMLObject> tokenwrapper(encassertions.front()->decrypt(*cr, relyingParty->getXMLString("entityID").second, &mcc));
+            newtoken = dynamic_cast<saml2::Assertion*>(tokenwrapper.get());
+            if (newtoken) {
+                tokenwrapper.release();
+                if (m_log.isDebugEnabled())
+                    m_log.debugStream() << "decrypted Assertion: " << *newtoken << logging::eol;
+            }
+        }
+        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;
+        }
+    }
+    else {
+        if (assertions.size() > 1)
+            m_log.warn("simple resolver only supports one assertion in the query response");
+        newtoken = assertions.front();
+    }
 
     if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
         m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
+        if (!wrapper.get())
+            delete newtoken;
         return true;
     }
 
@@ -431,14 +474,60 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha
         // Now we can check the security status of the policy.
         if (!policy.isAuthenticated())
             throw SecurityPolicyException("Security of SAML 2.0 query result not established.");
+
+        if (m_subjectMatch) {
+            // Check for subject match.
+            bool ownedName = false;
+            NameID* respName = newtoken->getSubject() ? newtoken->getSubject()->getNameID() : NULL;
+            if (!respName) {
+                // Check for encryption.
+                EncryptedID* encname = newtoken->getSubject() ? newtoken->getSubject()->getEncryptedID() : NULL;
+                if (encname) {
+                    CredentialResolver* cr=application.getCredentialResolver();
+                    if (!cr)
+                        m_log.warn("found EncryptedID, but no CredentialResolver was available");
+                    else {
+                        Locker credlocker(cr);
+                        auto_ptr<XMLObject> decryptedID(encname->decrypt(*cr, relyingParty->getXMLString("entityID").second, &mcc));
+                        respName = dynamic_cast<NameID*>(decryptedID.get());
+                        if (respName) {
+                            ownedName = true;
+                            decryptedID.release();
+                            if (m_log.isDebugEnabled())
+                                m_log.debugStream() << "decrypted NameID: " << *respName << logging::eol;
+                        }
+                    }
+                }
+            }
+
+            auto_ptr<NameID> nameIDwrapper(ownedName ? respName : NULL);
+
+            if (!respName || !XMLString::equals(respName->getName(), name->getName()) ||
+                !XMLString::equals(respName->getFormat(), name->getFormat()) ||
+                !XMLString::equals(respName->getNameQualifier(), name->getNameQualifier()) ||
+                !XMLString::equals(respName->getSPNameQualifier(), name->getSPNameQualifier())) {
+                if (respName)
+                    m_log.warnStream() << "ignoring Assertion without strongly matching NameID in Subject: " <<
+                        *respName << logging::eol;
+                else
+                    m_log.warn("ignoring Assertion without NameID in Subject");
+                if (!wrapper.get())
+                    delete newtoken;
+                return true;
+            }
+        }
     }
     catch (exception& ex) {
         m_log.error("assertion failed policy validation: %s", ex.what());
+        if (!wrapper.get())
+            delete newtoken;
         return true;
     }
 
-    newtoken->detach();
-    wrapper.release();
+    if (wrapper.get()) {
+        newtoken->detach();
+        wrapper.release();  // detach blows away the Response
+    }
     ctx.getResolvedAssertions().push_back(newtoken);
 
     // Finally, extract and filter the result.
index e77133a..9b9d98d 100644 (file)
@@ -127,6 +127,20 @@ namespace shibsp {
             ) const;
         void extractAttributes(
             const Application& application,
+            const char* assertingParty,
+            const char* relyingParty,
+            const saml1::AttributeStatement& statement,
+            vector<Attribute*>& attributes
+            ) const;
+        void extractAttributes(
+            const Application& application,
+            const char* assertingParty,
+            const char* relyingParty,
+            const saml2::AttributeStatement& statement,
+            vector<Attribute*>& attributes
+            ) const;
+        void extractAttributes(
+            const Application& application,
             const ObservableMetadataProvider* observable,
             const XMLCh* entityID,
             const char* relyingParty,
@@ -540,6 +554,32 @@ void XMLExtractorImpl::extractAttributes(
 
 void XMLExtractorImpl::extractAttributes(
     const Application& application,
+    const char* assertingParty,
+    const char* relyingParty,
+    const saml1::AttributeStatement& statement,
+    vector<Attribute*>& attributes
+    ) const
+{
+    const vector<saml1::Attribute*>& attrs = statement.getAttributes();
+    for (vector<saml1::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a)
+        extractAttributes(application, assertingParty, relyingParty, *(*a), attributes);
+}
+
+void XMLExtractorImpl::extractAttributes(
+    const Application& application,
+    const char* assertingParty,
+    const char* relyingParty,
+    const saml2::AttributeStatement& statement,
+    vector<Attribute*>& attributes
+    ) const
+{
+    const vector<saml2::Attribute*>& attrs = statement.getAttributes();
+    for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a)
+        extractAttributes(application, assertingParty, relyingParty, *(*a), attributes);
+}
+
+void XMLExtractorImpl::extractAttributes(
+    const Application& application,
     const ObservableMetadataProvider* observable,
     const XMLCh* entityID,
     const char* relyingParty,
@@ -792,6 +832,29 @@ void XMLExtractor::extractAttributes(
     const EntityDescriptor* entity = issuer ? dynamic_cast<const EntityDescriptor*>(issuer->getParent()) : NULL;
     const char* relyingParty = application.getRelyingParty(entity)->getString("entityID").second;
 
+    // Check for statements.
+    if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), saml1::AttributeStatement::LOCAL_NAME)) {
+        const saml2::AttributeStatement* statement2 = dynamic_cast<const saml2::AttributeStatement*>(&xmlObject);
+        if (statement2) {
+            auto_ptr_char assertingParty(entity ? entity->getEntityID() : NULL);
+            m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *statement2, attributes);
+            // Handle EncryptedAttributes inline so we have access to the role descriptor.
+            const vector<saml2::EncryptedAttribute*>& encattrs = statement2->getEncryptedAttributes();
+            for (vector<saml2::EncryptedAttribute*>::const_iterator ea = encattrs.begin(); ea!=encattrs.end(); ++ea)
+                extractAttributes(application, issuer, *(*ea), attributes);
+            return;
+        }
+
+        const saml1::AttributeStatement* statement1 = dynamic_cast<const saml1::AttributeStatement*>(&xmlObject);
+        if (statement1) {
+            auto_ptr_char assertingParty(entity ? entity->getEntityID() : NULL);
+            m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *statement1, attributes);
+            return;
+        }
+
+        throw AttributeExtractionException("Unable to extract attributes, unknown object type.");
+    }
+
     // Check for assertions.
     if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), saml1::Assertion::LOCAL_NAME)) {
         const saml2::Assertion* token2 = dynamic_cast<const saml2::Assertion*>(&xmlObject);
@@ -799,10 +862,8 @@ void XMLExtractor::extractAttributes(
             auto_ptr_char assertingParty(entity ? entity->getEntityID() : NULL);
             const vector<saml2::AttributeStatement*>& statements = token2->getAttributeStatements();
             for (vector<saml2::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {
-                const vector<saml2::Attribute*>& attrs = const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
-                for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a)
-                    m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *(*a), attributes);
-
+                m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *(*s), attributes);
+                // Handle EncryptedAttributes inline so we have access to the role descriptor.
                 const vector<saml2::EncryptedAttribute*>& encattrs = const_cast<const saml2::AttributeStatement*>(*s)->getEncryptedAttributes();
                 for (vector<saml2::EncryptedAttribute*>::const_iterator ea = encattrs.begin(); ea!=encattrs.end(); ++ea)
                     extractAttributes(application, issuer, *(*ea), attributes);
@@ -814,11 +875,8 @@ void XMLExtractor::extractAttributes(
         if (token1) {
             auto_ptr_char assertingParty(entity ? entity->getEntityID() : NULL);
             const vector<saml1::AttributeStatement*>& statements = token1->getAttributeStatements();
-            for (vector<saml1::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {
-                const vector<saml1::Attribute*>& attrs = const_cast<const saml1::AttributeStatement*>(*s)->getAttributes();
-                for (vector<saml1::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a)
-                    m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *(*a), attributes);
-            }
+            for (vector<saml1::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s)
+                m_impl->extractAttributes(application, assertingParty.get(), relyingParty, *(*s), attributes);
             return;
         }
 
index ca7e3c2..d1c8d58 100644 (file)
-/*\r
- *  Copyright 2001-2009 Internet2\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *     http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/**\r
- * AbstractHandler.cpp\r
- *\r
- * Base class for handlers based on a DOMPropertySet.\r
- */\r
-\r
-#include "internal.h"\r
-#include "exceptions.h"\r
-#include "Application.h"\r
-#include "ServiceProvider.h"\r
-#include "SPRequest.h"\r
-#include "handler/AbstractHandler.h"\r
-#include "handler/LogoutHandler.h"\r
-#include "remoting/ListenerService.h"\r
-#include "util/CGIParser.h"\r
-#include "util/SPConstants.h"\r
-#include "util/TemplateParameters.h"\r
-\r
-#include <vector>\r
-#include <fstream>\r
-#include <xmltooling/XMLToolingConfig.h>\r
-#include <xmltooling/util/PathResolver.h>\r
-#include <xmltooling/util/URLEncoder.h>\r
-\r
-\r
-#ifndef SHIBSP_LITE\r
-# include <saml/exceptions.h>\r
-# include <saml/SAMLConfig.h>\r
-# include <saml/binding/SAMLArtifact.h>\r
-# include <saml/saml1/core/Protocols.h>\r
-# include <saml/saml2/core/Protocols.h>\r
-# include <saml/saml2/metadata/Metadata.h>\r
-# include <saml/saml2/metadata/MetadataCredentialCriteria.h>\r
-# include <saml/util/SAMLConstants.h>\r
-# include <xmltooling/security/Credential.h>\r
-# include <xmltooling/security/CredentialResolver.h>\r
-# include <xmltooling/util/StorageService.h>\r
-using namespace opensaml::saml2md;\r
-using namespace opensaml;\r
-#else\r
-# include "lite/SAMLConstants.h"\r
-#endif\r
-\r
-#include <xmltooling/XMLToolingConfig.h>\r
-#include <xmltooling/util/URLEncoder.h>\r
-\r
-using namespace shibsp;\r
-using namespace samlconstants;\r
-using namespace xmltooling;\r
-using namespace xercesc;\r
-using namespace std;\r
-\r
-namespace shibsp {\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML1ConsumerFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2ConsumerFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2ArtifactResolutionFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory ChainingLogoutInitiatorFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory LocalLogoutInitiatorFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2LogoutInitiatorFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2LogoutFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2NameIDMgmtFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory AssertionLookupFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory MetadataGeneratorFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory StatusHandlerFactory;\r
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SessionHandlerFactory;\r
-\r
-    void SHIBSP_DLLLOCAL generateRandomHex(std::string& buf, unsigned int len) {\r
-        static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};\r
-        int r;\r
-        unsigned char b1,b2;\r
-        buf.erase();\r
-        for (unsigned int i=0; i<len; i+=4) {\r
-            r = rand();\r
-            b1 = (0x00FF & r);\r
-            b2 = (0xFF00 & r)  >> 8;\r
-            buf += (DIGITS[(0xF0 & b1) >> 4 ]);\r
-            buf += (DIGITS[0x0F & b1]);\r
-            buf += (DIGITS[(0xF0 & b2) >> 4 ]);\r
-            buf += (DIGITS[0x0F & b2]);\r
-        }\r
-    }\r
-};\r
-\r
-void SHIBSP_API shibsp::registerHandlers()\r
-{\r
-    SPConfig& conf=SPConfig::getConfig();\r
-\r
-    conf.AssertionConsumerServiceManager.registerFactory(SAML1_PROFILE_BROWSER_ARTIFACT, SAML1ConsumerFactory);\r
-    conf.AssertionConsumerServiceManager.registerFactory(SAML1_PROFILE_BROWSER_POST, SAML1ConsumerFactory);\r
-    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2ConsumerFactory);\r
-    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2ConsumerFactory);\r
-    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2ConsumerFactory);\r
-    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_PAOS, SAML2ConsumerFactory);\r
-\r
-    conf.ArtifactResolutionServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2ArtifactResolutionFactory);\r
-\r
-    conf.HandlerManager.registerFactory(SAML20_BINDING_URI, AssertionLookupFactory);\r
-    conf.HandlerManager.registerFactory(METADATA_GENERATOR_HANDLER, MetadataGeneratorFactory);\r
-    conf.HandlerManager.registerFactory(STATUS_HANDLER, StatusHandlerFactory);\r
-    conf.HandlerManager.registerFactory(SESSION_HANDLER, SessionHandlerFactory);\r
-\r
-    conf.LogoutInitiatorManager.registerFactory(CHAINING_LOGOUT_INITIATOR, ChainingLogoutInitiatorFactory);\r
-    conf.LogoutInitiatorManager.registerFactory(LOCAL_LOGOUT_INITIATOR, LocalLogoutInitiatorFactory);\r
-    conf.LogoutInitiatorManager.registerFactory(SAML2_LOGOUT_INITIATOR, SAML2LogoutInitiatorFactory);\r
-    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2LogoutFactory);\r
-    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_REDIRECT, SAML2LogoutFactory);\r
-    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2LogoutFactory);\r
-    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2LogoutFactory);\r
-    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2LogoutFactory);\r
-\r
-    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2NameIDMgmtFactory);\r
-    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_REDIRECT, SAML2NameIDMgmtFactory);\r
-    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2NameIDMgmtFactory);\r
-    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2NameIDMgmtFactory);\r
-    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2NameIDMgmtFactory);\r
-}\r
-\r
-Handler::Handler()\r
-{\r
-}\r
-\r
-Handler::~Handler()\r
-{\r
-}\r
-\r
-AbstractHandler::AbstractHandler(\r
-    const DOMElement* e, Category& log, DOMNodeFilter* filter, const map<string,string>* remapper\r
-    ) : m_log(log), m_configNS(shibspconstants::SHIB2SPCONFIG_NS) {\r
-    load(e,NULL,filter,remapper);\r
-}\r
-\r
-AbstractHandler::~AbstractHandler()\r
-{\r
-}\r
-\r
-#ifndef SHIBSP_LITE\r
-\r
-const char* Handler::getType() const\r
-{\r
-    return getString("type").second;\r
-}\r
-\r
-void AbstractHandler::checkError(const XMLObject* response, const saml2md::RoleDescriptor* role) const\r
-{\r
-    const saml2p::StatusResponseType* r2 = dynamic_cast<const saml2p::StatusResponseType*>(response);\r
-    if (r2) {\r
-        const saml2p::Status* status = r2->getStatus();\r
-        if (status) {\r
-            const saml2p::StatusCode* sc = status->getStatusCode();\r
-            const XMLCh* code = sc ? sc->getValue() : NULL;\r
-            if (code && !XMLString::equals(code,saml2p::StatusCode::SUCCESS)) {\r
-                FatalProfileException ex("SAML response contained an error.");\r
-                annotateException(&ex, role, status);   // throws it\r
-            }\r
-        }\r
-    }\r
-\r
-    const saml1p::Response* r1 = dynamic_cast<const saml1p::Response*>(response);\r
-    if (r1) {\r
-        const saml1p::Status* status = r1->getStatus();\r
-        if (status) {\r
-            const saml1p::StatusCode* sc = status->getStatusCode();\r
-            const xmltooling::QName* code = sc ? sc->getValue() : NULL;\r
-            if (code && *code != saml1p::StatusCode::SUCCESS) {\r
-                FatalProfileException ex("SAML response contained an error.");\r
-                ex.addProperty("statusCode", code->toString().c_str());\r
-                if (sc->getStatusCode()) {\r
-                    code = sc->getStatusCode()->getValue();\r
-                    if (code)\r
-                        ex.addProperty("statusCode2", code->toString().c_str());\r
-                }\r
-                if (status->getStatusMessage()) {\r
-                    auto_ptr_char msg(status->getStatusMessage()->getMessage());\r
-                    if (msg.get() && *msg.get())\r
-                        ex.addProperty("statusMessage", msg.get());\r
-                }\r
-                ex.raise();\r
-            }\r
-        }\r
-    }\r
-}\r
-\r
-void AbstractHandler::fillStatus(saml2p::StatusResponseType& response, const XMLCh* code, const XMLCh* subcode, const char* msg) const\r
-{\r
-    saml2p::Status* status = saml2p::StatusBuilder::buildStatus();\r
-    saml2p::StatusCode* scode = saml2p::StatusCodeBuilder::buildStatusCode();\r
-    status->setStatusCode(scode);\r
-    scode->setValue(code);\r
-    if (subcode) {\r
-        saml2p::StatusCode* ssubcode = saml2p::StatusCodeBuilder::buildStatusCode();\r
-        scode->setStatusCode(ssubcode);\r
-        ssubcode->setValue(subcode);\r
-    }\r
-    if (msg) {\r
-        pair<bool,bool> flag = getBool("detailedErrors", m_configNS.get());\r
-        auto_ptr_XMLCh widemsg((flag.first && flag.second) ? msg : "Error processing request.");\r
-        saml2p::StatusMessage* sm = saml2p::StatusMessageBuilder::buildStatusMessage();\r
-        status->setStatusMessage(sm);\r
-        sm->setMessage(widemsg.get());\r
-    }\r
-    response.setStatus(status);\r
-}\r
-\r
-long AbstractHandler::sendMessage(\r
-    const MessageEncoder& encoder,\r
-    XMLObject* msg,\r
-    const char* relayState,\r
-    const char* destination,\r
-    const saml2md::RoleDescriptor* role,\r
-    const Application& application,\r
-    HTTPResponse& httpResponse,\r
-    bool signIfPossible\r
-    ) const\r
-{\r
-    const EntityDescriptor* entity = role ? dynamic_cast<const EntityDescriptor*>(role->getParent()) : NULL;\r
-    const PropertySet* relyingParty = application.getRelyingParty(entity);\r
-    pair<bool,const char*> flag = signIfPossible ? make_pair(true,(const char*)"true") : relyingParty->getString("signing");\r
-    if (role && flag.first &&\r
-        (!strcmp(flag.second, "true") ||\r
-            (encoder.isUserAgentPresent() && !strcmp(flag.second, "front")) ||\r
-            (!encoder.isUserAgentPresent() && !strcmp(flag.second, "back")))) {\r
-        CredentialResolver* credResolver=application.getCredentialResolver();\r
-        if (credResolver) {\r
-            Locker credLocker(credResolver);\r
-            const Credential* cred = NULL;\r
-            pair<bool,const char*> keyName = relyingParty->getString("keyName");\r
-            pair<bool,const XMLCh*> sigalg = relyingParty->getXMLString("signingAlg");\r
-            if (role) {\r
-                MetadataCredentialCriteria mcc(*role);\r
-                mcc.setUsage(Credential::SIGNING_CREDENTIAL);\r
-                if (keyName.first)\r
-                    mcc.getKeyNames().insert(keyName.second);\r
-                if (sigalg.first)\r
-                    mcc.setXMLAlgorithm(sigalg.second);\r
-                cred = credResolver->resolve(&mcc);\r
-            }\r
-            else {\r
-                CredentialCriteria cc;\r
-                cc.setUsage(Credential::SIGNING_CREDENTIAL);\r
-                if (keyName.first)\r
-                    cc.getKeyNames().insert(keyName.second);\r
-                if (sigalg.first)\r
-                    cc.setXMLAlgorithm(sigalg.second);\r
-                cred = credResolver->resolve(&cc);\r
-            }\r
-            if (cred) {\r
-                // Signed request.\r
-                return encoder.encode(\r
-                    httpResponse,\r
-                    msg,\r
-                    destination,\r
-                    entity,\r
-                    relayState,\r
-                    &application,\r
-                    cred,\r
-                    sigalg.second,\r
-                    relyingParty->getXMLString("digestAlg").second\r
-                    );\r
-            }\r
-            else {\r
-                m_log.warn("no signing credential resolved, leaving message unsigned");\r
-            }\r
-        }\r
-        else {\r
-            m_log.warn("no credential resolver installed, leaving message unsigned");\r
-        }\r
-    }\r
-\r
-    // Unsigned request.\r
-    return encoder.encode(httpResponse, msg, destination, entity, relayState, &application);\r
-}\r
-\r
-#endif\r
-\r
-void AbstractHandler::preserveRelayState(const Application& application, HTTPResponse& response, string& relayState) const\r
-{\r
-    if (relayState.empty())\r
-        return;\r
-\r
-    // No setting means just pass it by value.\r
-    pair<bool,const char*> mech=getString("relayState");\r
-    if (!mech.first || !mech.second || !*mech.second)\r
-        return;\r
-\r
-    if (!strcmp(mech.second, "cookie")) {\r
-        // Here we store the state in a cookie and send a fixed\r
-        // value so we can recognize it on the way back.\r
-        if (relayState.find("cookie:") != 0) {\r
-            const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();\r
-            pair<string,const char*> shib_cookie=application.getCookieNameProps("_shibstate_");\r
-            string stateval = urlenc->encode(relayState.c_str()) + shib_cookie.second;\r
-            // Generate a random key for the cookie name instead of the fixed name.\r
-            string rsKey;\r
-            generateRandomHex(rsKey,5);\r
-            shib_cookie.first = "_shibstate_" + rsKey;\r
-            response.setCookie(shib_cookie.first.c_str(),stateval.c_str());\r
-            relayState = "cookie:" + rsKey;\r
-        }\r
-    }\r
-    else if (strstr(mech.second,"ss:")==mech.second) {\r
-        if (relayState.find("ss:") != 0) {\r
-            mech.second+=3;\r
-            if (*mech.second) {\r
-                if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {\r
-#ifndef SHIBSP_LITE\r
-                    StorageService* storage = application.getServiceProvider().getStorageService(mech.second);\r
-                    if (storage) {\r
-                        string rsKey;\r
-                        generateRandomHex(rsKey,5);\r
-                        if (!storage->createString("RelayState", rsKey.c_str(), relayState.c_str(), time(NULL) + 600))\r
-                            throw IOException("Attempted to insert duplicate storage key.");\r
-                        relayState = string(mech.second-3) + ':' + rsKey;\r
-                    }\r
-                    else {\r
-                        m_log.error("Storage-backed RelayState with invalid StorageService ID (%s)", mech.second);\r
-                        relayState.erase();\r
-                    }\r
-#endif\r
-                }\r
-                else if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {\r
-                    DDF out,in = DDF("set::RelayState").structure();\r
-                    in.addmember("id").string(mech.second);\r
-                    in.addmember("value").unsafe_string(relayState.c_str());\r
-                    DDFJanitor jin(in),jout(out);\r
-                    out = application.getServiceProvider().getListenerService()->send(in);\r
-                    if (!out.isstring())\r
-                        throw IOException("StorageService-backed RelayState mechanism did not return a state key.");\r
-                    relayState = string(mech.second-3) + ':' + out.string();\r
-                }\r
-            }\r
-        }\r
-    }\r
-    else\r
-        throw ConfigurationException("Unsupported relayState mechanism ($1).", params(1,mech.second));\r
-}\r
-\r
-void AbstractHandler::recoverRelayState(\r
-    const Application& application, const HTTPRequest& request, HTTPResponse& response, string& relayState, bool clear\r
-    ) const\r
-{\r
-    SPConfig& conf = SPConfig::getConfig();\r
-\r
-    // Look for StorageService-backed state of the form "ss:SSID:key".\r
-    const char* state = relayState.c_str();\r
-    if (strstr(state,"ss:")==state) {\r
-        state += 3;\r
-        const char* key = strchr(state,':');\r
-        if (key) {\r
-            string ssid = relayState.substr(3, key - state);\r
-            key++;\r
-            if (!ssid.empty() && *key) {\r
-                if (conf.isEnabled(SPConfig::OutOfProcess)) {\r
-#ifndef SHIBSP_LITE\r
-                    StorageService* storage = conf.getServiceProvider()->getStorageService(ssid.c_str());\r
-                    if (storage) {\r
-                        ssid = key;\r
-                        if (storage->readString("RelayState",ssid.c_str(),&relayState)>0) {\r
-                            if (clear)\r
-                                storage->deleteString("RelayState",ssid.c_str());\r
-                            return;\r
-                        }\r
-                        else\r
-                            relayState.erase();\r
-                    }\r
-                    else {\r
-                        m_log.error("Storage-backed RelayState with invalid StorageService ID (%s)", ssid.c_str());\r
-                        relayState.erase();\r
-                    }\r
-#endif\r
-                }\r
-                else if (conf.isEnabled(SPConfig::InProcess)) {\r
-                    DDF out,in = DDF("get::RelayState").structure();\r
-                    in.addmember("id").string(ssid.c_str());\r
-                    in.addmember("key").string(key);\r
-                    in.addmember("clear").integer(clear ? 1 : 0);\r
-                    DDFJanitor jin(in),jout(out);\r
-                    out = application.getServiceProvider().getListenerService()->send(in);\r
-                    if (!out.isstring()) {\r
-                        m_log.error("StorageService-backed RelayState mechanism did not return a state value.");\r
-                        relayState.erase();\r
-                    }\r
-                    else {\r
-                        relayState = out.string();\r
-                        return;\r
-                    }\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    // Look for cookie-backed state of the form "cookie:key".\r
-    if (strstr(state,"cookie:")==state) {\r
-        state += 7;\r
-        if (*state) {\r
-            // Pull the value from the "relay state" cookie.\r
-            pair<string,const char*> relay_cookie = application.getCookieNameProps("_shibstate_");\r
-            relay_cookie.first = string("_shibstate_") + state;\r
-            state = request.getCookie(relay_cookie.first.c_str());\r
-            if (state && *state) {\r
-                // URL-decode the value.\r
-                char* rscopy=strdup(state);\r
-                XMLToolingConfig::getConfig().getURLEncoder()->decode(rscopy);\r
-                relayState = rscopy;\r
-                free(rscopy);\r
-\r
-                if (clear) {\r
-                    string exp(relay_cookie.second);\r
-                    exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";\r
-                    response.setCookie(relay_cookie.first.c_str(), exp.c_str());\r
-                }\r
-                return;\r
-            }\r
-        }\r
-\r
-        relayState.erase();\r
-    }\r
-\r
-    // Check for "default" value (or the old "cookie" value that might come from stale bookmarks).\r
-    if (relayState.empty() || relayState == "default" || relayState == "cookie") {\r
-        pair<bool,const char*> homeURL=application.getString("homeURL");\r
-        if (homeURL.first)\r
-            relayState=homeURL.second;\r
-        else {\r
-            // Compute a URL to the root of the site.\r
-            int port = request.getPort();\r
-            const char* scheme = request.getScheme();\r
-            relayState = string(scheme) + "://" + request.getHostname();\r
-            if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) {\r
-                ostringstream portstr;\r
-                portstr << port;\r
-                relayState += ":" + portstr.str();\r
-            }\r
-            relayState += '/';\r
-        }\r
-    }\r
-}\r
-\r
-void AbstractHandler::preservePostData(\r
-    const Application& application, const HTTPRequest& request, HTTPResponse& response, const char* relayState\r
-    ) const\r
-{\r
-#ifdef HAVE_STRCASECMP\r
-    if (strcasecmp(request.getMethod(), "POST")) return;\r
-#else\r
-    if (stricmp(request.getMethod(), "POST")) return;\r
-#endif\r
-\r
-    // No specs mean no save.\r
-    const PropertySet* props=application.getPropertySet("Sessions");\r
-    pair<bool,const char*> mech = props->getString("postData");\r
-    if (!mech.first) {\r
-        m_log.info("postData property not supplied, form data will not be preserved across SSO");\r
-        return;\r
-    }\r
-\r
-    DDF postData = getPostData(application, request);\r
-    if (postData.isnull())\r
-        return;\r
-\r
-    if (strstr(mech.second,"ss:") == mech.second) {\r
-        mech.second+=3;\r
-        if (!*mech.second) {\r
-            postData.destroy();\r
-            throw ConfigurationException("Unsupported postData mechanism ($1).", params(1, mech.second - 3));\r
-        }\r
-\r
-        string postkey;\r
-        if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {\r
-            DDFJanitor postjan(postData);\r
-#ifndef SHIBSP_LITE\r
-            StorageService* storage = application.getServiceProvider().getStorageService(mech.second);\r
-            if (storage) {\r
-                // Use a random key\r
-                string rsKey;\r
-                SAMLConfig::getConfig().generateRandomBytes(rsKey,20);\r
-                rsKey = SAMLArtifact::toHex(rsKey);\r
-                ostringstream out;\r
-                out << postData;\r
-                if (!storage->createString("PostData", rsKey.c_str(), out.str().c_str(), time(NULL) + 600))\r
-                    throw IOException("Attempted to insert duplicate storage key.");\r
-                postkey = string(mech.second-3) + ':' + rsKey;\r
-            }\r
-            else {\r
-                m_log.error("storage-backed PostData mechanism with invalid StorageService ID (%s)", mech.second);\r
-            }\r
-#endif\r
-        }\r
-        else if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {\r
-            DDF out,in = DDF("set::PostData").structure();\r
-            DDFJanitor jin(in),jout(out);\r
-            in.addmember("id").string(mech.second);\r
-            in.add(postData);\r
-            out = application.getServiceProvider().getListenerService()->send(in);\r
-            if (!out.isstring())\r
-                throw IOException("StorageService-backed PostData mechanism did not return a state key.");\r
-            postkey = string(mech.second-3) + ':' + out.string();\r
-        }\r
-\r
-        // Set a cookie with key info.\r
-        pair<string,const char*> shib_cookie = getPostCookieNameProps(application, relayState);\r
-        postkey += shib_cookie.second;\r
-        response.setCookie(shib_cookie.first.c_str(), postkey.c_str());\r
-    }\r
-    else {\r
-        postData.destroy();\r
-        throw ConfigurationException("Unsupported postData mechanism ($1).", params(1,mech.second));\r
-    }\r
-}\r
-\r
-DDF AbstractHandler::recoverPostData(\r
-    const Application& application, const HTTPRequest& request, HTTPResponse& response, const char* relayState\r
-    ) const\r
-{\r
-    // First we need the post recovery cookie.\r
-    pair<string,const char*> shib_cookie = getPostCookieNameProps(application, relayState);\r
-    const char* cookie = request.getCookie(shib_cookie.first.c_str());\r
-    if (!cookie || !*cookie)\r
-        return DDF();\r
-\r
-    // Clear the cookie.\r
-    string exp(shib_cookie.second);\r
-    exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";\r
-    response.setCookie(shib_cookie.first.c_str(), exp.c_str());\r
-\r
-    // Look for StorageService-backed state of the form "ss:SSID:key".\r
-    const char* state = cookie;\r
-    if (strstr(state, "ss:") == state) {\r
-        state += 3;\r
-        const char* key = strchr(state, ':');\r
-        if (key) {\r
-            string ssid = string(cookie).substr(3, key - state);\r
-            key++;\r
-            if (!ssid.empty() && *key) {\r
-                SPConfig& conf = SPConfig::getConfig();\r
-                if (conf.isEnabled(SPConfig::OutOfProcess)) {\r
-#ifndef SHIBSP_LITE\r
-                    StorageService* storage = conf.getServiceProvider()->getStorageService(ssid.c_str());\r
-                    if (storage) {\r
-                        if (storage->readString("PostData", key, &ssid) > 0) {\r
-                            storage->deleteString("PostData", key);\r
-                            istringstream inret(ssid);\r
-                            DDF ret;\r
-                            inret >> ret;\r
-                            return ret;\r
-                        }\r
-                        else {\r
-                            m_log.error("failed to recover form post data using key (%s)", key);\r
-                        }\r
-                    }\r
-                    else {\r
-                        m_log.error("storage-backed PostData with invalid StorageService ID (%s)", ssid.c_str());\r
-                    }\r
-#endif\r
-                }\r
-                else if (conf.isEnabled(SPConfig::InProcess)) {\r
-                    DDF in = DDF("get::PostData").structure();\r
-                    DDFJanitor jin(in);\r
-                    in.addmember("id").string(ssid.c_str());\r
-                    in.addmember("key").string(key);\r
-                    DDF out = application.getServiceProvider().getListenerService()->send(in);\r
-                    if (out.islist())\r
-                        return out;\r
-                    out.destroy();\r
-                    m_log.error("storageService-backed PostData mechanism did not return preserved data.");\r
-                }\r
-            }\r
-        }\r
-    }\r
-    return DDF();\r
-}\r
-\r
-long AbstractHandler::sendPostResponse(\r
-    const Application& application, HTTPResponse& httpResponse, const char* url, DDF& postData\r
-    ) const\r
-{\r
-    HTTPResponse::sanitizeURL(url);\r
-\r
-    const PropertySet* props=application.getPropertySet("Sessions");\r
-    pair<bool,const char*> postTemplate = props->getString("postTemplate");\r
-    if (!postTemplate.first)\r
-        throw ConfigurationException("Missing postTemplate property, unable to recreate form post.");\r
-\r
-    string fname(postTemplate.second);\r
-    ifstream infile(XMLToolingConfig::getConfig().getPathResolver()->resolve(fname, PathResolver::XMLTOOLING_CFG_FILE).c_str());\r
-    if (!infile)\r
-        throw ConfigurationException("Unable to access HTML template ($1).", params(1, fname.c_str()));\r
-    TemplateParameters respParam;\r
-    respParam.m_map["action"] = url;\r
-\r
-    // Load the parameters into objects for the template.\r
-    multimap<string,string>& collection = respParam.m_collectionMap["PostedData"];\r
-    DDF param = postData.first();\r
-    while (!param.isnull()) {\r
-        collection.insert(pair<const string,string>(param.name(), (param.string() ? param.string() : "")));\r
-        param = postData.next();\r
-    }\r
-\r
-    stringstream str;\r
-    XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, respParam);\r
-\r
-    pair<bool,bool> postExpire = props->getBool("postExpire");\r
-\r
-    httpResponse.setContentType("text/html");\r
-    if (!postExpire.first || postExpire.second) {\r
-        httpResponse.setResponseHeader("Expires", "01-Jan-1997 12:00:00 GMT");\r
-        httpResponse.setResponseHeader("Cache-Control", "no-cache, no-store, must-revalidate, private");\r
-        httpResponse.setResponseHeader("Pragma", "no-cache");\r
-    }\r
-    return httpResponse.sendResponse(str);\r
-}\r
-\r
-pair<string,const char*> AbstractHandler::getPostCookieNameProps(const Application& app, const char* relayState) const\r
-{\r
-    // Decorates the name of the cookie with the relay state key, if any.\r
-    // Doing so gives a better assurance that the recovered data really\r
-    // belongs to the relayed request.\r
-    pair<string,const char*> shib_cookie=app.getCookieNameProps("_shibpost_");\r
-    if (strstr(relayState, "cookie:") == relayState) {\r
-        shib_cookie.first = string("_shibpost_") + (relayState + 7);\r
-    }\r
-    else if (strstr(relayState, "ss:") == relayState) {\r
-        const char* pch = strchr(relayState + 3, ':');\r
-        if (pch)\r
-            shib_cookie.first = string("_shibpost_") + (pch + 1);\r
-    }\r
-    return shib_cookie;\r
-}\r
-\r
-DDF AbstractHandler::getPostData(const Application& application, const HTTPRequest& request) const\r
-{\r
-    string contentType = request.getContentType();\r
-    if (contentType.compare("application/x-www-form-urlencoded") == 0) {\r
-        const PropertySet* props=application.getPropertySet("Sessions");\r
-        pair<bool,unsigned int> plimit = props->getUnsignedInt("postLimit");\r
-        if (!plimit.first)\r
-            plimit.second = 1024 * 1024;\r
-        if (plimit.second == 0 || request.getContentLength() <= plimit.second) {\r
-            CGIParser cgi(request);\r
-            pair<CGIParser::walker,CGIParser::walker> params = cgi.getParameters(NULL);\r
-            if (params.first == params.second)\r
-                return DDF("parameters").list();\r
-            DDF child;\r
-            DDF ret = DDF("parameters").list();\r
-            for (; params.first != params.second; ++params.first) {\r
-                if (!params.first->first.empty()) {\r
-                    child = DDF(params.first->first.c_str()).unsafe_string(params.first->second);\r
-                    ret.add(child);\r
-                }\r
-            }\r
-            return ret;\r
-        }\r
-        else {\r
-            m_log.warn("POST limit exceeded, ignoring %d bytes of posted data", request.getContentLength());\r
-        }\r
-    }\r
-    else {\r
-        m_log.info("ignoring POST data with non-standard encoding (%s)", contentType.c_str());\r
-    }\r
-    return DDF();\r
-}\r
+/*
+ *  Copyright 2001-2009 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.
+ */
+
+/**
+ * AbstractHandler.cpp
+ *
+ * Base class for handlers based on a DOMPropertySet.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "Application.h"
+#include "ServiceProvider.h"
+#include "SPRequest.h"
+#include "handler/AbstractHandler.h"
+#include "handler/LogoutHandler.h"
+#include "remoting/ListenerService.h"
+#include "util/CGIParser.h"
+#include "util/SPConstants.h"
+#include "util/TemplateParameters.h"
+
+#include <vector>
+#include <fstream>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/PathResolver.h>
+#include <xmltooling/util/URLEncoder.h>
+
+
+#ifndef SHIBSP_LITE
+# include <saml/exceptions.h>
+# include <saml/SAMLConfig.h>
+# include <saml/binding/SAMLArtifact.h>
+# include <saml/saml1/core/Protocols.h>
+# include <saml/saml2/core/Protocols.h>
+# include <saml/saml2/metadata/Metadata.h>
+# include <saml/saml2/metadata/MetadataCredentialCriteria.h>
+# include <saml/util/SAMLConstants.h>
+# include <xmltooling/security/Credential.h>
+# include <xmltooling/security/CredentialResolver.h>
+# include <xmltooling/util/StorageService.h>
+using namespace opensaml::saml2md;
+using namespace opensaml;
+#else
+# include "lite/SAMLConstants.h"
+#endif
+
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/URLEncoder.h>
+
+using namespace shibsp;
+using namespace samlconstants;
+using namespace xmltooling;
+using namespace xercesc;
+using namespace std;
+
+namespace shibsp {
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML1ConsumerFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2ConsumerFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2ArtifactResolutionFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory ChainingLogoutInitiatorFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory LocalLogoutInitiatorFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2LogoutInitiatorFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2LogoutFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2NameIDMgmtFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory AssertionLookupFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory MetadataGeneratorFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory StatusHandlerFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SessionHandlerFactory;
+
+    void SHIBSP_DLLLOCAL generateRandomHex(std::string& buf, unsigned int len) {
+        static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+        int r;
+        unsigned char b1,b2;
+        buf.erase();
+        for (unsigned int i=0; i<len; i+=4) {
+            r = rand();
+            b1 = (0x00FF & r);
+            b2 = (0xFF00 & r)  >> 8;
+            buf += (DIGITS[(0xF0 & b1) >> 4 ]);
+            buf += (DIGITS[0x0F & b1]);
+            buf += (DIGITS[(0xF0 & b2) >> 4 ]);
+            buf += (DIGITS[0x0F & b2]);
+        }
+    }
+};
+
+void SHIBSP_API shibsp::registerHandlers()
+{
+    SPConfig& conf=SPConfig::getConfig();
+
+    conf.AssertionConsumerServiceManager.registerFactory(SAML1_PROFILE_BROWSER_ARTIFACT, SAML1ConsumerFactory);
+    conf.AssertionConsumerServiceManager.registerFactory(SAML1_PROFILE_BROWSER_POST, SAML1ConsumerFactory);
+    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2ConsumerFactory);
+    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2ConsumerFactory);
+    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2ConsumerFactory);
+    conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_PAOS, SAML2ConsumerFactory);
+
+    conf.ArtifactResolutionServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2ArtifactResolutionFactory);
+
+    conf.HandlerManager.registerFactory(SAML20_BINDING_URI, AssertionLookupFactory);
+    conf.HandlerManager.registerFactory(METADATA_GENERATOR_HANDLER, MetadataGeneratorFactory);
+    conf.HandlerManager.registerFactory(STATUS_HANDLER, StatusHandlerFactory);
+    conf.HandlerManager.registerFactory(SESSION_HANDLER, SessionHandlerFactory);
+
+    conf.LogoutInitiatorManager.registerFactory(CHAINING_LOGOUT_INITIATOR, ChainingLogoutInitiatorFactory);
+    conf.LogoutInitiatorManager.registerFactory(LOCAL_LOGOUT_INITIATOR, LocalLogoutInitiatorFactory);
+    conf.LogoutInitiatorManager.registerFactory(SAML2_LOGOUT_INITIATOR, SAML2LogoutInitiatorFactory);
+    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2LogoutFactory);
+    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_REDIRECT, SAML2LogoutFactory);
+    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2LogoutFactory);
+    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2LogoutFactory);
+    conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2LogoutFactory);
+
+    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2NameIDMgmtFactory);
+    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_REDIRECT, SAML2NameIDMgmtFactory);
+    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2NameIDMgmtFactory);
+    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2NameIDMgmtFactory);
+    conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2NameIDMgmtFactory);
+}
+
+Handler::Handler()
+{
+}
+
+Handler::~Handler()
+{
+}
+
+AbstractHandler::AbstractHandler(
+    const DOMElement* e, Category& log, DOMNodeFilter* filter, const map<string,string>* remapper
+    ) : m_log(log), m_configNS(shibspconstants::SHIB2SPCONFIG_NS) {
+    load(e,NULL,filter,remapper);
+}
+
+AbstractHandler::~AbstractHandler()
+{
+}
+
+#ifndef SHIBSP_LITE
+
+const char* Handler::getType() const
+{
+    return getString("type").second;
+}
+
+void AbstractHandler::checkError(const XMLObject* response, const saml2md::RoleDescriptor* role) const
+{
+    const saml2p::StatusResponseType* r2 = dynamic_cast<const saml2p::StatusResponseType*>(response);
+    if (r2) {
+        const saml2p::Status* status = r2->getStatus();
+        if (status) {
+            const saml2p::StatusCode* sc = status->getStatusCode();
+            const XMLCh* code = sc ? sc->getValue() : NULL;
+            if (code && !XMLString::equals(code,saml2p::StatusCode::SUCCESS)) {
+                FatalProfileException ex("SAML response contained an error.");
+                annotateException(&ex, role, status);   // throws it
+            }
+        }
+    }
+
+    const saml1p::Response* r1 = dynamic_cast<const saml1p::Response*>(response);
+    if (r1) {
+        const saml1p::Status* status = r1->getStatus();
+        if (status) {
+            const saml1p::StatusCode* sc = status->getStatusCode();
+            const xmltooling::QName* code = sc ? sc->getValue() : NULL;
+            if (code && *code != saml1p::StatusCode::SUCCESS) {
+                FatalProfileException ex("SAML response contained an error.");
+                ex.addProperty("statusCode", code->toString().c_str());
+                if (sc->getStatusCode()) {
+                    code = sc->getStatusCode()->getValue();
+                    if (code)
+                        ex.addProperty("statusCode2", code->toString().c_str());
+                }
+                if (status->getStatusMessage()) {
+                    auto_ptr_char msg(status->getStatusMessage()->getMessage());
+                    if (msg.get() && *msg.get())
+                        ex.addProperty("statusMessage", msg.get());
+                }
+                ex.raise();
+            }
+        }
+    }
+}
+
+void AbstractHandler::fillStatus(saml2p::StatusResponseType& response, const XMLCh* code, const XMLCh* subcode, const char* msg) const
+{
+    saml2p::Status* status = saml2p::StatusBuilder::buildStatus();
+    saml2p::StatusCode* scode = saml2p::StatusCodeBuilder::buildStatusCode();
+    status->setStatusCode(scode);
+    scode->setValue(code);
+    if (subcode) {
+        saml2p::StatusCode* ssubcode = saml2p::StatusCodeBuilder::buildStatusCode();
+        scode->setStatusCode(ssubcode);
+        ssubcode->setValue(subcode);
+    }
+    if (msg) {
+        pair<bool,bool> flag = getBool("detailedErrors", m_configNS.get());
+        auto_ptr_XMLCh widemsg((flag.first && flag.second) ? msg : "Error processing request.");
+        saml2p::StatusMessage* sm = saml2p::StatusMessageBuilder::buildStatusMessage();
+        status->setStatusMessage(sm);
+        sm->setMessage(widemsg.get());
+    }
+    response.setStatus(status);
+}
+
+long AbstractHandler::sendMessage(
+    const MessageEncoder& encoder,
+    XMLObject* msg,
+    const char* relayState,
+    const char* destination,
+    const saml2md::RoleDescriptor* role,
+    const Application& application,
+    HTTPResponse& httpResponse,
+    bool signIfPossible
+    ) const
+{
+    const EntityDescriptor* entity = role ? dynamic_cast<const EntityDescriptor*>(role->getParent()) : NULL;
+    const PropertySet* relyingParty = application.getRelyingParty(entity);
+    pair<bool,const char*> flag = signIfPossible ? make_pair(true,(const char*)"true") : relyingParty->getString("signing");
+    if (role && flag.first &&
+        (!strcmp(flag.second, "true") ||
+            (encoder.isUserAgentPresent() && !strcmp(flag.second, "front")) ||
+            (!encoder.isUserAgentPresent() && !strcmp(flag.second, "back")))) {
+        CredentialResolver* credResolver=application.getCredentialResolver();
+        if (credResolver) {
+            Locker credLocker(credResolver);
+            const Credential* cred = NULL;
+            pair<bool,const char*> keyName = relyingParty->getString("keyName");
+            pair<bool,const XMLCh*> sigalg = relyingParty->getXMLString("signingAlg");
+            if (role) {
+                MetadataCredentialCriteria mcc(*role);
+                mcc.setUsage(Credential::SIGNING_CREDENTIAL);
+                if (keyName.first)
+                    mcc.getKeyNames().insert(keyName.second);
+                if (sigalg.first)
+                    mcc.setXMLAlgorithm(sigalg.second);
+                cred = credResolver->resolve(&mcc);
+            }
+            else {
+                CredentialCriteria cc;
+                cc.setUsage(Credential::SIGNING_CREDENTIAL);
+                if (keyName.first)
+                    cc.getKeyNames().insert(keyName.second);
+                if (sigalg.first)
+                    cc.setXMLAlgorithm(sigalg.second);
+                cred = credResolver->resolve(&cc);
+            }
+            if (cred) {
+                // Signed request.
+                return encoder.encode(
+                    httpResponse,
+                    msg,
+                    destination,
+                    entity,
+                    relayState,
+                    &application,
+                    cred,
+                    sigalg.second,
+                    relyingParty->getXMLString("digestAlg").second
+                    );
+            }
+            else {
+                m_log.warn("no signing credential resolved, leaving message unsigned");
+            }
+        }
+        else {
+            m_log.warn("no credential resolver installed, leaving message unsigned");
+        }
+    }
+
+    // Unsigned request.
+    return encoder.encode(httpResponse, msg, destination, entity, relayState, &application);
+}
+
+#endif
+
+void AbstractHandler::preserveRelayState(const Application& application, HTTPResponse& response, string& relayState) const
+{
+    if (relayState.empty())
+        return;
+
+    // No setting means just pass it by value.
+    pair<bool,const char*> mech=getString("relayState");
+    if (!mech.first || !mech.second || !*mech.second)
+        return;
+
+    if (!strcmp(mech.second, "cookie")) {
+        // Here we store the state in a cookie and send a fixed
+        // value so we can recognize it on the way back.
+        if (relayState.find("cookie:") != 0) {
+            const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
+            pair<string,const char*> shib_cookie=application.getCookieNameProps("_shibstate_");
+            string stateval = urlenc->encode(relayState.c_str()) + shib_cookie.second;
+            // Generate a random key for the cookie name instead of the fixed name.
+            string rsKey;
+            generateRandomHex(rsKey,5);
+            shib_cookie.first = "_shibstate_" + rsKey;
+            response.setCookie(shib_cookie.first.c_str(),stateval.c_str());
+            relayState = "cookie:" + rsKey;
+        }
+    }
+    else if (strstr(mech.second,"ss:")==mech.second) {
+        if (relayState.find("ss:") != 0) {
+            mech.second+=3;
+            if (*mech.second) {
+                if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
+#ifndef SHIBSP_LITE
+                    StorageService* storage = application.getServiceProvider().getStorageService(mech.second);
+                    if (storage) {
+                        string rsKey;
+                        generateRandomHex(rsKey,5);
+                        if (!storage->createString("RelayState", rsKey.c_str(), relayState.c_str(), time(NULL) + 600))
+                            throw IOException("Attempted to insert duplicate storage key.");
+                        relayState = string(mech.second-3) + ':' + rsKey;
+                    }
+                    else {
+                        m_log.error("Storage-backed RelayState with invalid StorageService ID (%s)", mech.second);
+                        relayState.erase();
+                    }
+#endif
+                }
+                else if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
+                    DDF out,in = DDF("set::RelayState").structure();
+                    in.addmember("id").string(mech.second);
+                    in.addmember("value").unsafe_string(relayState.c_str());
+                    DDFJanitor jin(in),jout(out);
+                    out = application.getServiceProvider().getListenerService()->send(in);
+                    if (!out.isstring())
+                        throw IOException("StorageService-backed RelayState mechanism did not return a state key.");
+                    relayState = string(mech.second-3) + ':' + out.string();
+                }
+            }
+        }
+    }
+    else
+        throw ConfigurationException("Unsupported relayState mechanism ($1).", params(1,mech.second));
+}
+
+void AbstractHandler::recoverRelayState(
+    const Application& application, const HTTPRequest& request, HTTPResponse& response, string& relayState, bool clear
+    ) const
+{
+    SPConfig& conf = SPConfig::getConfig();
+
+    // Look for StorageService-backed state of the form "ss:SSID:key".
+    const char* state = relayState.c_str();
+    if (strstr(state,"ss:")==state) {
+        state += 3;
+        const char* key = strchr(state,':');
+        if (key) {
+            string ssid = relayState.substr(3, key - state);
+            key++;
+            if (!ssid.empty() && *key) {
+                if (conf.isEnabled(SPConfig::OutOfProcess)) {
+#ifndef SHIBSP_LITE
+                    StorageService* storage = conf.getServiceProvider()->getStorageService(ssid.c_str());
+                    if (storage) {
+                        ssid = key;
+                        if (storage->readString("RelayState",ssid.c_str(),&relayState)>0) {
+                            if (clear)
+                                storage->deleteString("RelayState",ssid.c_str());
+                            return;
+                        }
+                        else
+                            relayState.erase();
+                    }
+                    else {
+                        m_log.error("Storage-backed RelayState with invalid StorageService ID (%s)", ssid.c_str());
+                        relayState.erase();
+                    }
+#endif
+                }
+                else if (conf.isEnabled(SPConfig::InProcess)) {
+                    DDF out,in = DDF("get::RelayState").structure();
+                    in.addmember("id").string(ssid.c_str());
+                    in.addmember("key").string(key);
+                    in.addmember("clear").integer(clear ? 1 : 0);
+                    DDFJanitor jin(in),jout(out);
+                    out = application.getServiceProvider().getListenerService()->send(in);
+                    if (!out.isstring()) {
+                        m_log.error("StorageService-backed RelayState mechanism did not return a state value.");
+                        relayState.erase();
+                    }
+                    else {
+                        relayState = out.string();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    // Look for cookie-backed state of the form "cookie:key".
+    if (strstr(state,"cookie:")==state) {
+        state += 7;
+        if (*state) {
+            // Pull the value from the "relay state" cookie.
+            pair<string,const char*> relay_cookie = application.getCookieNameProps("_shibstate_");
+            relay_cookie.first = string("_shibstate_") + state;
+            state = request.getCookie(relay_cookie.first.c_str());
+            if (state && *state) {
+                // URL-decode the value.
+                char* rscopy=strdup(state);
+                XMLToolingConfig::getConfig().getURLEncoder()->decode(rscopy);
+                relayState = rscopy;
+                free(rscopy);
+
+                if (clear) {
+                    string exp(relay_cookie.second);
+                    exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT";
+                    response.setCookie(relay_cookie.first.c_str(), exp.c_str());
+                }
+                return;
+            }
+        }
+
+        relayState.erase();
+    }
+
+    // Check for "default" value (or the old "cookie" value that might come from stale bookmarks).
+    if (relayState.empty() || relayState == "default" || relayState == "cookie") {
+        pair<bool,const char*> homeURL=application.getString("homeURL");
+        if (homeURL.first)
+            relayState=homeURL.second;
+        else {
+            // Compute a URL to the root of the site.
+            int port = request.getPort();
+            const char* scheme = request.getScheme();
+            relayState = string(scheme) + "://" + request.getHostname();
+            if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) {
+                ostringstream portstr;
+                portstr << port;
+                relayState += ":" + portstr.str();
+            }
+            relayState += '/';
+        }
+    }
+}
+
+void AbstractHandler::preservePostData(
+    const Application& application, const HTTPRequest& request, HTTPResponse& response, const char* relayState
+    ) const
+{
+#ifdef HAVE_STRCASECMP
+    if (strcasecmp(request.getMethod(), "POST")) return;
+#else
+    if (stricmp(request.getMethod(), "POST")) return;
+#endif
+
+    // No specs mean no save.
+    const PropertySet* props=application.getPropertySet("Sessions");
+    pair<bool,const char*> mech = props->getString("postData");
+    if (!mech.first) {
+        m_log.info("postData property not supplied, form data will not be preserved across SSO");
+        return;
+    }
+
+    DDF postData = getPostData(application, request);
+    if (postData.isnull())
+        return;
+
+    if (strstr(mech.second,"ss:") == mech.second) {
+        mech.second+=3;
+        if (!*mech.second) {
+            postData.destroy();
+            throw ConfigurationException("Unsupported postData mechanism ($1).", params(1, mech.second - 3));
+        }
+
+        string postkey;
+        if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
+            DDFJanitor postjan(postData);
+#ifndef SHIBSP_LITE
+            StorageService* storage = application.getServiceProvider().getStorageService(mech.second);
+            if (storage) {
+                // Use a random key
+                string rsKey;
+                SAMLConfig::getConfig().generateRandomBytes(rsKey,20);
+                rsKey = SAMLArtifact::toHex(rsKey);
+                ostringstream out;
+                out << postData;
+                if (!storage->createString("PostData", rsKey.c_str(), out.str().c_str(), time(NULL) + 600))
+                    throw IOException("Attempted to insert duplicate storage key.");
+                postkey = string(mech.second-3) + ':' + rsKey;
+            }
+            else {
+                m_log.error("storage-backed PostData mechanism with invalid StorageService ID (%s)", mech.second);
+            }
+#endif
+        }
+        else if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
+            DDF out,in = DDF("set::PostData").structure();
+            DDFJanitor jin(in),jout(out);
+            in.addmember("id").string(mech.second);
+            in.add(postData);
+            out = application.getServiceProvider().getListenerService()->send(in);
+            if (!out.isstring())
+                throw IOException("StorageService-backed PostData mechanism did not return a state key.");
+            postkey = string(mech.second-3) + ':' + out.string();
+        }
+
+        // Set a cookie with key info.
+        pair<string,const char*> shib_cookie = getPostCookieNameProps(application, relayState);
+        postkey += shib_cookie.second;
+        response.setCookie(shib_cookie.first.c_str(), postkey.c_str());
+    }
+    else {
+        postData.destroy();
+        throw ConfigurationException("Unsupported postData mechanism ($1).", params(1,mech.second));
+    }
+}
+
+DDF AbstractHandler::recoverPostData(
+    const Application& application, const HTTPRequest& request, HTTPResponse& response, const char* relayState
+    ) const
+{
+    // First we need the post recovery cookie.
+    pair<string,const char*> shib_cookie = getPostCookieNameProps(application, relayState);
+    const char* cookie = request.getCookie(shib_cookie.first.c_str());
+    if (!cookie || !*cookie)
+        return DDF();
+
+    // Clear the cookie.
+    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());
+
+    // Look for StorageService-backed state of the form "ss:SSID:key".
+    const char* state = cookie;
+    if (strstr(state, "ss:") == state) {
+        state += 3;
+        const char* key = strchr(state, ':');
+        if (key) {
+            string ssid = string(cookie).substr(3, key - state);
+            key++;
+            if (!ssid.empty() && *key) {
+                SPConfig& conf = SPConfig::getConfig();
+                if (conf.isEnabled(SPConfig::OutOfProcess)) {
+#ifndef SHIBSP_LITE
+                    StorageService* storage = conf.getServiceProvider()->getStorageService(ssid.c_str());
+                    if (storage) {
+                        if (storage->readString("PostData", key, &ssid) > 0) {
+                            storage->deleteString("PostData", key);
+                            istringstream inret(ssid);
+                            DDF ret;
+                            inret >> ret;
+                            return ret;
+                        }
+                        else {
+                            m_log.error("failed to recover form post data using key (%s)", key);
+                        }
+                    }
+                    else {
+                        m_log.error("storage-backed PostData with invalid StorageService ID (%s)", ssid.c_str());
+                    }
+#endif
+                }
+                else if (conf.isEnabled(SPConfig::InProcess)) {
+                    DDF in = DDF("get::PostData").structure();
+                    DDFJanitor jin(in);
+                    in.addmember("id").string(ssid.c_str());
+                    in.addmember("key").string(key);
+                    DDF out = application.getServiceProvider().getListenerService()->send(in);
+                    if (out.islist())
+                        return out;
+                    out.destroy();
+                    m_log.error("storageService-backed PostData mechanism did not return preserved data.");
+                }
+            }
+        }
+    }
+    return DDF();
+}
+
+long AbstractHandler::sendPostResponse(
+    const Application& application, HTTPResponse& httpResponse, const char* url, DDF& postData
+    ) const
+{
+    HTTPResponse::sanitizeURL(url);
+
+    const PropertySet* props=application.getPropertySet("Sessions");
+    pair<bool,const char*> postTemplate = props->getString("postTemplate");
+    if (!postTemplate.first)
+        throw ConfigurationException("Missing postTemplate property, unable to recreate form post.");
+
+    string fname(postTemplate.second);
+    ifstream infile(XMLToolingConfig::getConfig().getPathResolver()->resolve(fname, PathResolver::XMLTOOLING_CFG_FILE).c_str());
+    if (!infile)
+        throw ConfigurationException("Unable to access HTML template ($1).", params(1, fname.c_str()));
+    TemplateParameters respParam;
+    respParam.m_map["action"] = url;
+
+    // Load the parameters into objects for the template.
+    multimap<string,string>& collection = respParam.m_collectionMap["PostedData"];
+    DDF param = postData.first();
+    while (!param.isnull()) {
+        collection.insert(pair<const string,string>(param.name(), (param.string() ? param.string() : "")));
+        param = postData.next();
+    }
+
+    stringstream str;
+    XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, respParam);
+
+    pair<bool,bool> postExpire = props->getBool("postExpire");
+
+    httpResponse.setContentType("text/html");
+    if (!postExpire.first || postExpire.second) {
+        httpResponse.setResponseHeader("Expires", "01-Jan-1997 12:00:00 GMT");
+        httpResponse.setResponseHeader("Cache-Control", "no-cache, no-store, must-revalidate, private");
+        httpResponse.setResponseHeader("Pragma", "no-cache");
+    }
+    return httpResponse.sendResponse(str);
+}
+
+pair<string,const char*> AbstractHandler::getPostCookieNameProps(const Application& app, const char* relayState) const
+{
+    // Decorates the name of the cookie with the relay state key, if any.
+    // Doing so gives a better assurance that the recovered data really
+    // belongs to the relayed request.
+    pair<string,const char*> shib_cookie=app.getCookieNameProps("_shibpost_");
+    if (strstr(relayState, "cookie:") == relayState) {
+        shib_cookie.first = string("_shibpost_") + (relayState + 7);
+    }
+    else if (strstr(relayState, "ss:") == relayState) {
+        const char* pch = strchr(relayState + 3, ':');
+        if (pch)
+            shib_cookie.first = string("_shibpost_") + (pch + 1);
+    }
+    return shib_cookie;
+}
+
+DDF AbstractHandler::getPostData(const Application& application, const HTTPRequest& request) const
+{
+    string contentType = request.getContentType();
+    if (contentType.compare("application/x-www-form-urlencoded") == 0) {
+        const PropertySet* props=application.getPropertySet("Sessions");
+        pair<bool,unsigned int> plimit = props->getUnsignedInt("postLimit");
+        if (!plimit.first)
+            plimit.second = 1024 * 1024;
+        if (plimit.second == 0 || request.getContentLength() <= plimit.second) {
+            CGIParser cgi(request);
+            pair<CGIParser::walker,CGIParser::walker> params = cgi.getParameters(NULL);
+            if (params.first == params.second)
+                return DDF("parameters").list();
+            DDF child;
+            DDF ret = DDF("parameters").list();
+            for (; params.first != params.second; ++params.first) {
+                if (!params.first->first.empty()) {
+                    child = DDF(params.first->first.c_str()).unsafe_string(params.first->second);
+                    ret.add(child);
+                }
+            }
+            return ret;
+        }
+        else {
+            m_log.warn("POST limit exceeded, ignoring %d bytes of posted data", request.getContentLength());
+        }
+    }
+    else {
+        m_log.info("ignoring POST data with non-standard encoding (%s)", contentType.c_str());
+    }
+    return DDF();
+}
index f88ba99..f5d4e5e 100644 (file)
@@ -234,25 +234,31 @@ const char* AssertionConsumerService::getType() const
 
 void AssertionConsumerService::generateMetadata(SPSSODescriptor& role, const char* handlerURL) const
 {
+    // Initial guess at index to use.
+    pair<bool,unsigned int> ix = pair<bool,unsigned int>(false,0);
+    if (!strncmp(handlerURL, "https", 5))
+        ix = getUnsignedInt("sslIndex", shibspconstants::ASCII_SHIB2SPCONFIG_NS);
+    if (!ix.first)
+        ix = getUnsignedInt("index");
+    if (!ix.first)
+        ix.second = 1;
+
+    // Find maximum index in use and go one higher.
+    const vector<saml2md::AssertionConsumerService*>& services = const_cast<const SPSSODescriptor&>(role).getAssertionConsumerServices();
+    if (!services.empty() && ix.second <= services.back()->getIndex().second)
+        ix.second = services.back()->getIndex().second + 1;
+
     const char* loc = getString("Location").second;
     string hurl(handlerURL);
     if (*loc != '/')
         hurl += '/';
     hurl += loc;
     auto_ptr_XMLCh widen(hurl.c_str());
+
     saml2md::AssertionConsumerService* ep = saml2md::AssertionConsumerServiceBuilder::buildAssertionConsumerService();
     ep->setLocation(widen.get());
     ep->setBinding(getXMLString("Binding").second);
-    if (!strncmp(handlerURL, "https", 5)) {
-       pair<bool,const XMLCh*> index = getXMLString("sslIndex", shibspconstants::ASCII_SHIB2SPCONFIG_NS);
-       if (index.first)
-               ep->setIndex(index.second);
-       else
-               ep->setIndex(getXMLString("index").second);
-    }
-    else {
-       ep->setIndex(getXMLString("index").second);
-    }
+    ep->setIndex(ix.second);
     role.getAssertionConsumerServices().push_back(ep);
 }
 
@@ -364,6 +370,9 @@ ResolutionContext* AssertionConsumerService::resolveAttributes(
             }
         }
     }
+    else {
+        m_log.warn("no AttributeExtractor plugin installed, check log during startup");
+    }
 
     try {
         AttributeResolver* resolver = application.getAttributeResolver();
index 6e609a3..bec9c01 100644 (file)
@@ -75,19 +75,42 @@ namespace shibsp {
         const char* getType() const {
             return "ArtifactResolutionService";
         }
+
+        void generateMetadata(SPSSODescriptor& role, const char* handlerURL) const {
+            // Initial guess at index to use.
+            pair<bool,unsigned int> ix = pair<bool,unsigned int>(false,0);
+            if (!strncmp(handlerURL, "https", 5))
+                ix = getUnsignedInt("sslIndex", shibspconstants::ASCII_SHIB2SPCONFIG_NS);
+            if (!ix.first)
+                ix = getUnsignedInt("index");
+            if (!ix.first)
+                ix.second = 1;
+
+            // Find maximum index in use and go one higher.
+            const vector<ArtifactResolutionService*>& services = const_cast<const SPSSODescriptor&>(role).getArtifactResolutionServices();
+            if (!services.empty() && ix.second <= services.back()->getIndex().second)
+                ix.second = services.back()->getIndex().second + 1;
+
+            const char* loc = getString("Location").second;
+            string hurl(handlerURL);
+            if (*loc != '/')
+                hurl += '/';
+            hurl += loc;
+            auto_ptr_XMLCh widen(hurl.c_str());
+
+            ArtifactResolutionService* ep = ArtifactResolutionServiceBuilder::buildArtifactResolutionService();
+            ep->setLocation(widen.get());
+            ep->setBinding(getXMLString("Binding").second);
+            ep->setIndex(ix.second);
+            role.getArtifactResolutionServices().push_back(ep);
+        }
 #endif
 
     private:
         pair<bool,long> processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const;
 #ifndef SHIBSP_LITE
-        pair<bool,long> samlError(
-            const Application& app,
-            const ArtifactResolve& request,
-            HTTPResponse& httpResponse,
-            const EntityDescriptor* recipient,
-            const XMLCh* code,
-            const XMLCh* subcode=NULL,
-            const char* msg=NULL
+        pair<bool,long> emptyResponse(
+            const Application& app, const ArtifactResolve& request, HTTPResponse& httpResponse, const EntityDescriptor* recipient
             ) const;
 
         MessageEncoder* m_encoder;
@@ -285,7 +308,7 @@ pair<bool,long> SAML2ArtifactResolution::processMessage(const Application& appli
     try {
         auto_ptr_char artifact(req->getArtifact() ? req->getArtifact()->getArtifact() : NULL);
         if (!artifact.get() || !*artifact.get())
-            return samlError(application, *req, httpResponse, entity, StatusCode::REQUESTER, NULL, "Request did not contain an artifact to resolve.");
+            return emptyResponse(application, *req, httpResponse, entity);
         auto_ptr_char issuer(policy.getIssuer() ? policy.getIssuer()->getName() : NULL);
 
         m_log.info("resolving artifact (%s) for (%s)", artifact.get(), issuer.get() ? issuer.get() : "unknown");
@@ -296,7 +319,7 @@ pair<bool,long> SAML2ArtifactResolution::processMessage(const Application& appli
 
         if (!policy.isAuthenticated()) {
             m_log.error("request for artifact was unauthenticated, purging the artifact mapping");
-            return samlError(application, *req, httpResponse, entity, StatusCode::REQUESTER, StatusCode::AUTHN_FAILED, "Unable to authenticate request.");
+            return emptyResponse(application, *req, httpResponse, entity);
         }
 
         m_log.debug("artifact resolved, preparing response");
@@ -315,9 +338,9 @@ pair<bool,long> SAML2ArtifactResolution::processMessage(const Application& appli
         return make_pair(true,ret);
     }
     catch (exception& ex) {
-        // Trap localized errors in a SAML Response.
-        m_log.error("error processing artifact request, returning SAML error: %s", ex.what());
-        return samlError(application, *req, httpResponse, entity, StatusCode::RESPONDER, NULL, ex.what());
+        // Trap localized errors.
+        m_log.error("error processing artifact request: %s", ex.what());
+        return emptyResponse(application, *req, httpResponse, entity);
     }
 #else
     return make_pair(false,0L);
@@ -325,21 +348,15 @@ pair<bool,long> SAML2ArtifactResolution::processMessage(const Application& appli
 }
 
 #ifndef SHIBSP_LITE
-pair<bool,long> SAML2ArtifactResolution::samlError(
-    const Application& app,
-    const ArtifactResolve& request,
-    HTTPResponse& httpResponse,
-    const EntityDescriptor* recipient,
-    const XMLCh* code,
-    const XMLCh* subcode,
-    const char* msg
+pair<bool,long> SAML2ArtifactResolution::emptyResponse(
+    const Application& app, const ArtifactResolve& request, HTTPResponse& httpResponse, const EntityDescriptor* recipient
     ) const
 {
     auto_ptr<ArtifactResponse> resp(ArtifactResponseBuilder::buildArtifactResponse());
     resp->setInResponseTo(request.getID());
     Issuer* me = IssuerBuilder::buildIssuer();
     me->setName(app.getRelyingParty(recipient)->getXMLString("entityID").second);
-    fillStatus(*resp.get(), code, subcode, msg);
+    fillStatus(*resp.get(), StatusCode::SUCCESS);
     long ret = m_encoder->encode(httpResponse, resp.get(), NULL);
     resp.release();  // freed by encoder
     return make_pair(true,ret);
index d6931ce..5f5379d 100644 (file)
@@ -284,7 +284,7 @@ pair<bool,long> SAML2Logout::doRequest(const Application& application, const HTT
                 worked2 = true;
             }
             catch (exception& ex) {
-                m_log.error("error removing session (%s): %s", session_id, ex.what());
+                m_log.error("error removing session (%s): %s", session_id.c_str(), ex.what());
             }
         }
         else {
index 24b8bfa..15d38c8 100644 (file)
@@ -40,9 +40,6 @@
 # include <saml/saml2/metadata/EndpointManager.h>
 # include <saml/saml2/metadata/Metadata.h>
 # include <saml/saml2/metadata/MetadataCredentialCriteria.h>
-# include <saml/signature/ContentReference.h>
-# include <xmltooling/security/Credential.h>
-# include <xmltooling/signature/Signature.h>
 using namespace opensaml::saml2;
 using namespace opensaml::saml2p;
 using namespace opensaml::saml2md;
@@ -361,24 +358,25 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
                     m_log.warn("IdP didn't respond to logout request");
                 ret = sendLogoutPage(application, httpRequest, httpResponse, "partial");
             }
-
-            // Check the status, looking for non-success or a partial logout code.
-            const StatusCode* sc = logoutResponse->getStatus() ? logoutResponse->getStatus()->getStatusCode() : NULL;
-            bool partial = (!sc || !XMLString::equals(sc->getValue(), StatusCode::SUCCESS));
-            if (!partial) {
-                // Success, but still need to check for partial.
-                partial = XMLString::equals(sc->getStatusCode()->getValue(), StatusCode::PARTIAL_LOGOUT);
-            }
-            delete logoutResponse;
-            if (partial)
-                ret = sendLogoutPage(application, httpRequest, httpResponse, "partial");
             else {
-                const char* returnloc = httpRequest.getParameter("return");
-                if (returnloc) {
-                    ret.second = httpResponse.sendRedirect(returnloc);
-                    ret.first = true;
+                // Check the status, looking for non-success or a partial logout code.
+                const StatusCode* sc = logoutResponse->getStatus() ? logoutResponse->getStatus()->getStatusCode() : NULL;
+                bool partial = (!sc || !XMLString::equals(sc->getValue(), StatusCode::SUCCESS));
+                if (!partial && sc->getStatusCode()) {
+                    // Success, but still need to check for partial.
+                    partial = XMLString::equals(sc->getStatusCode()->getValue(), StatusCode::PARTIAL_LOGOUT);
+                }
+                delete logoutResponse;
+                if (partial)
+                    ret = sendLogoutPage(application, httpRequest, httpResponse, "partial");
+                else {
+                    const char* returnloc = httpRequest.getParameter("return");
+                    if (returnloc) {
+                        ret.second = httpResponse.sendRedirect(returnloc);
+                        ret.first = true;
+                    }
+                    ret = sendLogoutPage(application, httpRequest, httpResponse, "global");
                 }
-                ret = sendLogoutPage(application, httpRequest, httpResponse, "global");
             }
 
             if (session) {
@@ -386,6 +384,7 @@ pair<bool,long> SAML2LogoutInitiator::doRequest(
                 session = NULL;
                 application.getServiceProvider().getSessionCache()->remove(application, httpRequest, &httpResponse);
             }
+
             return ret;
         }
 
@@ -461,49 +460,6 @@ LogoutRequest* SAML2LogoutInitiator::buildRequest(
         msg->setNameID(nameid->cloneNameID());
     }
 
-    if (!encoder) {
-        // No encoder being used, so sign for SOAP client manually.
-        flag = relyingParty->getString("signing");
-        if (flag.first && (!strcmp(flag.second, "true") || !strcmp(flag.second, "back"))) {
-            CredentialResolver* credResolver=application.getCredentialResolver();
-            if (credResolver) {
-                Locker credLocker(credResolver);
-                // Fill in criteria to use.
-                MetadataCredentialCriteria mcc(role);
-                mcc.setUsage(Credential::SIGNING_CREDENTIAL);
-                pair<bool,const char*> keyName = relyingParty->getString("keyName");
-                if (keyName.first)
-                    mcc.getKeyNames().insert(keyName.second);
-                pair<bool,const XMLCh*> sigalg = relyingParty->getXMLString("signingAlg");
-                if (sigalg.first)
-                    mcc.setXMLAlgorithm(sigalg.second);
-                const Credential* cred = credResolver->resolve(&mcc);
-                if (cred) {
-                    xmlsignature::Signature* sig = xmlsignature::SignatureBuilder::buildSignature();
-                    msg->setSignature(sig);
-                    if (sigalg.first)
-                        sig->setSignatureAlgorithm(sigalg.second);
-                    sigalg = relyingParty->getXMLString("digestAlg");
-                    if (sigalg.first) {
-                        ContentReference* cr = dynamic_cast<ContentReference*>(sig->getContentReference());
-                        if (cr)
-                            cr->setDigestAlgorithm(sigalg.second);
-                    }
-
-                    // Sign response while marshalling.
-                    vector<xmlsignature::Signature*> sigs(1,sig);
-                    msg->marshall((DOMDocument*)NULL,&sigs,cred);
-                }
-                else {
-                    m_log.warn("no signing credential resolved, leaving message unsigned");
-                }
-            }
-            else {
-                m_log.warn("no credential resolver installed, leaving message unsigned");
-            }
-        }
-    }
-
     return msg.release();
 }
 
index 1c0a7e3..85b65bb 100644 (file)
@@ -73,18 +73,47 @@ namespace shibsp {
 #ifndef SHIBSP_LITE
         void generateMetadata(SPSSODescriptor& role, const char* handlerURL) const {
             static const XMLCh LOCAL_NAME[] = UNICODE_LITERAL_17(D,i,s,c,o,v,e,r,y,R,e,s,p,o,n,s,e);
+
+            // Initial guess at index to use.
+            pair<bool,unsigned int> ix = getUnsignedInt("index");
+            if (!ix.first)
+                ix.second = 1;
+
+            // Find maximum index in use and go one higher.
+            if (role.getExtensions()) {
+                const vector<XMLObject*>& exts = const_cast<const Extensions*>(role.getExtensions())->getUnknownXMLObjects();
+                for (vector<XMLObject*>::const_reverse_iterator i = exts.rbegin(); i != exts.rend(); ++i) {
+                    if (XMLString::equals((*i)->getElementQName().getLocalPart(), LOCAL_NAME) &&
+                        XMLString::equals((*i)->getElementQName().getNamespaceURI(), m_discoNS.get())) {
+                        const AttributeExtensibleXMLObject* sub = dynamic_cast<const AttributeExtensibleXMLObject*>(*i);
+                        if (sub) {
+                            const XMLCh* val = sub->getAttribute(xmltooling::QName(NULL,IndexedEndpointType::INDEX_ATTRIB_NAME));
+                            if (val) {
+                                int maxindex = XMLString::parseInt(val);
+                                if (ix.second <= maxindex)
+                                    ix.second = maxindex + 1;
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
             const char* loc = getString("Location").second;
             string hurl(handlerURL);
             if (*loc != '/')
                 hurl += '/';
             hurl += loc;
             auto_ptr_XMLCh widen(hurl.c_str());
+
+            ostringstream os;
+            os << ix.second;
+            auto_ptr_XMLCh widen2(os.str().c_str());
+
             ElementProxy* ep = new AnyElementImpl(m_discoNS.get(), LOCAL_NAME);
             ep->setAttribute(xmltooling::QName(NULL,EndpointType::LOCATION_ATTRIB_NAME), widen.get());
             ep->setAttribute(xmltooling::QName(NULL,EndpointType::BINDING_ATTRIB_NAME), m_discoNS.get());
-            pair<bool,const XMLCh*> ix = getXMLString("index");
-            ep->setAttribute(xmltooling::QName(NULL,IndexedEndpointType::INDEX_ATTRIB_NAME), ix.first ? ix.second : xmlconstants::XML_ONE);
-
+            ep->setAttribute(xmltooling::QName(NULL,IndexedEndpointType::INDEX_ATTRIB_NAME), widen2.get());
             Extensions* ext = role.getExtensions();
             if (!ext) {
                 ext = ExtensionsBuilder::buildExtensions();
index 05f3ef4..ab4dce6 100644 (file)
-/*\r
- *  Copyright 2001-2009 Internet2\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *     http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/**\r
- * XMLServiceProvider.cpp\r
- *\r
- * XML-based SP configuration and mgmt.\r
- */\r
-\r
-#include "internal.h"\r
-#include "exceptions.h"\r
-#include "version.h"\r
-#include "AccessControl.h"\r
-#include "Application.h"\r
-#include "RequestMapper.h"\r
-#include "ServiceProvider.h"\r
-#include "SessionCache.h"\r
-#include "SPConfig.h"\r
-#include "SPRequest.h"\r
-#include "handler/SessionInitiator.h"\r
-#include "remoting/ListenerService.h"\r
-#include "util/DOMPropertySet.h"\r
-#include "util/SPConstants.h"\r
-\r
-#if defined(XMLTOOLING_LOG4SHIB)\r
-# include <log4shib/PropertyConfigurator.hh>\r
-#elif defined(XMLTOOLING_LOG4CPP)\r
-# include <log4cpp/PropertyConfigurator.hh>\r
-#else\r
-# error "Supported logging library not available."\r
-#endif\r
-#include <algorithm>\r
-#include <xercesc/util/XMLUniDefs.hpp>\r
-#include <xmltooling/XMLToolingConfig.h>\r
-#include <xmltooling/version.h>\r
-#include <xmltooling/util/NDC.h>\r
-#include <xmltooling/util/ReloadableXMLFile.h>\r
-#include <xmltooling/util/TemplateEngine.h>\r
-#include <xmltooling/util/XMLHelper.h>\r
-\r
-#ifndef SHIBSP_LITE\r
-# include "TransactionLog.h"\r
-# include "attribute/filtering/AttributeFilter.h"\r
-# include "attribute/resolver/AttributeExtractor.h"\r
-# include "attribute/resolver/AttributeResolver.h"\r
-# include "security/PKIXTrustEngine.h"\r
-# include <saml/SAMLConfig.h>\r
-# include <saml/version.h>\r
-# include <saml/binding/ArtifactMap.h>\r
-# include <saml/binding/SAMLArtifact.h>\r
-# include <saml/binding/SecurityPolicyRule.h>\r
-# include <saml/saml1/core/Assertions.h>\r
-# include <saml/saml2/core/Assertions.h>\r
-# include <saml/saml2/binding/SAML2ArtifactType0004.h>\r
-# include <saml/saml2/metadata/Metadata.h>\r
-# include <saml/saml2/metadata/MetadataProvider.h>\r
-# include <saml/util/SAMLConstants.h>\r
-# include <xmltooling/security/CredentialResolver.h>\r
-# include <xmltooling/security/SecurityHelper.h>\r
-# include <xmltooling/security/TrustEngine.h>\r
-# include <xmltooling/util/ReplayCache.h>\r
-# include <xmltooling/util/StorageService.h>\r
-using namespace opensaml::saml2;\r
-using namespace opensaml::saml2p;\r
-using namespace opensaml::saml2md;\r
-using namespace opensaml;\r
-#else\r
-# include "lite/SAMLConstants.h"\r
-#endif\r
-\r
-using namespace shibsp;\r
-using namespace xmltooling;\r
-using namespace std;\r
-\r
-#ifndef min\r
-# define min(a,b)            (((a) < (b)) ? (a) : (b))\r
-#endif\r
-\r
-namespace {\r
-\r
-#if defined (_MSC_VER)\r
-    #pragma warning( push )\r
-    #pragma warning( disable : 4250 )\r
-#endif\r
-\r
-    static vector<const Handler*> g_noHandlers;\r
-\r
-    // Application configuration wrapper\r
-    class SHIBSP_DLLLOCAL XMLApplication : public Application, public Remoted, public DOMPropertySet, public DOMNodeFilter\r
-    {\r
-    public:\r
-        XMLApplication(const ServiceProvider*, const DOMElement* e, const XMLApplication* base=NULL);\r
-        ~XMLApplication() { cleanup(); }\r
-\r
-        const char* getHash() const {return m_hash.c_str();}\r
-\r
-#ifndef SHIBSP_LITE\r
-        SAMLArtifact* generateSAML1Artifact(const EntityDescriptor* relyingParty) const {\r
-            throw ConfigurationException("No support for SAML 1.x artifact generation.");\r
-        }\r
-        SAML2Artifact* generateSAML2Artifact(const EntityDescriptor* relyingParty) const {\r
-            pair<bool,int> index = make_pair(false,0);\r
-            const PropertySet* props = getRelyingParty(relyingParty);\r
-            index = props->getInt("artifactEndpointIndex");\r
-            if (!index.first)\r
-                index = getArtifactEndpointIndex();\r
-            pair<bool,const char*> entityID = props->getString("entityID");\r
-            return new SAML2ArtifactType0004(\r
-                SecurityHelper::doHash("SHA1", entityID.second, strlen(entityID.second), false),\r
-                index.first ? index.second : 1\r
-                );\r
-        }\r
-\r
-        MetadataProvider* getMetadataProvider(bool required=true) const {\r
-            if (required && !m_base && !m_metadata)\r
-                throw ConfigurationException("No MetadataProvider available.");\r
-            return (!m_metadata && m_base) ? m_base->getMetadataProvider() : m_metadata;\r
-        }\r
-        TrustEngine* getTrustEngine(bool required=true) const {\r
-            if (required && !m_base && !m_trust)\r
-                throw ConfigurationException("No TrustEngine available.");\r
-            return (!m_trust && m_base) ? m_base->getTrustEngine() : m_trust;\r
-        }\r
-        AttributeExtractor* getAttributeExtractor() const {\r
-            return (!m_attrExtractor && m_base) ? m_base->getAttributeExtractor() : m_attrExtractor;\r
-        }\r
-        AttributeFilter* getAttributeFilter() const {\r
-            return (!m_attrFilter && m_base) ? m_base->getAttributeFilter() : m_attrFilter;\r
-        }\r
-        AttributeResolver* getAttributeResolver() const {\r
-            return (!m_attrResolver && m_base) ? m_base->getAttributeResolver() : m_attrResolver;\r
-        }\r
-        CredentialResolver* getCredentialResolver() const {\r
-            return (!m_credResolver && m_base) ? m_base->getCredentialResolver() : m_credResolver;\r
-        }\r
-        const PropertySet* getRelyingParty(const EntityDescriptor* provider) const;\r
-        const PropertySet* getRelyingParty(const XMLCh* entityID) const;\r
-        const vector<const XMLCh*>* getAudiences() const {\r
-            return (m_audiences.empty() && m_base) ? m_base->getAudiences() : &m_audiences;\r
-        }\r
-#endif\r
-        string getNotificationURL(const char* resource, bool front, unsigned int index) const;\r
-\r
-        const vector<string>& getRemoteUserAttributeIds() const {\r
-            return (m_remoteUsers.empty() && m_base) ? m_base->getRemoteUserAttributeIds() : m_remoteUsers;\r
-        }\r
-\r
-        void clearHeader(SPRequest& request, const char* rawname, const char* cginame) const;\r
-        void setHeader(SPRequest& request, const char* name, const char* value) const;\r
-        string getSecureHeader(const SPRequest& request, const char* name) const;\r
-\r
-        const SessionInitiator* getDefaultSessionInitiator() const;\r
-        const SessionInitiator* getSessionInitiatorById(const char* id) const;\r
-        const Handler* getDefaultAssertionConsumerService() const;\r
-        const Handler* getAssertionConsumerServiceByIndex(unsigned short index) const;\r
-        const vector<const Handler*>& getAssertionConsumerServicesByBinding(const XMLCh* binding) const;\r
-        const Handler* getHandler(const char* path) const;\r
-        void getHandlers(vector<const Handler*>& handlers) const;\r
-\r
-        void receive(DDF& in, ostream& out) {\r
-            // Only current function is to return the headers to clear.\r
-            DDF header;\r
-            DDF ret=DDF(NULL).list();\r
-            DDFJanitor jret(ret);\r
-            for (vector< pair<string,string> >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) {\r
-                header = DDF(i->first.c_str()).string(i->second.c_str());\r
-                ret.add(header);\r
-            }\r
-            out << ret;\r
-        }\r
-\r
-        // Provides filter to exclude special config elements.\r
-#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE\r
-        short\r
-#else\r
-        FilterAction\r
-#endif\r
-        acceptNode(const DOMNode* node) const;\r
-\r
-    private:\r
-        void cleanup();\r
-        const XMLApplication* m_base;\r
-        string m_hash;\r
-        std::pair<std::string,std::string> m_attributePrefix;\r
-#ifndef SHIBSP_LITE\r
-        MetadataProvider* m_metadata;\r
-        TrustEngine* m_trust;\r
-        AttributeExtractor* m_attrExtractor;\r
-        AttributeFilter* m_attrFilter;\r
-        AttributeResolver* m_attrResolver;\r
-        CredentialResolver* m_credResolver;\r
-        vector<const XMLCh*> m_audiences;\r
-\r
-        // RelyingParty properties\r
-        map<xstring,PropertySet*> m_partyMap;\r
-#endif\r
-        vector<string> m_remoteUsers,m_frontLogout,m_backLogout;\r
-\r
-        // manage handler objects\r
-        vector<Handler*> m_handlers;\r
-\r
-        // maps location (path info) to applicable handlers\r
-        map<string,const Handler*> m_handlerMap;\r
-\r
-        // maps unique indexes to consumer services\r
-        map<unsigned int,const Handler*> m_acsIndexMap;\r
-\r
-        // pointer to default consumer service\r
-        const Handler* m_acsDefault;\r
-\r
-        // maps binding strings to supporting consumer service(s)\r
-        typedef map<xstring,vector<const Handler*> > ACSBindingMap;\r
-        ACSBindingMap m_acsBindingMap;\r
-\r
-        // pointer to default session initiator\r
-        const SessionInitiator* m_sessionInitDefault;\r
-\r
-        // maps unique ID strings to session initiators\r
-        map<string,const SessionInitiator*> m_sessionInitMap;\r
-\r
-        // pointer to default artifact resolution service\r
-        const Handler* m_artifactResolutionDefault;\r
-\r
-        pair<bool,int> getArtifactEndpointIndex() const {\r
-            if (m_artifactResolutionDefault) return m_artifactResolutionDefault->getInt("index");\r
-            return m_base ? m_base->getArtifactEndpointIndex() : make_pair(false,0);\r
-        }\r
-    };\r
-\r
-    // Top-level configuration implementation\r
-    class SHIBSP_DLLLOCAL XMLConfig;\r
-    class SHIBSP_DLLLOCAL XMLConfigImpl : public DOMPropertySet, public DOMNodeFilter\r
-    {\r
-    public:\r
-        XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer, Category& log);\r
-        ~XMLConfigImpl();\r
-\r
-        RequestMapper* m_requestMapper;\r
-        map<string,Application*> m_appmap;\r
-#ifndef SHIBSP_LITE\r
-        map< string,pair< PropertySet*,vector<const SecurityPolicyRule*> > > m_policyMap;\r
-        vector< pair< string, pair<string,string> > > m_transportOptions;\r
-#endif\r
-\r
-        // Provides filter to exclude special config elements.\r
-#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE\r
-        short\r
-#else\r
-        FilterAction\r
-#endif\r
-        acceptNode(const DOMNode* node) const;\r
-\r
-        void setDocument(DOMDocument* doc) {\r
-            m_document = doc;\r
-        }\r
-\r
-    private:\r
-        void doExtensions(const DOMElement* e, const char* label, Category& log);\r
-        void cleanup();\r
-\r
-        const XMLConfig* m_outer;\r
-        DOMDocument* m_document;\r
-    };\r
-\r
-    class SHIBSP_DLLLOCAL XMLConfig : public ServiceProvider, public ReloadableXMLFile\r
-#ifndef SHIBSP_LITE\r
-        ,public Remoted\r
-#endif\r
-    {\r
-    public:\r
-        XMLConfig(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".Config")),\r
-            m_impl(NULL), m_listener(NULL), m_sessionCache(NULL)\r
-#ifndef SHIBSP_LITE\r
-            , m_tranLog(NULL)\r
-#endif\r
-        {\r
-        }\r
-\r
-        void init() {\r
-            load();\r
-        }\r
-\r
-        ~XMLConfig() {\r
-            delete m_impl;\r
-            delete m_sessionCache;\r
-            delete m_listener;\r
-#ifndef SHIBSP_LITE\r
-            delete m_tranLog;\r
-            SAMLConfig::getConfig().setArtifactMap(NULL);\r
-            XMLToolingConfig::getConfig().setReplayCache(NULL);\r
-            for_each(m_storage.begin(), m_storage.end(), cleanup_pair<string,StorageService>());\r
-#endif\r
-        }\r
-\r
-        // PropertySet\r
-        const PropertySet* getParent() const { return m_impl->getParent(); }\r
-        void setParent(const PropertySet* parent) {return m_impl->setParent(parent);}\r
-        pair<bool,bool> getBool(const char* name, const char* ns=NULL) const {return m_impl->getBool(name,ns);}\r
-        pair<bool,const char*> getString(const char* name, const char* ns=NULL) const {return m_impl->getString(name,ns);}\r
-        pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const {return m_impl->getXMLString(name,ns);}\r
-        pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const {return m_impl->getUnsignedInt(name,ns);}\r
-        pair<bool,int> getInt(const char* name, const char* ns=NULL) const {return m_impl->getInt(name,ns);}\r
-        void getAll(map<string,const char*>& properties) const {return m_impl->getAll(properties);}\r
-        const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:2.0:native:sp:config") const {return m_impl->getPropertySet(name,ns);}\r
-        const DOMElement* getElement() const {return m_impl->getElement();}\r
-\r
-        // ServiceProvider\r
-#ifndef SHIBSP_LITE\r
-        // Remoted\r
-        void receive(DDF& in, ostream& out);\r
-\r
-        TransactionLog* getTransactionLog() const {\r
-            if (m_tranLog)\r
-                return m_tranLog;\r
-            throw ConfigurationException("No TransactionLog available.");\r
-        }\r
-\r
-        StorageService* getStorageService(const char* id) const {\r
-            if (id) {\r
-                map<string,StorageService*>::const_iterator i=m_storage.find(id);\r
-                if (i!=m_storage.end())\r
-                    return i->second;\r
-            }\r
-            return NULL;\r
-        }\r
-#endif\r
-\r
-        ListenerService* getListenerService(bool required=true) const {\r
-            if (required && !m_listener)\r
-                throw ConfigurationException("No ListenerService available.");\r
-            return m_listener;\r
-        }\r
-\r
-        SessionCache* getSessionCache(bool required=true) const {\r
-            if (required && !m_sessionCache)\r
-                throw ConfigurationException("No SessionCache available.");\r
-            return m_sessionCache;\r
-        }\r
-\r
-        RequestMapper* getRequestMapper(bool required=true) const {\r
-            if (required && !m_impl->m_requestMapper)\r
-                throw ConfigurationException("No RequestMapper available.");\r
-            return m_impl->m_requestMapper;\r
-        }\r
-\r
-        const Application* getApplication(const char* applicationId) const {\r
-            map<string,Application*>::const_iterator i=m_impl->m_appmap.find(applicationId);\r
-            return (i!=m_impl->m_appmap.end()) ? i->second : NULL;\r
-        }\r
-\r
-#ifndef SHIBSP_LITE\r
-        const PropertySet* getPolicySettings(const char* id) const {\r
-            map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);\r
-            if (i!=m_impl->m_policyMap.end())\r
-                return i->second.first;\r
-            throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));\r
-        }\r
-\r
-        const vector<const SecurityPolicyRule*>& getPolicyRules(const char* id) const {\r
-            map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);\r
-            if (i!=m_impl->m_policyMap.end())\r
-                return i->second.second;\r
-            throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));\r
-        }\r
-\r
-        bool setTransportOptions(SOAPTransport& transport) const {\r
-            bool ret = true;\r
-            vector< pair< string, pair<string,string> > >::const_iterator opt;\r
-            for (opt = m_impl->m_transportOptions.begin(); opt != m_impl->m_transportOptions.end(); ++opt) {\r
-                if (!transport.setProviderOption(opt->first.c_str(), opt->second.first.c_str(), opt->second.second.c_str())) {\r
-                    m_log.error("failed to set SOAPTransport option (%s)", opt->second.first.c_str());\r
-                    ret = false;\r
-                }\r
-            }\r
-            return ret;\r
-        }\r
-#endif\r
-\r
-    protected:\r
-        pair<bool,DOMElement*> load();\r
-\r
-    private:\r
-        friend class XMLConfigImpl;\r
-        XMLConfigImpl* m_impl;\r
-        mutable ListenerService* m_listener;\r
-        mutable SessionCache* m_sessionCache;\r
-#ifndef SHIBSP_LITE\r
-        mutable TransactionLog* m_tranLog;\r
-        mutable map<string,StorageService*> m_storage;\r
-#endif\r
-    };\r
-\r
-#if defined (_MSC_VER)\r
-    #pragma warning( pop )\r
-#endif\r
-\r
-    static const XMLCh ApplicationOverride[] =  UNICODE_LITERAL_19(A,p,p,l,i,c,a,t,i,o,n,O,v,e,r,r,i,d,e);\r
-    static const XMLCh ApplicationDefaults[] =  UNICODE_LITERAL_19(A,p,p,l,i,c,a,t,i,o,n,D,e,f,a,u,l,t,s);\r
-    static const XMLCh _ArtifactMap[] =         UNICODE_LITERAL_11(A,r,t,i,f,a,c,t,M,a,p);\r
-    static const XMLCh _AttributeExtractor[] =  UNICODE_LITERAL_18(A,t,t,r,i,b,u,t,e,E,x,t,r,a,c,t,o,r);\r
-    static const XMLCh _AttributeFilter[] =     UNICODE_LITERAL_15(A,t,t,r,i,b,u,t,e,F,i,l,t,e,r);\r
-    static const XMLCh _AttributeResolver[] =   UNICODE_LITERAL_17(A,t,t,r,i,b,u,t,e,R,e,s,o,l,v,e,r);\r
-    static const XMLCh _AssertionConsumerService[] = UNICODE_LITERAL_24(A,s,s,e,r,t,i,o,n,C,o,n,s,u,m,e,r,S,e,r,v,i,c,e);\r
-    static const XMLCh _ArtifactResolutionService[] =UNICODE_LITERAL_25(A,r,t,i,f,a,c,t,R,e,s,o,l,u,t,i,o,n,S,e,r,v,i,c,e);\r
-    static const XMLCh _Audience[] =            UNICODE_LITERAL_8(A,u,d,i,e,n,c,e);\r
-    static const XMLCh Binding[] =              UNICODE_LITERAL_7(B,i,n,d,i,n,g);\r
-    static const XMLCh Channel[]=               UNICODE_LITERAL_7(C,h,a,n,n,e,l);\r
-    static const XMLCh _CredentialResolver[] =  UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);\r
-    static const XMLCh _Extensions[] =          UNICODE_LITERAL_10(E,x,t,e,n,s,i,o,n,s);\r
-    static const XMLCh _fatal[] =               UNICODE_LITERAL_5(f,a,t,a,l);\r
-    static const XMLCh _Handler[] =             UNICODE_LITERAL_7(H,a,n,d,l,e,r);\r
-    static const XMLCh _id[] =                  UNICODE_LITERAL_2(i,d);\r
-    static const XMLCh InProcess[] =            UNICODE_LITERAL_9(I,n,P,r,o,c,e,s,s);\r
-    static const XMLCh Library[] =              UNICODE_LITERAL_7(L,i,b,r,a,r,y);\r
-    static const XMLCh Listener[] =             UNICODE_LITERAL_8(L,i,s,t,e,n,e,r);\r
-    static const XMLCh Location[] =             UNICODE_LITERAL_8(L,o,c,a,t,i,o,n);\r
-    static const XMLCh logger[] =               UNICODE_LITERAL_6(l,o,g,g,e,r);\r
-    static const XMLCh _LogoutInitiator[] =     UNICODE_LITERAL_15(L,o,g,o,u,t,I,n,i,t,i,a,t,o,r);\r
-    static const XMLCh _ManageNameIDService[] = UNICODE_LITERAL_19(M,a,n,a,g,e,N,a,m,e,I,D,S,e,r,v,i,c,e);\r
-    static const XMLCh _MetadataProvider[] =    UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r);\r
-    static const XMLCh Notify[] =               UNICODE_LITERAL_6(N,o,t,i,f,y);\r
-    static const XMLCh _option[] =              UNICODE_LITERAL_6(o,p,t,i,o,n);\r
-    static const XMLCh OutOfProcess[] =         UNICODE_LITERAL_12(O,u,t,O,f,P,r,o,c,e,s,s);\r
-    static const XMLCh _path[] =                UNICODE_LITERAL_4(p,a,t,h);\r
-    static const XMLCh Policy[] =               UNICODE_LITERAL_6(P,o,l,i,c,y);\r
-    static const XMLCh PolicyRule[] =           UNICODE_LITERAL_10(P,o,l,i,c,y,R,u,l,e);\r
-    static const XMLCh _provider[] =            UNICODE_LITERAL_8(p,r,o,v,i,d,e,r);\r
-    static const XMLCh RelyingParty[] =         UNICODE_LITERAL_12(R,e,l,y,i,n,g,P,a,r,t,y);\r
-    static const XMLCh _ReplayCache[] =         UNICODE_LITERAL_11(R,e,p,l,a,y,C,a,c,h,e);\r
-    static const XMLCh _RequestMapper[] =       UNICODE_LITERAL_13(R,e,q,u,e,s,t,M,a,p,p,e,r);\r
-    static const XMLCh Rule[] =                 UNICODE_LITERAL_4(R,u,l,e);\r
-    static const XMLCh SecurityPolicies[] =     UNICODE_LITERAL_16(S,e,c,u,r,i,t,y,P,o,l,i,c,i,e,s);\r
-    static const XMLCh _SessionCache[] =        UNICODE_LITERAL_12(S,e,s,s,i,o,n,C,a,c,h,e);\r
-    static const XMLCh _SessionInitiator[] =    UNICODE_LITERAL_16(S,e,s,s,i,o,n,I,n,i,t,i,a,t,o,r);\r
-    static const XMLCh _SingleLogoutService[] = UNICODE_LITERAL_19(S,i,n,g,l,e,L,o,g,o,u,t,S,e,r,v,i,c,e);\r
-    static const XMLCh Site[] =                 UNICODE_LITERAL_4(S,i,t,e);\r
-    static const XMLCh _StorageService[] =      UNICODE_LITERAL_14(S,t,o,r,a,g,e,S,e,r,v,i,c,e);\r
-    static const XMLCh TCPListener[] =          UNICODE_LITERAL_11(T,C,P,L,i,s,t,e,n,e,r);\r
-    static const XMLCh TransportOption[] =      UNICODE_LITERAL_15(T,r,a,n,s,p,o,r,t,O,p,t,i,o,n);\r
-    static const XMLCh _TrustEngine[] =         UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e);\r
-    static const XMLCh _type[] =                UNICODE_LITERAL_4(t,y,p,e);\r
-    static const XMLCh UnixListener[] =         UNICODE_LITERAL_12(U,n,i,x,L,i,s,t,e,n,e,r);\r
-\r
-#ifndef SHIBSP_LITE\r
-    class SHIBSP_DLLLOCAL PolicyNodeFilter : public DOMNodeFilter\r
-    {\r
-    public:\r
-#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE\r
-        short\r
-#else\r
-        FilterAction\r
-#endif\r
-        acceptNode(const DOMNode* node) const {\r
-            return FILTER_REJECT;\r
-        }\r
-    };\r
-#endif\r
-};\r
-\r
-namespace shibsp {\r
-    ServiceProvider* XMLServiceProviderFactory(const DOMElement* const & e)\r
-    {\r
-        return new XMLConfig(e);\r
-    }\r
-};\r
-\r
-XMLApplication::XMLApplication(\r
-    const ServiceProvider* sp,\r
-    const DOMElement* e,\r
-    const XMLApplication* base\r
-    ) : Application(sp), m_base(base),\r
-#ifndef SHIBSP_LITE\r
-        m_metadata(NULL), m_trust(NULL),\r
-        m_attrExtractor(NULL), m_attrFilter(NULL), m_attrResolver(NULL),\r
-        m_credResolver(NULL),\r
-#endif\r
-        m_acsDefault(NULL), m_sessionInitDefault(NULL), m_artifactResolutionDefault(NULL)\r
-{\r
-#ifdef _DEBUG\r
-    xmltooling::NDC ndc("XMLApplication");\r
-#endif\r
-    Category& log=Category::getInstance(SHIBSP_LOGCAT".Application");\r
-\r
-    try {\r
-        // First load any property sets.\r
-        load(e,NULL,this);\r
-        if (base)\r
-            setParent(base);\r
-\r
-        SPConfig& conf=SPConfig::getConfig();\r
-#ifndef SHIBSP_LITE\r
-        SAMLConfig& samlConf=SAMLConfig::getConfig();\r
-        XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();\r
-#endif\r
-\r
-        // This used to be an actual hash, but now it's just a hex-encode to avoid xmlsec.\r
-        static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};\r
-        string tohash=getId();\r
-        tohash+=getString("entityID").second;\r
-        for (const char* ch = tohash.c_str(); *ch; ++ch) {\r
-            m_hash += (DIGITS[((unsigned char)(0xF0 & *ch)) >> 4 ]);\r
-            m_hash += (DIGITS[0x0F & *ch]);\r
-        }\r
-\r
-        // Populate prefix pair.\r
-        m_attributePrefix.second = "HTTP_";\r
-        pair<bool,const char*> prefix = getString("attributePrefix");\r
-        if (prefix.first) {\r
-            m_attributePrefix.first = prefix.second;\r
-            const char* pch = prefix.second;\r
-            while (*pch) {\r
-                m_attributePrefix.second += (isalnum(*pch) ? toupper(*pch) : '_');\r
-                pch++;\r
-            }\r
-        }\r
-\r
-        // Load attribute ID lists for REMOTE_USER and header clearing.\r
-        if (conf.isEnabled(SPConfig::InProcess)) {\r
-            pair<bool,const char*> attributes = getString("REMOTE_USER");\r
-            if (attributes.first) {\r
-                char* dup = strdup(attributes.second);\r
-                char* pos;\r
-                char* start = dup;\r
-                while (start && *start) {\r
-                    while (*start && isspace(*start))\r
-                        start++;\r
-                    if (!*start)\r
-                        break;\r
-                    pos = strchr(start,' ');\r
-                    if (pos)\r
-                        *pos=0;\r
-                    m_remoteUsers.push_back(start);\r
-                    start = pos ? pos+1 : NULL;\r
-                }\r
-                free(dup);\r
-            }\r
-\r
-            attributes = getString("unsetHeaders");\r
-            if (attributes.first) {\r
-                string transformedprefix(m_attributePrefix.second);\r
-                const char* pch;\r
-                prefix = getString("metadataAttributePrefix");\r
-                if (prefix.first) {\r
-                    pch = prefix.second;\r
-                    while (*pch) {\r
-                        transformedprefix += (isalnum(*pch) ? toupper(*pch) : '_');\r
-                        pch++;\r
-                    }\r
-                }\r
-                char* dup = strdup(attributes.second);\r
-                char* pos;\r
-                char* start = dup;\r
-                while (start && *start) {\r
-                    while (*start && isspace(*start))\r
-                        start++;\r
-                    if (!*start)\r
-                        break;\r
-                    pos = strchr(start,' ');\r
-                    if (pos)\r
-                        *pos=0;\r
-\r
-                    string transformed;\r
-                    pch = start;\r
-                    while (*pch) {\r
-                        transformed += (isalnum(*pch) ? toupper(*pch) : '_');\r
-                        pch++;\r
-                    }\r
-\r
-                    m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + start, m_attributePrefix.second + transformed));\r
-                    if (prefix.first)\r
-                        m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + prefix.second + start, transformedprefix + transformed));\r
-                    start = pos ? pos+1 : NULL;\r
-                }\r
-                free(dup);\r
-                m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + "Shib-Application-ID", m_attributePrefix.second + "SHIB_APPLICATION_ID"));\r
-            }\r
-        }\r
-\r
-        Handler* handler=NULL;\r
-        const PropertySet* sessions = getPropertySet("Sessions");\r
-\r
-        // Process assertion export handler.\r
-        pair<bool,const char*> location = sessions ? sessions->getString("exportLocation") : pair<bool,const char*>(false,NULL);\r
-        if (location.first) {\r
-            try {\r
-                DOMElement* exportElement = e->getOwnerDocument()->createElementNS(shibspconstants::SHIB2SPCONFIG_NS,_Handler);\r
-                exportElement->setAttributeNS(NULL,Location,sessions->getXMLString("exportLocation").second);\r
-                pair<bool,const XMLCh*> exportACL = sessions->getXMLString("exportACL");\r
-                if (exportACL.first) {\r
-                    static const XMLCh _acl[] = UNICODE_LITERAL_9(e,x,p,o,r,t,A,C,L);\r
-                    exportElement->setAttributeNS(NULL,_acl,exportACL.second);\r
-                }\r
-                handler = conf.HandlerManager.newPlugin(\r
-                    samlconstants::SAML20_BINDING_URI, pair<const DOMElement*,const char*>(exportElement, getId())\r
-                    );\r
-                m_handlers.push_back(handler);\r
-\r
-                // Insert into location map. If it contains the handlerURL, we skip past that part.\r
-                const char* pch = strstr(location.second, sessions->getString("handlerURL").second);\r
-                if (pch)\r
-                    location.second = pch + strlen(sessions->getString("handlerURL").second);\r
-                if (*location.second == '/')\r
-                    m_handlerMap[location.second]=handler;\r
-                else\r
-                    m_handlerMap[string("/") + location.second]=handler;\r
-            }\r
-            catch (exception& ex) {\r
-                log.error("caught exception installing assertion lookup handler: %s", ex.what());\r
-            }\r
-        }\r
-\r
-        // Process other handlers.\r
-        bool hardACS=false, hardSessionInit=false, hardArt=false;\r
-        const DOMElement* child = sessions ? XMLHelper::getFirstChildElement(sessions->getElement()) : NULL;\r
-        while (child) {\r
-            try {\r
-                // A handler is based on the Binding property in conjunction with the element name.\r
-                // If it's an ACS or SI, also handle index/id mappings and defaulting.\r
-                if (XMLString::equals(child->getLocalName(),_AssertionConsumerService)) {\r
-                    auto_ptr_char bindprop(child->getAttributeNS(NULL,Binding));\r
-                    if (!bindprop.get() || !*(bindprop.get())) {\r
-                        log.warn("md:AssertionConsumerService element has no Binding attribute, skipping it...");\r
-                        child = XMLHelper::getNextSiblingElement(child);\r
-                        continue;\r
-                    }\r
-                    handler=conf.AssertionConsumerServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));\r
-                    // Map by binding (may be > 1 per binding, e.g. SAML 1.0 vs 1.1)\r
-                    m_acsBindingMap[handler->getXMLString("Binding").second].push_back(handler);\r
-                    m_acsIndexMap[handler->getUnsignedInt("index").second]=handler;\r
-\r
-                    if (!hardACS) {\r
-                        pair<bool,bool> defprop=handler->getBool("isDefault");\r
-                        if (defprop.first) {\r
-                            if (defprop.second) {\r
-                                hardACS=true;\r
-                                m_acsDefault=handler;\r
-                            }\r
-                        }\r
-                        else if (!m_acsDefault)\r
-                            m_acsDefault=handler;\r
-                    }\r
-                }\r
-                else if (XMLString::equals(child->getLocalName(),_SessionInitiator)) {\r
-                    auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                    if (!type.get() || !*(type.get())) {\r
-                        log.warn("SessionInitiator element has no type attribute, skipping it...");\r
-                        child = XMLHelper::getNextSiblingElement(child);\r
-                        continue;\r
-                    }\r
-                    SessionInitiator* sihandler=conf.SessionInitiatorManager.newPlugin(type.get(),make_pair(child, getId()));\r
-                    handler=sihandler;\r
-                    pair<bool,const char*> si_id=handler->getString("id");\r
-                    if (si_id.first && si_id.second)\r
-                        m_sessionInitMap[si_id.second]=sihandler;\r
-                    if (!hardSessionInit) {\r
-                        pair<bool,bool> defprop=handler->getBool("isDefault");\r
-                        if (defprop.first) {\r
-                            if (defprop.second) {\r
-                                hardSessionInit=true;\r
-                                m_sessionInitDefault=sihandler;\r
-                            }\r
-                        }\r
-                        else if (!m_sessionInitDefault)\r
-                            m_sessionInitDefault=sihandler;\r
-                    }\r
-                }\r
-                else if (XMLString::equals(child->getLocalName(),_LogoutInitiator)) {\r
-                    auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                    if (!type.get() || !*(type.get())) {\r
-                        log.warn("LogoutInitiator element has no type attribute, skipping it...");\r
-                        child = XMLHelper::getNextSiblingElement(child);\r
-                        continue;\r
-                    }\r
-                    handler=conf.LogoutInitiatorManager.newPlugin(type.get(),make_pair(child, getId()));\r
-                }\r
-                else if (XMLString::equals(child->getLocalName(),_ArtifactResolutionService)) {\r
-                    auto_ptr_char bindprop(child->getAttributeNS(NULL,Binding));\r
-                    if (!bindprop.get() || !*(bindprop.get())) {\r
-                        log.warn("md:ArtifactResolutionService element has no Binding attribute, skipping it...");\r
-                        child = XMLHelper::getNextSiblingElement(child);\r
-                        continue;\r
-                    }\r
-                    handler=conf.ArtifactResolutionServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));\r
-\r
-                    if (!hardArt) {\r
-                        pair<bool,bool> defprop=handler->getBool("isDefault");\r
-                        if (defprop.first) {\r
-                            if (defprop.second) {\r
-                                hardArt=true;\r
-                                m_artifactResolutionDefault=handler;\r
-                            }\r
-                        }\r
-                        else if (!m_artifactResolutionDefault)\r
-                            m_artifactResolutionDefault=handler;\r
-                    }\r
-                }\r
-                else if (XMLString::equals(child->getLocalName(),_SingleLogoutService)) {\r
-                    auto_ptr_char bindprop(child->getAttributeNS(NULL,Binding));\r
-                    if (!bindprop.get() || !*(bindprop.get())) {\r
-                        log.warn("md:SingleLogoutService element has no Binding attribute, skipping it...");\r
-                        child = XMLHelper::getNextSiblingElement(child);\r
-                        continue;\r
-                    }\r
-                    handler=conf.SingleLogoutServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));\r
-                }\r
-                else if (XMLString::equals(child->getLocalName(),_ManageNameIDService)) {\r
-                    auto_ptr_char bindprop(child->getAttributeNS(NULL,Binding));\r
-                    if (!bindprop.get() || !*(bindprop.get())) {\r
-                        log.warn("md:ManageNameIDService element has no Binding attribute, skipping it...");\r
-                        child = XMLHelper::getNextSiblingElement(child);\r
-                        continue;\r
-                    }\r
-                    handler=conf.ManageNameIDServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));\r
-                }\r
-                else {\r
-                    auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                    if (!type.get() || !*(type.get())) {\r
-                        log.warn("Handler element has no type attribute, skipping it...");\r
-                        child = XMLHelper::getNextSiblingElement(child);\r
-                        continue;\r
-                    }\r
-                    handler=conf.HandlerManager.newPlugin(type.get(),make_pair(child, getId()));\r
-                }\r
-\r
-                m_handlers.push_back(handler);\r
-\r
-                // Insert into location map.\r
-                location=handler->getString("Location");\r
-                if (location.first && *location.second == '/')\r
-                    m_handlerMap[location.second]=handler;\r
-                else if (location.first)\r
-                    m_handlerMap[string("/") + location.second]=handler;\r
-\r
-            }\r
-            catch (exception& ex) {\r
-                log.error("caught exception processing handler element: %s", ex.what());\r
-            }\r
-\r
-            child = XMLHelper::getNextSiblingElement(child);\r
-        }\r
-\r
-        // Notification.\r
-        DOMNodeList* nlist=e->getElementsByTagNameNS(shibspconstants::SHIB2SPCONFIG_NS,Notify);\r
-        for (XMLSize_t i=0; nlist && i<nlist->getLength(); i++) {\r
-            if (nlist->item(i)->getParentNode()->isSameNode(e)) {\r
-                const XMLCh* channel = static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,Channel);\r
-                auto_ptr_char loc(static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,Location));\r
-                if (loc.get() && *loc.get()) {\r
-                    if (channel && *channel == chLatin_f)\r
-                        m_frontLogout.push_back(loc.get());\r
-                    else\r
-                        m_backLogout.push_back(loc.get());\r
-                }\r
-            }\r
-        }\r
-\r
-#ifndef SHIBSP_LITE\r
-        nlist=e->getElementsByTagNameNS(samlconstants::SAML20_NS,Audience::LOCAL_NAME);\r
-        if (nlist && nlist->getLength()) {\r
-            log.warn("use of <saml:Audience> elements outside of a Security Policy Rule is deprecated");\r
-            for (XMLSize_t i=0; i<nlist->getLength(); i++)\r
-                if (nlist->item(i)->getParentNode()->isSameNode(e) && nlist->item(i)->hasChildNodes())\r
-                    m_audiences.push_back(nlist->item(i)->getFirstChild()->getNodeValue());\r
-        }\r
-\r
-        if (conf.isEnabled(SPConfig::Metadata)) {\r
-            child = XMLHelper::getFirstChildElement(e,_MetadataProvider);\r
-            if (child) {\r
-                auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                log.info("building MetadataProvider of type %s...",type.get());\r
-                try {\r
-                    auto_ptr<MetadataProvider> mp(samlConf.MetadataProviderManager.newPlugin(type.get(),child));\r
-                    mp->init();\r
-                    m_metadata = mp.release();\r
-                }\r
-                catch (exception& ex) {\r
-                    log.crit("error building/initializing MetadataProvider: %s", ex.what());\r
-                }\r
-            }\r
-        }\r
-\r
-        if (conf.isEnabled(SPConfig::Trust)) {\r
-            child = XMLHelper::getFirstChildElement(e,_TrustEngine);\r
-            if (child) {\r
-                auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                log.info("building TrustEngine of type %s...",type.get());\r
-                try {\r
-                    m_trust = xmlConf.TrustEngineManager.newPlugin(type.get(),child);\r
-                }\r
-                catch (exception& ex) {\r
-                    log.crit("error building TrustEngine: %s", ex.what());\r
-                }\r
-            }\r
-        }\r
-\r
-        if (conf.isEnabled(SPConfig::AttributeResolution)) {\r
-            child = XMLHelper::getFirstChildElement(e,_AttributeExtractor);\r
-            if (child) {\r
-                auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                log.info("building AttributeExtractor of type %s...",type.get());\r
-                try {\r
-                    m_attrExtractor = conf.AttributeExtractorManager.newPlugin(type.get(),child);\r
-                }\r
-                catch (exception& ex) {\r
-                    log.crit("error building AttributeExtractor: %s", ex.what());\r
-                }\r
-            }\r
-\r
-            child = XMLHelper::getFirstChildElement(e,_AttributeFilter);\r
-            if (child) {\r
-                auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                log.info("building AttributeFilter of type %s...",type.get());\r
-                try {\r
-                    m_attrFilter = conf.AttributeFilterManager.newPlugin(type.get(),child);\r
-                }\r
-                catch (exception& ex) {\r
-                    log.crit("error building AttributeFilter: %s", ex.what());\r
-                }\r
-            }\r
-\r
-            child = XMLHelper::getFirstChildElement(e,_AttributeResolver);\r
-            if (child) {\r
-                auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                log.info("building AttributeResolver of type %s...",type.get());\r
-                try {\r
-                    m_attrResolver = conf.AttributeResolverManager.newPlugin(type.get(),child);\r
-                }\r
-                catch (exception& ex) {\r
-                    log.crit("error building AttributeResolver: %s", ex.what());\r
-                }\r
-            }\r
-\r
-            if (m_unsetHeaders.empty()) {\r
-                vector<string> unsetHeaders;\r
-                if (m_attrExtractor) {\r
-                    Locker extlock(m_attrExtractor);\r
-                    m_attrExtractor->getAttributeIds(unsetHeaders);\r
-                }\r
-                else if (m_base && m_base->m_attrExtractor) {\r
-                    Locker extlock(m_base->m_attrExtractor);\r
-                    m_base->m_attrExtractor->getAttributeIds(unsetHeaders);\r
-                }\r
-                if (m_attrResolver) {\r
-                    Locker reslock(m_attrResolver);\r
-                    m_attrResolver->getAttributeIds(unsetHeaders);\r
-                }\r
-                else if (m_base && m_base->m_attrResolver) {\r
-                    Locker extlock(m_base->m_attrResolver);\r
-                    m_base->m_attrResolver->getAttributeIds(unsetHeaders);\r
-                }\r
-                if (!unsetHeaders.empty()) {\r
-                    string transformedprefix(m_attributePrefix.second);\r
-                    const char* pch;\r
-                    pair<bool,const char*> prefix = getString("metadataAttributePrefix");\r
-                    if (prefix.first) {\r
-                        pch = prefix.second;\r
-                        while (*pch) {\r
-                            transformedprefix += (isalnum(*pch) ? toupper(*pch) : '_');\r
-                            pch++;\r
-                        }\r
-                    }\r
-                    for (vector<string>::const_iterator hdr = unsetHeaders.begin(); hdr!=unsetHeaders.end(); ++hdr) {\r
-                        string transformed;\r
-                        pch = hdr->c_str();\r
-                        while (*pch) {\r
-                            transformed += (isalnum(*pch) ? toupper(*pch) : '_');\r
-                            pch++;\r
-                        }\r
-                        m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + *hdr, m_attributePrefix.second + transformed));\r
-                        if (prefix.first)\r
-                            m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + prefix.second + *hdr, transformedprefix + transformed));\r
-                    }\r
-                }\r
-                m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + "Shib-Application-ID", m_attributePrefix.second + "SHIB_APPLICATION_ID"));\r
-            }\r
-        }\r
-\r
-        if (conf.isEnabled(SPConfig::Credentials)) {\r
-            child = XMLHelper::getFirstChildElement(e,_CredentialResolver);\r
-            if (child) {\r
-                auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                log.info("building CredentialResolver of type %s...",type.get());\r
-                try {\r
-                    m_credResolver = xmlConf.CredentialResolverManager.newPlugin(type.get(),child);\r
-                }\r
-                catch (exception& ex) {\r
-                    log.crit("error building CredentialResolver: %s", ex.what());\r
-                }\r
-            }\r
-        }\r
-\r
-        // Finally, load relying parties.\r
-        child = XMLHelper::getFirstChildElement(e,RelyingParty);\r
-        while (child) {\r
-            auto_ptr<DOMPropertySet> rp(new DOMPropertySet());\r
-            rp->load(child,NULL,this);\r
-            rp->setParent(this);\r
-            m_partyMap[child->getAttributeNS(NULL,saml2::Attribute::NAME_ATTRIB_NAME)]=rp.release();\r
-            child = XMLHelper::getNextSiblingElement(child,RelyingParty);\r
-        }\r
-#endif\r
-\r
-        // Out of process only, we register a listener endpoint.\r
-        if (!conf.isEnabled(SPConfig::InProcess)) {\r
-            ListenerService* listener = sp->getListenerService(false);\r
-            if (listener) {\r
-                string addr=string(getId()) + "::getHeaders::Application";\r
-                listener->regListener(addr.c_str(),this);\r
-            }\r
-            else\r
-                log.info("no ListenerService available, Application remoting disabled");\r
-        }\r
-    }\r
-    catch (exception&) {\r
-        cleanup();\r
-        throw;\r
-    }\r
-#ifndef _DEBUG\r
-    catch (...) {\r
-        cleanup();\r
-        throw;\r
-    }\r
-#endif\r
-}\r
-\r
-void XMLApplication::cleanup()\r
-{\r
-    ListenerService* listener=getServiceProvider().getListenerService(false);\r
-    if (listener && SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess) && !SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {\r
-        string addr=string(getId()) + "::getHeaders::Application";\r
-        listener->unregListener(addr.c_str(),this);\r
-    }\r
-    for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());\r
-    m_handlers.clear();\r
-#ifndef SHIBSP_LITE\r
-    for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair<xstring,PropertySet>());\r
-    m_partyMap.clear();\r
-    delete m_credResolver;\r
-    m_credResolver = NULL;\r
-    delete m_attrResolver;\r
-    m_attrResolver = NULL;\r
-    delete m_attrFilter;\r
-    m_attrFilter = NULL;\r
-    delete m_attrExtractor;\r
-    m_attrExtractor = NULL;\r
-    delete m_trust;\r
-    m_trust = NULL;\r
-    delete m_metadata;\r
-    m_metadata = NULL;\r
-#endif\r
-}\r
-\r
-#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE\r
-short\r
-#else\r
-DOMNodeFilter::FilterAction\r
-#endif\r
-XMLApplication::acceptNode(const DOMNode* node) const\r
-{\r
-    const XMLCh* name=node->getLocalName();\r
-    if (XMLString::equals(name,ApplicationOverride) ||\r
-        XMLString::equals(name,_Audience) ||\r
-        XMLString::equals(name,Notify) ||\r
-        XMLString::equals(name,_Handler) ||\r
-        XMLString::equals(name,_AssertionConsumerService) ||\r
-        XMLString::equals(name,_ArtifactResolutionService) ||\r
-        XMLString::equals(name,_LogoutInitiator) ||\r
-        XMLString::equals(name,_ManageNameIDService) ||\r
-        XMLString::equals(name,_SessionInitiator) ||\r
-        XMLString::equals(name,_SingleLogoutService) ||\r
-        XMLString::equals(name,RelyingParty) ||\r
-        XMLString::equals(name,_MetadataProvider) ||\r
-        XMLString::equals(name,_TrustEngine) ||\r
-        XMLString::equals(name,_CredentialResolver) ||\r
-        XMLString::equals(name,_AttributeFilter) ||\r
-        XMLString::equals(name,_AttributeExtractor) ||\r
-        XMLString::equals(name,_AttributeResolver))\r
-        return FILTER_REJECT;\r
-\r
-    return FILTER_ACCEPT;\r
-}\r
-\r
-#ifndef SHIBSP_LITE\r
-\r
-const PropertySet* XMLApplication::getRelyingParty(const EntityDescriptor* provider) const\r
-{\r
-    if (!provider)\r
-        return this;\r
-\r
-    map<xstring,PropertySet*>::const_iterator i=m_partyMap.find(provider->getEntityID());\r
-    if (i!=m_partyMap.end())\r
-        return i->second;\r
-    const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());\r
-    while (group) {\r
-        if (group->getName()) {\r
-            i=m_partyMap.find(group->getName());\r
-            if (i!=m_partyMap.end())\r
-                return i->second;\r
-        }\r
-        group=dynamic_cast<const EntitiesDescriptor*>(group->getParent());\r
-    }\r
-    return this;\r
-}\r
-\r
-const PropertySet* XMLApplication::getRelyingParty(const XMLCh* entityID) const\r
-{\r
-    if (!entityID)\r
-        return this;\r
-\r
-    map<xstring,PropertySet*>::const_iterator i=m_partyMap.find(entityID);\r
-    if (i!=m_partyMap.end())\r
-        return i->second;\r
-    return this;\r
-}\r
-\r
-#endif\r
-\r
-string XMLApplication::getNotificationURL(const char* resource, bool front, unsigned int index) const\r
-{\r
-    const vector<string>& locs = front ? m_frontLogout : m_backLogout;\r
-    if (locs.empty())\r
-        return m_base ? m_base->getNotificationURL(resource, front, index) : string();\r
-    else if (index >= locs.size())\r
-        return string();\r
-\r
-#ifdef HAVE_STRCASECMP\r
-    if (!resource || (strncasecmp(resource,"http://",7) && strncasecmp(resource,"https://",8)))\r
-#else\r
-    if (!resource || (strnicmp(resource,"http://",7) && strnicmp(resource,"https://",8)))\r
-#endif\r
-        throw ConfigurationException("Request URL was not absolute.");\r
-\r
-    const char* handler=locs[index].c_str();\r
-\r
-    // Should never happen...\r
-    if (!handler || (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)))\r
-        throw ConfigurationException(\r
-            "Invalid Location property ($1) in Notify element for Application ($2)",\r
-            params(2, handler ? handler : "null", getId())\r
-            );\r
-\r
-    // The "Location" property can be in one of three formats:\r
-    //\r
-    // 1) a full URI:       http://host/foo/bar\r
-    // 2) a hostless URI:   http:///foo/bar\r
-    // 3) a relative path:  /foo/bar\r
-    //\r
-    // #  Protocol  Host        Path\r
-    // 1  handler   handler     handler\r
-    // 2  handler   resource    handler\r
-    // 3  resource  resource    handler\r
-\r
-    const char* path = NULL;\r
-\r
-    // Decide whether to use the handler or the resource for the "protocol"\r
-    const char* prot;\r
-    if (*handler != '/') {\r
-        prot = handler;\r
-    }\r
-    else {\r
-        prot = resource;\r
-        path = handler;\r
-    }\r
-\r
-    // break apart the "protocol" string into protocol, host, and "the rest"\r
-    const char* colon=strchr(prot,':');\r
-    colon += 3;\r
-    const char* slash=strchr(colon,'/');\r
-    if (!path)\r
-        path = slash;\r
-\r
-    // Compute the actual protocol and store.\r
-    string notifyURL(prot, colon-prot);\r
-\r
-    // create the "host" from either the colon/slash or from the target string\r
-    // If prot == handler then we're in either #1 or #2, else #3.\r
-    // If slash == colon then we're in #2.\r
-    if (prot != handler || slash == colon) {\r
-        colon = strchr(resource, ':');\r
-        colon += 3;      // Get past the ://\r
-        slash = strchr(colon, '/');\r
-    }\r
-    string host(colon, (slash ? slash-colon : strlen(colon)));\r
-\r
-    // Build the URL\r
-    notifyURL += host + path;\r
-    return notifyURL;\r
-}\r
-\r
-void XMLApplication::clearHeader(SPRequest& request, const char* rawname, const char* cginame) const\r
-{\r
-    if (!m_attributePrefix.first.empty()) {\r
-        string temp = m_attributePrefix.first + rawname;\r
-        string temp2 = m_attributePrefix.second + (cginame + 5);\r
-        request.clearHeader(temp.c_str(), temp2.c_str());\r
-    }\r
-    else if (m_base) {\r
-        m_base->clearHeader(request, rawname, cginame);\r
-    }\r
-    else {\r
-        request.clearHeader(rawname, cginame);\r
-    }\r
-}\r
-\r
-void XMLApplication::setHeader(SPRequest& request, const char* name, const char* value) const\r
-{\r
-    if (!m_attributePrefix.first.empty()) {\r
-        string temp = m_attributePrefix.first + name;\r
-        request.setHeader(temp.c_str(), value);\r
-    }\r
-    else if (m_base) {\r
-        m_base->setHeader(request, name, value);\r
-    }\r
-    else {\r
-        request.setHeader(name, value);\r
-    }\r
-}\r
-\r
-string XMLApplication::getSecureHeader(const SPRequest& request, const char* name) const\r
-{\r
-    if (!m_attributePrefix.first.empty()) {\r
-        string temp = m_attributePrefix.first + name;\r
-        return request.getSecureHeader(temp.c_str());\r
-    }\r
-    else if (m_base) {\r
-        return m_base->getSecureHeader(request,name);\r
-    }\r
-    else {\r
-        return request.getSecureHeader(name);\r
-    }\r
-}\r
-\r
-const SessionInitiator* XMLApplication::getDefaultSessionInitiator() const\r
-{\r
-    if (m_sessionInitDefault) return m_sessionInitDefault;\r
-    return m_base ? m_base->getDefaultSessionInitiator() : NULL;\r
-}\r
-\r
-const SessionInitiator* XMLApplication::getSessionInitiatorById(const char* id) const\r
-{\r
-    map<string,const SessionInitiator*>::const_iterator i=m_sessionInitMap.find(id);\r
-    if (i!=m_sessionInitMap.end()) return i->second;\r
-    return m_base ? m_base->getSessionInitiatorById(id) : NULL;\r
-}\r
-\r
-const Handler* XMLApplication::getDefaultAssertionConsumerService() const\r
-{\r
-    if (m_acsDefault) return m_acsDefault;\r
-    return m_base ? m_base->getDefaultAssertionConsumerService() : NULL;\r
-}\r
-\r
-const Handler* XMLApplication::getAssertionConsumerServiceByIndex(unsigned short index) const\r
-{\r
-    map<unsigned int,const Handler*>::const_iterator i=m_acsIndexMap.find(index);\r
-    if (i!=m_acsIndexMap.end()) return i->second;\r
-    return m_base ? m_base->getAssertionConsumerServiceByIndex(index) : NULL;\r
-}\r
-\r
-const vector<const Handler*>& XMLApplication::getAssertionConsumerServicesByBinding(const XMLCh* binding) const\r
-{\r
-    ACSBindingMap::const_iterator i=m_acsBindingMap.find(binding);\r
-    if (i!=m_acsBindingMap.end())\r
-        return i->second;\r
-    return m_base ? m_base->getAssertionConsumerServicesByBinding(binding) : g_noHandlers;\r
-}\r
-\r
-const Handler* XMLApplication::getHandler(const char* path) const\r
-{\r
-    string wrap(path);\r
-    wrap = wrap.substr(0,wrap.find(';'));\r
-    map<string,const Handler*>::const_iterator i=m_handlerMap.find(wrap.substr(0,wrap.find('?')));\r
-    if (i!=m_handlerMap.end())\r
-        return i->second;\r
-    return m_base ? m_base->getHandler(path) : NULL;\r
-}\r
-\r
-void XMLApplication::getHandlers(vector<const Handler*>& handlers) const\r
-{\r
-    handlers.insert(handlers.end(), m_handlers.begin(), m_handlers.end());\r
-    if (m_base) {\r
-        for (map<string,const Handler*>::const_iterator h = m_base->m_handlerMap.begin(); h != m_base->m_handlerMap.end(); ++h) {\r
-            if (m_handlerMap.count(h->first) == 0)\r
-                handlers.push_back(h->second);\r
-        }\r
-    }\r
-}\r
-\r
-#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE\r
-short\r
-#else\r
-DOMNodeFilter::FilterAction\r
-#endif\r
-XMLConfigImpl::acceptNode(const DOMNode* node) const\r
-{\r
-    if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB2SPCONFIG_NS))\r
-        return FILTER_ACCEPT;\r
-    const XMLCh* name=node->getLocalName();\r
-    if (XMLString::equals(name,ApplicationDefaults) ||\r
-        XMLString::equals(name,_ArtifactMap) ||\r
-        XMLString::equals(name,_Extensions) ||\r
-        XMLString::equals(name,Listener) ||\r
-        XMLString::equals(name,_RequestMapper) ||\r
-        XMLString::equals(name,_ReplayCache) ||\r
-        XMLString::equals(name,SecurityPolicies) ||\r
-        XMLString::equals(name,_SessionCache) ||\r
-        XMLString::equals(name,Site) ||\r
-        XMLString::equals(name,_StorageService) ||\r
-        XMLString::equals(name,TCPListener) ||\r
-        XMLString::equals(name,TransportOption) ||\r
-        XMLString::equals(name,UnixListener))\r
-        return FILTER_REJECT;\r
-\r
-    return FILTER_ACCEPT;\r
-}\r
-\r
-void XMLConfigImpl::doExtensions(const DOMElement* e, const char* label, Category& log)\r
-{\r
-    const DOMElement* exts=XMLHelper::getFirstChildElement(e,_Extensions);\r
-    if (exts) {\r
-        exts=XMLHelper::getFirstChildElement(exts,Library);\r
-        while (exts) {\r
-            auto_ptr_char path(exts->getAttributeNS(NULL,_path));\r
-            try {\r
-                if (path.get()) {\r
-                    if (!XMLToolingConfig::getConfig().load_library(path.get(),(void*)exts))\r
-                        throw ConfigurationException("XMLToolingConfig::load_library failed.");\r
-                    log.debug("loaded %s extension library (%s)", label, path.get());\r
-                }\r
-            }\r
-            catch (exception& e) {\r
-                const XMLCh* fatal=exts->getAttributeNS(NULL,_fatal);\r
-                if (fatal && (*fatal==chLatin_t || *fatal==chDigit_1)) {\r
-                    log.fatal("unable to load mandatory %s extension library %s: %s", label, path.get(), e.what());\r
-                    throw;\r
-                }\r
-                else {\r
-                    log.crit("unable to load optional %s extension library %s: %s", label, path.get(), e.what());\r
-                }\r
-            }\r
-            exts=XMLHelper::getNextSiblingElement(exts,Library);\r
-        }\r
-    }\r
-}\r
-\r
-XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer, Category& log)\r
-    : m_requestMapper(NULL), m_outer(outer), m_document(NULL)\r
-{\r
-#ifdef _DEBUG\r
-    xmltooling::NDC ndc("XMLConfigImpl");\r
-#endif\r
-\r
-    try {\r
-        SPConfig& conf=SPConfig::getConfig();\r
-#ifndef SHIBSP_LITE\r
-        SAMLConfig& samlConf=SAMLConfig::getConfig();\r
-#endif\r
-        XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();\r
-        const DOMElement* SHAR=XMLHelper::getFirstChildElement(e,OutOfProcess);\r
-        const DOMElement* SHIRE=XMLHelper::getFirstChildElement(e,InProcess);\r
-\r
-        // Initialize log4cpp manually in order to redirect log messages as soon as possible.\r
-        if (conf.isEnabled(SPConfig::Logging)) {\r
-            const XMLCh* logconf=NULL;\r
-            if (conf.isEnabled(SPConfig::OutOfProcess))\r
-                logconf=SHAR->getAttributeNS(NULL,logger);\r
-            else if (conf.isEnabled(SPConfig::InProcess))\r
-                logconf=SHIRE->getAttributeNS(NULL,logger);\r
-            if (!logconf || !*logconf)\r
-                logconf=e->getAttributeNS(NULL,logger);\r
-            if (logconf && *logconf) {\r
-                auto_ptr_char logpath(logconf);\r
-                log.debug("loading new logging configuration from (%s), check log destination for status of configuration",logpath.get());\r
-                if (!XMLToolingConfig::getConfig().log_config(logpath.get()))\r
-                    log.crit("failed to load new logging configuration from (%s)", logpath.get());\r
-            }\r
-\r
-#ifndef SHIBSP_LITE\r
-            if (first)\r
-                m_outer->m_tranLog = new TransactionLog();\r
-#endif\r
-        }\r
-\r
-        // Re-log library versions now that logging is set up.\r
-#ifndef SHIBSP_LITE\r
-        log.info(\r
-            "Library versions: Xerces-C %s, XML-Security-C %s, XMLTooling-C %s, OpenSAML-C %s, Shibboleth %s",\r
-            XERCES_FULLVERSIONDOT, XSEC_FULLVERSIONDOT, XMLTOOLING_FULLVERSIONDOT, OPENSAML_FULLVERSIONDOT, SHIBSP_FULLVERSIONDOT\r
-            );\r
-#else\r
-        log.info(\r
-            "Library versions: Xerces-C %s, XMLTooling-C %s, Shibboleth %s",\r
-            XERCES_FULLVERSIONDOT, XMLTOOLING_FULLVERSIONDOT, SHIBSP_FULLVERSIONDOT\r
-            );\r
-#endif\r
-\r
-        // First load any property sets.\r
-        load(e,NULL,this);\r
-\r
-        const DOMElement* child;\r
-        string plugtype;\r
-\r
-        // Much of the processing can only occur on the first instantiation.\r
-        if (first) {\r
-            // Set clock skew.\r
-            pair<bool,unsigned int> skew=getUnsignedInt("clockSkew");\r
-            if (skew.first)\r
-                xmlConf.clock_skew_secs=min(skew.second,(60*60*24*7*28));\r
-\r
-            pair<bool,const char*> unsafe = getString("unsafeChars");\r
-            if (unsafe.first)\r
-                TemplateEngine::unsafe_chars = unsafe.second;\r
-\r
-            unsafe = getString("allowedSchemes");\r
-            if (unsafe.first) {\r
-                HTTPResponse::getAllowedSchemes().clear();\r
-                string schemes=unsafe.second;\r
-                unsigned int j_sch=0;\r
-                for (unsigned int i_sch=0;  i_sch < schemes.length();  i_sch++) {\r
-                    if (schemes.at(i_sch)==' ') {\r
-                        HTTPResponse::getAllowedSchemes().push_back(schemes.substr(j_sch, i_sch-j_sch));\r
-                        j_sch = i_sch + 1;\r
-                    }\r
-                }\r
-                HTTPResponse::getAllowedSchemes().push_back(schemes.substr(j_sch, schemes.length()-j_sch));\r
-            }\r
-\r
-            // Extensions\r
-            doExtensions(e, "global", log);\r
-            if (conf.isEnabled(SPConfig::OutOfProcess))\r
-                doExtensions(SHAR, "out of process", log);\r
-\r
-            if (conf.isEnabled(SPConfig::InProcess))\r
-                doExtensions(SHIRE, "in process", log);\r
-\r
-            // Instantiate the ListenerService and SessionCache objects.\r
-            if (conf.isEnabled(SPConfig::Listener)) {\r
-                child=XMLHelper::getFirstChildElement(e,UnixListener);\r
-                if (child)\r
-                    plugtype=UNIX_LISTENER_SERVICE;\r
-                else {\r
-                    child=XMLHelper::getFirstChildElement(e,TCPListener);\r
-                    if (child)\r
-                        plugtype=TCP_LISTENER_SERVICE;\r
-                    else {\r
-                        child=XMLHelper::getFirstChildElement(e,Listener);\r
-                        if (child) {\r
-                            auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                            if (type.get())\r
-                                plugtype=type.get();\r
-                        }\r
-                    }\r
-                }\r
-                if (child) {\r
-                    log.info("building ListenerService of type %s...", plugtype.c_str());\r
-                    m_outer->m_listener = conf.ListenerServiceManager.newPlugin(plugtype.c_str(), child);\r
-                }\r
-                else {\r
-                    log.fatal("can't build ListenerService, missing conf:Listener element?");\r
-                    throw ConfigurationException("Can't build ListenerService, missing conf:Listener element?");\r
-                }\r
-            }\r
-\r
-#ifndef SHIBSP_LITE\r
-            if (m_outer->m_listener && conf.isEnabled(SPConfig::OutOfProcess) && !conf.isEnabled(SPConfig::InProcess)) {\r
-                m_outer->m_listener->regListener("set::RelayState", const_cast<XMLConfig*>(m_outer));\r
-                m_outer->m_listener->regListener("get::RelayState", const_cast<XMLConfig*>(m_outer));\r
-                m_outer->m_listener->regListener("set::PostData", const_cast<XMLConfig*>(m_outer));\r
-                m_outer->m_listener->regListener("get::PostData", const_cast<XMLConfig*>(m_outer));\r
-            }\r
-#endif\r
-\r
-            if (conf.isEnabled(SPConfig::Caching)) {\r
-                if (conf.isEnabled(SPConfig::OutOfProcess)) {\r
-#ifndef SHIBSP_LITE\r
-                    // First build any StorageServices.\r
-                    child=XMLHelper::getFirstChildElement(e,_StorageService);\r
-                    while (child) {\r
-                        auto_ptr_char id(child->getAttributeNS(NULL,_id));\r
-                        auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                        try {\r
-                            log.info("building StorageService (%s) of type %s...", id.get(), type.get());\r
-                            m_outer->m_storage[id.get()] = xmlConf.StorageServiceManager.newPlugin(type.get(),child);\r
-                        }\r
-                        catch (exception& ex) {\r
-                            log.crit("failed to instantiate StorageService (%s): %s", id.get(), ex.what());\r
-                        }\r
-                        child=XMLHelper::getNextSiblingElement(child,_StorageService);\r
-                    }\r
-\r
-                    // Replay cache.\r
-                    StorageService* replaySS=NULL;\r
-                    child=XMLHelper::getFirstChildElement(e,_ReplayCache);\r
-                    if (child) {\r
-                        auto_ptr_char ssid(child->getAttributeNS(NULL,_StorageService));\r
-                        if (ssid.get() && *ssid.get()) {\r
-                            if (m_outer->m_storage.count(ssid.get()))\r
-                                replaySS = m_outer->m_storage[ssid.get()];\r
-                            if (replaySS)\r
-                                log.info("building ReplayCache on top of StorageService (%s)...", ssid.get());\r
-                            else\r
-                                log.warn("unable to locate StorageService (%s) for ReplayCache, using dedicated in-memory instance", ssid.get());\r
-                        }\r
-                        xmlConf.setReplayCache(new ReplayCache(replaySS));\r
-                    }\r
-                    else {\r
-                        log.warn("no ReplayCache built, missing conf:ReplayCache element?");\r
-                    }\r
-\r
-                    // ArtifactMap\r
-                    child=XMLHelper::getFirstChildElement(e,_ArtifactMap);\r
-                    if (child) {\r
-                        auto_ptr_char ssid(child->getAttributeNS(NULL,_StorageService));\r
-                        if (ssid.get() && *ssid.get() && m_outer->m_storage.count(ssid.get())) {\r
-                            log.info("building ArtifactMap on top of StorageService (%s)...", ssid.get());\r
-                            samlConf.setArtifactMap(new ArtifactMap(child, m_outer->m_storage[ssid.get()]));\r
-                        }\r
-                    }\r
-                    if (samlConf.getArtifactMap()==NULL) {\r
-                        log.info("building in-memory ArtifactMap...");\r
-                        samlConf.setArtifactMap(new ArtifactMap(child));\r
-                    }\r
-#endif\r
-                }\r
-                child=XMLHelper::getFirstChildElement(e,_SessionCache);\r
-                if (child) {\r
-                    auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                    log.info("building SessionCache of type %s...",type.get());\r
-                    m_outer->m_sessionCache=conf.SessionCacheManager.newPlugin(type.get(), child);\r
-                }\r
-                else {\r
-                    log.fatal("can't build SessionCache, missing conf:SessionCache element?");\r
-                    throw ConfigurationException("Can't build SessionCache, missing conf:SessionCache element?");\r
-                }\r
-            }\r
-        } // end of first-time-only stuff\r
-\r
-        // Back to the fully dynamic stuff...next up is the RequestMapper.\r
-        if (conf.isEnabled(SPConfig::RequestMapping)) {\r
-            child=XMLHelper::getFirstChildElement(e,_RequestMapper);\r
-            if (child) {\r
-                auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
-                log.info("building RequestMapper of type %s...",type.get());\r
-                m_requestMapper=conf.RequestMapperManager.newPlugin(type.get(),child);\r
-            }\r
-            else {\r
-                log.fatal("can't build RequestMapper, missing conf:RequestMapper element?");\r
-                throw ConfigurationException("Can't build RequestMapper, missing conf:RequestMapper element?");\r
-            }\r
-        }\r
-\r
-#ifndef SHIBSP_LITE\r
-        // Load security policies.\r
-        child = XMLHelper::getLastChildElement(e,SecurityPolicies);\r
-        if (child) {\r
-            PolicyNodeFilter filter;\r
-            child = XMLHelper::getFirstChildElement(child,Policy);\r
-            while (child) {\r
-                auto_ptr_char id(child->getAttributeNS(NULL,_id));\r
-                pair< PropertySet*,vector<const SecurityPolicyRule*> >& rules = m_policyMap[id.get()];\r
-                rules.first = NULL;\r
-                auto_ptr<DOMPropertySet> settings(new DOMPropertySet());\r
-                settings->load(child, NULL, &filter);\r
-                rules.first = settings.release();\r
-\r
-                // Process PolicyRule elements.\r
-                const DOMElement* rule = XMLHelper::getFirstChildElement(child,PolicyRule);\r
-                while (rule) {\r
-                    auto_ptr_char type(rule->getAttributeNS(NULL,_type));\r
-                    try {\r
-                        rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule));\r
-                    }\r
-                    catch (exception& ex) {\r
-                        log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());\r
-                    }\r
-                    rule = XMLHelper::getNextSiblingElement(rule,PolicyRule);\r
-                }\r
-\r
-                if (rules.second.size() == 0) {\r
-                    // Process Rule elements.\r
-                    log.warn("detected legacy Policy configuration, please convert to new PolicyRule syntax");\r
-                    rule = XMLHelper::getFirstChildElement(child,Rule);\r
-                    while (rule) {\r
-                        auto_ptr_char type(rule->getAttributeNS(NULL,_type));\r
-                        try {\r
-                            rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule));\r
-                        }\r
-                        catch (exception& ex) {\r
-                            log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());\r
-                        }\r
-                        rule = XMLHelper::getNextSiblingElement(rule,Rule);\r
-                    }\r
-\r
-                    // Manually add a basic Conditions rule.\r
-                    log.info("installing a default Conditions rule in policy (%s) for compatibility with legacy configuration", id.get());\r
-                    rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(CONDITIONS_POLICY_RULE, NULL));\r
-                }\r
-\r
-                child = XMLHelper::getNextSiblingElement(child,Policy);\r
-            }\r
-        }\r
-\r
-        // Process TransportOption elements.\r
-        child = XMLHelper::getLastChildElement(e,TransportOption);\r
-        while (child) {\r
-            if (child->hasChildNodes()) {\r
-                auto_ptr_char provider(child->getAttributeNS(NULL,_provider));\r
-                auto_ptr_char option(child->getAttributeNS(NULL,_option));\r
-                auto_ptr_char value(child->getFirstChild()->getNodeValue());\r
-                if (provider.get() && *provider.get() && option.get() && *option.get() && value.get() && *value.get()) {\r
-                    m_transportOptions.push_back(make_pair(string(provider.get()), make_pair(string(option.get()), string(value.get()))));\r
-                }\r
-            }\r
-            child = XMLHelper::getPreviousSiblingElement(child,TransportOption);\r
-        }\r
-#endif\r
-\r
-        // Load the default application. This actually has a fixed ID of "default". ;-)\r
-        child=XMLHelper::getLastChildElement(e,ApplicationDefaults);\r
-        if (!child) {\r
-            log.fatal("can't build default Application object, missing conf:ApplicationDefaults element?");\r
-            throw ConfigurationException("can't build default Application object, missing conf:ApplicationDefaults element?");\r
-        }\r
-        XMLApplication* defapp=new XMLApplication(m_outer,child);\r
-        m_appmap[defapp->getId()]=defapp;\r
-\r
-        // Load any overrides.\r
-        child = XMLHelper::getFirstChildElement(child,ApplicationOverride);\r
-        while (child) {\r
-            auto_ptr<XMLApplication> iapp(new XMLApplication(m_outer,child,defapp));\r
-            if (m_appmap.count(iapp->getId()))\r
-                log.crit("found conf:ApplicationOverride element with duplicate id attribute (%s), skipping it", iapp->getId());\r
-            else {\r
-                const char* iappid=iapp->getId();\r
-                m_appmap[iappid]=iapp.release();\r
-            }\r
-\r
-            child = XMLHelper::getNextSiblingElement(child,ApplicationOverride);\r
-        }\r
-    }\r
-    catch (exception&) {\r
-        cleanup();\r
-        throw;\r
-    }\r
-}\r
-\r
-XMLConfigImpl::~XMLConfigImpl()\r
-{\r
-    cleanup();\r
-}\r
-\r
-void XMLConfigImpl::cleanup()\r
-{\r
-    for_each(m_appmap.begin(),m_appmap.end(),cleanup_pair<string,Application>());\r
-    m_appmap.clear();\r
-#ifndef SHIBSP_LITE\r
-    for (map< string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::iterator i=m_policyMap.begin(); i!=m_policyMap.end(); ++i) {\r
-        delete i->second.first;\r
-        for_each(i->second.second.begin(), i->second.second.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
-    }\r
-    m_policyMap.clear();\r
-#endif\r
-    delete m_requestMapper;\r
-    m_requestMapper = NULL;\r
-    if (m_document)\r
-        m_document->release();\r
-    m_document = NULL;\r
-}\r
-\r
-#ifndef SHIBSP_LITE\r
-void XMLConfig::receive(DDF& in, ostream& out)\r
-{\r
-    if (!strcmp(in.name(), "get::RelayState")) {\r
-        const char* id = in["id"].string();\r
-        const char* key = in["key"].string();\r
-        if (!id || !key)\r
-            throw ListenerException("Required parameters missing for RelayState recovery.");\r
-\r
-        string relayState;\r
-        StorageService* storage = getStorageService(id);\r
-        if (storage) {\r
-            if (storage->readString("RelayState",key,&relayState)>0) {\r
-                if (in["clear"].integer())\r
-                    storage->deleteString("RelayState",key);\r
-            }\r
-        }\r
-        else {\r
-            Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error(\r
-                "Storage-backed RelayState with invalid StorageService ID (%s)", id\r
-                );\r
-        }\r
-\r
-        // Repack for return to caller.\r
-        DDF ret=DDF(NULL).unsafe_string(relayState.c_str());\r
-        DDFJanitor jret(ret);\r
-        out << ret;\r
-    }\r
-    else if (!strcmp(in.name(), "set::RelayState")) {\r
-        const char* id = in["id"].string();\r
-        const char* value = in["value"].string();\r
-        if (!id || !value)\r
-            throw ListenerException("Required parameters missing for RelayState creation.");\r
-\r
-        string rsKey;\r
-        StorageService* storage = getStorageService(id);\r
-        if (storage) {\r
-            SAMLConfig::getConfig().generateRandomBytes(rsKey,20);\r
-            rsKey = SAMLArtifact::toHex(rsKey);\r
-            storage->createString("RelayState", rsKey.c_str(), value, time(NULL) + 600);\r
-        }\r
-        else {\r
-            Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error(\r
-                "Storage-backed RelayState with invalid StorageService ID (%s)", id\r
-                );\r
-        }\r
-\r
-        // Repack for return to caller.\r
-        DDF ret=DDF(NULL).string(rsKey.c_str());\r
-        DDFJanitor jret(ret);\r
-        out << ret;\r
-    }\r
-    else if (!strcmp(in.name(), "get::PostData")) {\r
-        const char* id = in["id"].string();\r
-        const char* key = in["key"].string();\r
-        if (!id || !key)\r
-            throw ListenerException("Required parameters missing for PostData recovery.");\r
-\r
-        string postData;\r
-        StorageService* storage = getStorageService(id);\r
-        if (storage) {\r
-            if (storage->readString("PostData",key,&postData) > 0) {\r
-                storage->deleteString("PostData",key);\r
-            }\r
-        }\r
-        else {\r
-            Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error(\r
-                "Storage-backed PostData with invalid StorageService ID (%s)", id\r
-                );\r
-        }\r
-        // If the data's empty, we'll send nothing back.\r
-        // If not, we don't need to round trip it, just send back the serialized DDF list.\r
-        if (postData.empty()) {\r
-            DDF ret(NULL);\r
-            DDFJanitor jret(ret);\r
-            out << ret;\r
-        }\r
-        else {\r
-            out << postData;\r
-        }\r
-    }\r
-    else if (!strcmp(in.name(), "set::PostData")) {\r
-        const char* id = in["id"].string();\r
-        if (!id || !in["parameters"].islist())\r
-            throw ListenerException("Required parameters missing for PostData creation.");\r
-\r
-        string rsKey;\r
-        StorageService* storage = getStorageService(id);\r
-        if (storage) {\r
-            SAMLConfig::getConfig().generateRandomBytes(rsKey,20);\r
-            rsKey = SAMLArtifact::toHex(rsKey);\r
-            ostringstream params;\r
-            params << in["parameters"];\r
-            storage->createString("PostData", rsKey.c_str(), params.str().c_str(), time(NULL) + 600);\r
-        }\r
-        else {\r
-            Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error(\r
-                "Storage-backed PostData with invalid StorageService ID (%s)", id\r
-                );\r
-        }\r
-\r
-        // Repack for return to caller.\r
-        DDF ret=DDF(NULL).string(rsKey.c_str());\r
-        DDFJanitor jret(ret);\r
-        out << ret;\r
-    }\r
-}\r
-#endif\r
-\r
-pair<bool,DOMElement*> XMLConfig::load()\r
-{\r
-    // Load from source using base class.\r
-    pair<bool,DOMElement*> raw = ReloadableXMLFile::load();\r
-\r
-    // If we own it, wrap it.\r
-    XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);\r
-\r
-    XMLConfigImpl* impl = new XMLConfigImpl(raw.second,(m_impl==NULL),this,m_log);\r
-\r
-    // If we held the document, transfer it to the impl. If we didn't, it's a no-op.\r
-    impl->setDocument(docjanitor.release());\r
-\r
-    delete m_impl;\r
-    m_impl = impl;\r
-\r
-    return make_pair(false,(DOMElement*)NULL);\r
-}\r
+/*
+ *  Copyright 2001-2009 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.
+ */
+
+/**
+ * XMLServiceProvider.cpp
+ *
+ * XML-based SP configuration and mgmt.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "version.h"
+#include "AccessControl.h"
+#include "Application.h"
+#include "RequestMapper.h"
+#include "ServiceProvider.h"
+#include "SessionCache.h"
+#include "SPConfig.h"
+#include "SPRequest.h"
+#include "handler/SessionInitiator.h"
+#include "remoting/ListenerService.h"
+#include "util/DOMPropertySet.h"
+#include "util/SPConstants.h"
+
+#if defined(XMLTOOLING_LOG4SHIB)
+# include <log4shib/PropertyConfigurator.hh>
+#elif defined(XMLTOOLING_LOG4CPP)
+# include <log4cpp/PropertyConfigurator.hh>
+#else
+# error "Supported logging library not available."
+#endif
+#include <algorithm>
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/version.h>
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/ReloadableXMLFile.h>
+#include <xmltooling/util/TemplateEngine.h>
+#include <xmltooling/util/XMLHelper.h>
+
+#ifndef SHIBSP_LITE
+# include "TransactionLog.h"
+# include "attribute/filtering/AttributeFilter.h"
+# include "attribute/resolver/AttributeExtractor.h"
+# include "attribute/resolver/AttributeResolver.h"
+# include "security/PKIXTrustEngine.h"
+# include <saml/SAMLConfig.h>
+# include <saml/version.h>
+# include <saml/binding/ArtifactMap.h>
+# include <saml/binding/SAMLArtifact.h>
+# include <saml/binding/SecurityPolicyRule.h>
+# include <saml/saml1/core/Assertions.h>
+# include <saml/saml2/core/Assertions.h>
+# include <saml/saml2/binding/SAML2ArtifactType0004.h>
+# include <saml/saml2/metadata/Metadata.h>
+# include <saml/saml2/metadata/MetadataProvider.h>
+# include <saml/util/SAMLConstants.h>
+# include <xmltooling/security/CredentialResolver.h>
+# include <xmltooling/security/SecurityHelper.h>
+# include <xmltooling/security/TrustEngine.h>
+# include <xmltooling/util/ReplayCache.h>
+# include <xmltooling/util/StorageService.h>
+using namespace opensaml::saml2;
+using namespace opensaml::saml2p;
+using namespace opensaml::saml2md;
+using namespace opensaml;
+#else
+# include "lite/SAMLConstants.h"
+#endif
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace std;
+
+#ifndef min
+# define min(a,b)            (((a) < (b)) ? (a) : (b))
+#endif
+
+namespace {
+
+#if defined (_MSC_VER)
+    #pragma warning( push )
+    #pragma warning( disable : 4250 )
+#endif
+
+    static vector<const Handler*> g_noHandlers;
+
+    // Application configuration wrapper
+    class SHIBSP_DLLLOCAL XMLApplication : public Application, public Remoted, public DOMPropertySet, public DOMNodeFilter
+    {
+    public:
+        XMLApplication(const ServiceProvider*, const DOMElement* e, const XMLApplication* base=NULL);
+        ~XMLApplication() { cleanup(); }
+
+        const char* getHash() const {return m_hash.c_str();}
+
+#ifndef SHIBSP_LITE
+        SAMLArtifact* generateSAML1Artifact(const EntityDescriptor* relyingParty) const {
+            throw ConfigurationException("No support for SAML 1.x artifact generation.");
+        }
+        SAML2Artifact* generateSAML2Artifact(const EntityDescriptor* relyingParty) const {
+            pair<bool,int> index = make_pair(false,0);
+            const PropertySet* props = getRelyingParty(relyingParty);
+            index = props->getInt("artifactEndpointIndex");
+            if (!index.first)
+                index = getArtifactEndpointIndex();
+            pair<bool,const char*> entityID = props->getString("entityID");
+            return new SAML2ArtifactType0004(
+                SecurityHelper::doHash("SHA1", entityID.second, strlen(entityID.second), false),
+                index.first ? index.second : 1
+                );
+        }
+
+        MetadataProvider* getMetadataProvider(bool required=true) const {
+            if (required && !m_base && !m_metadata)
+                throw ConfigurationException("No MetadataProvider available.");
+            return (!m_metadata && m_base) ? m_base->getMetadataProvider() : m_metadata;
+        }
+        TrustEngine* getTrustEngine(bool required=true) const {
+            if (required && !m_base && !m_trust)
+                throw ConfigurationException("No TrustEngine available.");
+            return (!m_trust && m_base) ? m_base->getTrustEngine() : m_trust;
+        }
+        AttributeExtractor* getAttributeExtractor() const {
+            return (!m_attrExtractor && m_base) ? m_base->getAttributeExtractor() : m_attrExtractor;
+        }
+        AttributeFilter* getAttributeFilter() const {
+            return (!m_attrFilter && m_base) ? m_base->getAttributeFilter() : m_attrFilter;
+        }
+        AttributeResolver* getAttributeResolver() const {
+            return (!m_attrResolver && m_base) ? m_base->getAttributeResolver() : m_attrResolver;
+        }
+        CredentialResolver* getCredentialResolver() const {
+            return (!m_credResolver && m_base) ? m_base->getCredentialResolver() : m_credResolver;
+        }
+        const PropertySet* getRelyingParty(const EntityDescriptor* provider) const;
+        const PropertySet* getRelyingParty(const XMLCh* entityID) const;
+        const vector<const XMLCh*>* getAudiences() const {
+            return (m_audiences.empty() && m_base) ? m_base->getAudiences() : &m_audiences;
+        }
+#endif
+        string getNotificationURL(const char* resource, bool front, unsigned int index) const;
+
+        const vector<string>& getRemoteUserAttributeIds() const {
+            return (m_remoteUsers.empty() && m_base) ? m_base->getRemoteUserAttributeIds() : m_remoteUsers;
+        }
+
+        void clearHeader(SPRequest& request, const char* rawname, const char* cginame) const;
+        void setHeader(SPRequest& request, const char* name, const char* value) const;
+        string getSecureHeader(const SPRequest& request, const char* name) const;
+
+        const SessionInitiator* getDefaultSessionInitiator() const;
+        const SessionInitiator* getSessionInitiatorById(const char* id) const;
+        const Handler* getDefaultAssertionConsumerService() const;
+        const Handler* getAssertionConsumerServiceByIndex(unsigned short index) const;
+        const vector<const Handler*>& getAssertionConsumerServicesByBinding(const XMLCh* binding) const;
+        const Handler* getHandler(const char* path) const;
+        void getHandlers(vector<const Handler*>& handlers) const;
+
+        void receive(DDF& in, ostream& out) {
+            // Only current function is to return the headers to clear.
+            DDF header;
+            DDF ret=DDF(NULL).list();
+            DDFJanitor jret(ret);
+            for (vector< pair<string,string> >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) {
+                header = DDF(i->first.c_str()).string(i->second.c_str());
+                ret.add(header);
+            }
+            out << ret;
+        }
+
+        // Provides filter to exclude special config elements.
+#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
+        short
+#else
+        FilterAction
+#endif
+        acceptNode(const DOMNode* node) const;
+
+    private:
+        void cleanup();
+        const XMLApplication* m_base;
+        string m_hash;
+        std::pair<std::string,std::string> m_attributePrefix;
+#ifndef SHIBSP_LITE
+        MetadataProvider* m_metadata;
+        TrustEngine* m_trust;
+        AttributeExtractor* m_attrExtractor;
+        AttributeFilter* m_attrFilter;
+        AttributeResolver* m_attrResolver;
+        CredentialResolver* m_credResolver;
+        vector<const XMLCh*> m_audiences;
+
+        // RelyingParty properties
+        map<xstring,PropertySet*> m_partyMap;
+#endif
+        vector<string> m_remoteUsers,m_frontLogout,m_backLogout;
+
+        // manage handler objects
+        vector<Handler*> m_handlers;
+
+        // maps location (path info) to applicable handlers
+        map<string,const Handler*> m_handlerMap;
+
+        // maps unique indexes to consumer services
+        map<unsigned int,const Handler*> m_acsIndexMap;
+
+        // pointer to default consumer service
+        const Handler* m_acsDefault;
+
+        // maps binding strings to supporting consumer service(s)
+        typedef map<xstring,vector<const Handler*> > ACSBindingMap;
+        ACSBindingMap m_acsBindingMap;
+
+        // pointer to default session initiator
+        const SessionInitiator* m_sessionInitDefault;
+
+        // maps unique ID strings to session initiators
+        map<string,const SessionInitiator*> m_sessionInitMap;
+
+        // pointer to default artifact resolution service
+        const Handler* m_artifactResolutionDefault;
+
+        pair<bool,int> getArtifactEndpointIndex() const {
+            if (m_artifactResolutionDefault) return m_artifactResolutionDefault->getInt("index");
+            return m_base ? m_base->getArtifactEndpointIndex() : make_pair(false,0);
+        }
+    };
+
+    // Top-level configuration implementation
+    class SHIBSP_DLLLOCAL XMLConfig;
+    class SHIBSP_DLLLOCAL XMLConfigImpl : public DOMPropertySet, public DOMNodeFilter
+    {
+    public:
+        XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer, Category& log);
+        ~XMLConfigImpl();
+
+        RequestMapper* m_requestMapper;
+        map<string,Application*> m_appmap;
+#ifndef SHIBSP_LITE
+        map< string,pair< PropertySet*,vector<const SecurityPolicyRule*> > > m_policyMap;
+        vector< pair< string, pair<string,string> > > m_transportOptions;
+#endif
+
+        // Provides filter to exclude special config elements.
+#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
+        short
+#else
+        FilterAction
+#endif
+        acceptNode(const DOMNode* node) const;
+
+        void setDocument(DOMDocument* doc) {
+            m_document = doc;
+        }
+
+    private:
+        void doExtensions(const DOMElement* e, const char* label, Category& log);
+        void cleanup();
+
+        const XMLConfig* m_outer;
+        DOMDocument* m_document;
+    };
+
+    class SHIBSP_DLLLOCAL XMLConfig : public ServiceProvider, public ReloadableXMLFile
+#ifndef SHIBSP_LITE
+        ,public Remoted
+#endif
+    {
+    public:
+        XMLConfig(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".Config")),
+            m_impl(NULL), m_listener(NULL), m_sessionCache(NULL)
+#ifndef SHIBSP_LITE
+            , m_tranLog(NULL)
+#endif
+        {
+        }
+
+        void init() {
+            load();
+        }
+
+        ~XMLConfig() {
+            delete m_impl;
+            delete m_sessionCache;
+            delete m_listener;
+#ifndef SHIBSP_LITE
+            delete m_tranLog;
+            SAMLConfig::getConfig().setArtifactMap(NULL);
+            XMLToolingConfig::getConfig().setReplayCache(NULL);
+            for_each(m_storage.begin(), m_storage.end(), cleanup_pair<string,StorageService>());
+#endif
+        }
+
+        // PropertySet
+        const PropertySet* getParent() const { return m_impl->getParent(); }
+        void setParent(const PropertySet* parent) {return m_impl->setParent(parent);}
+        pair<bool,bool> getBool(const char* name, const char* ns=NULL) const {return m_impl->getBool(name,ns);}
+        pair<bool,const char*> getString(const char* name, const char* ns=NULL) const {return m_impl->getString(name,ns);}
+        pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const {return m_impl->getXMLString(name,ns);}
+        pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const {return m_impl->getUnsignedInt(name,ns);}
+        pair<bool,int> getInt(const char* name, const char* ns=NULL) const {return m_impl->getInt(name,ns);}
+        void getAll(map<string,const char*>& properties) const {return m_impl->getAll(properties);}
+        const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:2.0:native:sp:config") const {return m_impl->getPropertySet(name,ns);}
+        const DOMElement* getElement() const {return m_impl->getElement();}
+
+        // ServiceProvider
+#ifndef SHIBSP_LITE
+        // Remoted
+        void receive(DDF& in, ostream& out);
+
+        TransactionLog* getTransactionLog() const {
+            if (m_tranLog)
+                return m_tranLog;
+            throw ConfigurationException("No TransactionLog available.");
+        }
+
+        StorageService* getStorageService(const char* id) const {
+            if (id) {
+                map<string,StorageService*>::const_iterator i=m_storage.find(id);
+                if (i!=m_storage.end())
+                    return i->second;
+            }
+            return NULL;
+        }
+#endif
+
+        ListenerService* getListenerService(bool required=true) const {
+            if (required && !m_listener)
+                throw ConfigurationException("No ListenerService available.");
+            return m_listener;
+        }
+
+        SessionCache* getSessionCache(bool required=true) const {
+            if (required && !m_sessionCache)
+                throw ConfigurationException("No SessionCache available.");
+            return m_sessionCache;
+        }
+
+        RequestMapper* getRequestMapper(bool required=true) const {
+            if (required && !m_impl->m_requestMapper)
+                throw ConfigurationException("No RequestMapper available.");
+            return m_impl->m_requestMapper;
+        }
+
+        const Application* getApplication(const char* applicationId) const {
+            map<string,Application*>::const_iterator i=m_impl->m_appmap.find(applicationId);
+            return (i!=m_impl->m_appmap.end()) ? i->second : NULL;
+        }
+
+#ifndef SHIBSP_LITE
+        const PropertySet* getPolicySettings(const char* id) const {
+            map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);
+            if (i!=m_impl->m_policyMap.end())
+                return i->second.first;
+            throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));
+        }
+
+        const vector<const SecurityPolicyRule*>& getPolicyRules(const char* id) const {
+            map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);
+            if (i!=m_impl->m_policyMap.end())
+                return i->second.second;
+            throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));
+        }
+
+        bool setTransportOptions(SOAPTransport& transport) const {
+            bool ret = true;
+            vector< pair< string, pair<string,string> > >::const_iterator opt;
+            for (opt = m_impl->m_transportOptions.begin(); opt != m_impl->m_transportOptions.end(); ++opt) {
+                if (!transport.setProviderOption(opt->first.c_str(), opt->second.first.c_str(), opt->second.second.c_str())) {
+                    m_log.error("failed to set SOAPTransport option (%s)", opt->second.first.c_str());
+                    ret = false;
+                }
+            }
+            return ret;
+        }
+#endif
+
+    protected:
+        pair<bool,DOMElement*> load();
+
+    private:
+        friend class XMLConfigImpl;
+        XMLConfigImpl* m_impl;
+        mutable ListenerService* m_listener;
+        mutable SessionCache* m_sessionCache;
+#ifndef SHIBSP_LITE
+        mutable TransactionLog* m_tranLog;
+        mutable map<string,StorageService*> m_storage;
+#endif
+    };
+
+#if defined (_MSC_VER)
+    #pragma warning( pop )
+#endif
+
+    static const XMLCh ApplicationOverride[] =  UNICODE_LITERAL_19(A,p,p,l,i,c,a,t,i,o,n,O,v,e,r,r,i,d,e);
+    static const XMLCh ApplicationDefaults[] =  UNICODE_LITERAL_19(A,p,p,l,i,c,a,t,i,o,n,D,e,f,a,u,l,t,s);
+    static const XMLCh _ArtifactMap[] =         UNICODE_LITERAL_11(A,r,t,i,f,a,c,t,M,a,p);
+    static const XMLCh _AttributeExtractor[] =  UNICODE_LITERAL_18(A,t,t,r,i,b,u,t,e,E,x,t,r,a,c,t,o,r);
+    static const XMLCh _AttributeFilter[] =     UNICODE_LITERAL_15(A,t,t,r,i,b,u,t,e,F,i,l,t,e,r);
+    static const XMLCh _AttributeResolver[] =   UNICODE_LITERAL_17(A,t,t,r,i,b,u,t,e,R,e,s,o,l,v,e,r);
+    static const XMLCh _AssertionConsumerService[] = UNICODE_LITERAL_24(A,s,s,e,r,t,i,o,n,C,o,n,s,u,m,e,r,S,e,r,v,i,c,e);
+    static const XMLCh _ArtifactResolutionService[] =UNICODE_LITERAL_25(A,r,t,i,f,a,c,t,R,e,s,o,l,u,t,i,o,n,S,e,r,v,i,c,e);
+    static const XMLCh _Audience[] =            UNICODE_LITERAL_8(A,u,d,i,e,n,c,e);
+    static const XMLCh Binding[] =              UNICODE_LITERAL_7(B,i,n,d,i,n,g);
+    static const XMLCh Channel[]=               UNICODE_LITERAL_7(C,h,a,n,n,e,l);
+    static const XMLCh _CredentialResolver[] =  UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);
+    static const XMLCh _Extensions[] =          UNICODE_LITERAL_10(E,x,t,e,n,s,i,o,n,s);
+    static const XMLCh _fatal[] =               UNICODE_LITERAL_5(f,a,t,a,l);
+    static const XMLCh _Handler[] =             UNICODE_LITERAL_7(H,a,n,d,l,e,r);
+    static const XMLCh _id[] =                  UNICODE_LITERAL_2(i,d);
+    static const XMLCh InProcess[] =            UNICODE_LITERAL_9(I,n,P,r,o,c,e,s,s);
+    static const XMLCh Library[] =              UNICODE_LITERAL_7(L,i,b,r,a,r,y);
+    static const XMLCh Listener[] =             UNICODE_LITERAL_8(L,i,s,t,e,n,e,r);
+    static const XMLCh Location[] =             UNICODE_LITERAL_8(L,o,c,a,t,i,o,n);
+    static const XMLCh logger[] =               UNICODE_LITERAL_6(l,o,g,g,e,r);
+    static const XMLCh _LogoutInitiator[] =     UNICODE_LITERAL_15(L,o,g,o,u,t,I,n,i,t,i,a,t,o,r);
+    static const XMLCh _ManageNameIDService[] = UNICODE_LITERAL_19(M,a,n,a,g,e,N,a,m,e,I,D,S,e,r,v,i,c,e);
+    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 Notify[] =               UNICODE_LITERAL_6(N,o,t,i,f,y);
+    static const XMLCh _option[] =              UNICODE_LITERAL_6(o,p,t,i,o,n);
+    static const XMLCh OutOfProcess[] =         UNICODE_LITERAL_12(O,u,t,O,f,P,r,o,c,e,s,s);
+    static const XMLCh _path[] =                UNICODE_LITERAL_4(p,a,t,h);
+    static const XMLCh Policy[] =               UNICODE_LITERAL_6(P,o,l,i,c,y);
+    static const XMLCh PolicyRule[] =           UNICODE_LITERAL_10(P,o,l,i,c,y,R,u,l,e);
+    static const XMLCh _provider[] =            UNICODE_LITERAL_8(p,r,o,v,i,d,e,r);
+    static const XMLCh RelyingParty[] =         UNICODE_LITERAL_12(R,e,l,y,i,n,g,P,a,r,t,y);
+    static const XMLCh _ReplayCache[] =         UNICODE_LITERAL_11(R,e,p,l,a,y,C,a,c,h,e);
+    static const XMLCh _RequestMapper[] =       UNICODE_LITERAL_13(R,e,q,u,e,s,t,M,a,p,p,e,r);
+    static const XMLCh Rule[] =                 UNICODE_LITERAL_4(R,u,l,e);
+    static const XMLCh SecurityPolicies[] =     UNICODE_LITERAL_16(S,e,c,u,r,i,t,y,P,o,l,i,c,i,e,s);
+    static const XMLCh _SessionCache[] =        UNICODE_LITERAL_12(S,e,s,s,i,o,n,C,a,c,h,e);
+    static const XMLCh _SessionInitiator[] =    UNICODE_LITERAL_16(S,e,s,s,i,o,n,I,n,i,t,i,a,t,o,r);
+    static const XMLCh _SingleLogoutService[] = UNICODE_LITERAL_19(S,i,n,g,l,e,L,o,g,o,u,t,S,e,r,v,i,c,e);
+    static const XMLCh Site[] =                 UNICODE_LITERAL_4(S,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 TCPListener[] =          UNICODE_LITERAL_11(T,C,P,L,i,s,t,e,n,e,r);
+    static const XMLCh TransportOption[] =      UNICODE_LITERAL_15(T,r,a,n,s,p,o,r,t,O,p,t,i,o,n);
+    static const XMLCh _TrustEngine[] =         UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e);
+    static const XMLCh _type[] =                UNICODE_LITERAL_4(t,y,p,e);
+    static const XMLCh UnixListener[] =         UNICODE_LITERAL_12(U,n,i,x,L,i,s,t,e,n,e,r);
+
+#ifndef SHIBSP_LITE
+    class SHIBSP_DLLLOCAL PolicyNodeFilter : public DOMNodeFilter
+    {
+    public:
+#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
+        short
+#else
+        FilterAction
+#endif
+        acceptNode(const DOMNode* node) const {
+            return FILTER_REJECT;
+        }
+    };
+#endif
+};
+
+namespace shibsp {
+    ServiceProvider* XMLServiceProviderFactory(const DOMElement* const & e)
+    {
+        return new XMLConfig(e);
+    }
+};
+
+XMLApplication::XMLApplication(
+    const ServiceProvider* sp,
+    const DOMElement* e,
+    const XMLApplication* base
+    ) : Application(sp), m_base(base),
+#ifndef SHIBSP_LITE
+        m_metadata(NULL), m_trust(NULL),
+        m_attrExtractor(NULL), m_attrFilter(NULL), m_attrResolver(NULL),
+        m_credResolver(NULL),
+#endif
+        m_acsDefault(NULL), m_sessionInitDefault(NULL), m_artifactResolutionDefault(NULL)
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("XMLApplication");
+#endif
+    Category& log=Category::getInstance(SHIBSP_LOGCAT".Application");
+
+    try {
+        // First load any property sets.
+        load(e,NULL,this);
+        if (base)
+            setParent(base);
+
+        SPConfig& conf=SPConfig::getConfig();
+#ifndef SHIBSP_LITE
+        SAMLConfig& samlConf=SAMLConfig::getConfig();
+        XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();
+#endif
+
+        // This used to be an actual hash, but now it's just a hex-encode to avoid xmlsec.
+        static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+        string tohash=getId();
+        tohash+=getString("entityID").second;
+        for (const char* ch = tohash.c_str(); *ch; ++ch) {
+            m_hash += (DIGITS[((unsigned char)(0xF0 & *ch)) >> 4 ]);
+            m_hash += (DIGITS[0x0F & *ch]);
+        }
+
+        // Populate prefix pair.
+        m_attributePrefix.second = "HTTP_";
+        pair<bool,const char*> prefix = getString("attributePrefix");
+        if (prefix.first) {
+            m_attributePrefix.first = prefix.second;
+            const char* pch = prefix.second;
+            while (*pch) {
+                m_attributePrefix.second += (isalnum(*pch) ? toupper(*pch) : '_');
+                pch++;
+            }
+        }
+
+        // Load attribute ID lists for REMOTE_USER and header clearing.
+        if (conf.isEnabled(SPConfig::InProcess)) {
+            pair<bool,const char*> attributes = getString("REMOTE_USER");
+            if (attributes.first) {
+                char* dup = strdup(attributes.second);
+                char* pos;
+                char* start = dup;
+                while (start && *start) {
+                    while (*start && isspace(*start))
+                        start++;
+                    if (!*start)
+                        break;
+                    pos = strchr(start,' ');
+                    if (pos)
+                        *pos=0;
+                    m_remoteUsers.push_back(start);
+                    start = pos ? pos+1 : NULL;
+                }
+                free(dup);
+            }
+
+            attributes = getString("unsetHeaders");
+            if (attributes.first) {
+                string transformedprefix(m_attributePrefix.second);
+                const char* pch;
+                prefix = getString("metadataAttributePrefix");
+                if (prefix.first) {
+                    pch = prefix.second;
+                    while (*pch) {
+                        transformedprefix += (isalnum(*pch) ? toupper(*pch) : '_');
+                        pch++;
+                    }
+                }
+                char* dup = strdup(attributes.second);
+                char* pos;
+                char* start = dup;
+                while (start && *start) {
+                    while (*start && isspace(*start))
+                        start++;
+                    if (!*start)
+                        break;
+                    pos = strchr(start,' ');
+                    if (pos)
+                        *pos=0;
+
+                    string transformed;
+                    pch = start;
+                    while (*pch) {
+                        transformed += (isalnum(*pch) ? toupper(*pch) : '_');
+                        pch++;
+                    }
+
+                    m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + start, m_attributePrefix.second + transformed));
+                    if (prefix.first)
+                        m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + prefix.second + start, transformedprefix + transformed));
+                    start = pos ? pos+1 : NULL;
+                }
+                free(dup);
+                m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + "Shib-Application-ID", m_attributePrefix.second + "SHIB_APPLICATION_ID"));
+            }
+        }
+
+        Handler* handler=NULL;
+        const PropertySet* sessions = getPropertySet("Sessions");
+
+        // Process assertion export handler.
+        pair<bool,const char*> location = sessions ? sessions->getString("exportLocation") : pair<bool,const char*>(false,NULL);
+        if (location.first) {
+            try {
+                DOMElement* exportElement = e->getOwnerDocument()->createElementNS(shibspconstants::SHIB2SPCONFIG_NS,_Handler);
+                exportElement->setAttributeNS(NULL,Location,sessions->getXMLString("exportLocation").second);
+                pair<bool,const XMLCh*> exportACL = sessions->getXMLString("exportACL");
+                if (exportACL.first) {
+                    static const XMLCh _acl[] = UNICODE_LITERAL_9(e,x,p,o,r,t,A,C,L);
+                    exportElement->setAttributeNS(NULL,_acl,exportACL.second);
+                }
+                handler = conf.HandlerManager.newPlugin(
+                    samlconstants::SAML20_BINDING_URI, pair<const DOMElement*,const char*>(exportElement, getId())
+                    );
+                m_handlers.push_back(handler);
+
+                // Insert into location map. If it contains the handlerURL, we skip past that part.
+                const char* pch = strstr(location.second, sessions->getString("handlerURL").second);
+                if (pch)
+                    location.second = pch + strlen(sessions->getString("handlerURL").second);
+                if (*location.second == '/')
+                    m_handlerMap[location.second]=handler;
+                else
+                    m_handlerMap[string("/") + location.second]=handler;
+            }
+            catch (exception& ex) {
+                log.error("caught exception installing assertion lookup handler: %s", ex.what());
+            }
+        }
+
+        // Process other handlers.
+        bool hardACS=false, hardSessionInit=false, hardArt=false;
+        const DOMElement* child = sessions ? XMLHelper::getFirstChildElement(sessions->getElement()) : NULL;
+        while (child) {
+            try {
+                // A handler is based on the Binding property in conjunction with the element name.
+                // If it's an ACS or SI, also handle index/id mappings and defaulting.
+                if (XMLString::equals(child->getLocalName(),_AssertionConsumerService)) {
+                    auto_ptr_char bindprop(child->getAttributeNS(NULL,Binding));
+                    if (!bindprop.get() || !*(bindprop.get())) {
+                        log.warn("md:AssertionConsumerService element has no Binding attribute, skipping it...");
+                        child = XMLHelper::getNextSiblingElement(child);
+                        continue;
+                    }
+                    handler=conf.AssertionConsumerServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));
+                    // Map by binding (may be > 1 per binding, e.g. SAML 1.0 vs 1.1)
+                    m_acsBindingMap[handler->getXMLString("Binding").second].push_back(handler);
+                    m_acsIndexMap[handler->getUnsignedInt("index").second]=handler;
+
+                    if (!hardACS) {
+                        pair<bool,bool> defprop=handler->getBool("isDefault");
+                        if (defprop.first) {
+                            if (defprop.second) {
+                                hardACS=true;
+                                m_acsDefault=handler;
+                            }
+                        }
+                        else if (!m_acsDefault)
+                            m_acsDefault=handler;
+                    }
+                }
+                else if (XMLString::equals(child->getLocalName(),_SessionInitiator)) {
+                    auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                    if (!type.get() || !*(type.get())) {
+                        log.warn("SessionInitiator element has no type attribute, skipping it...");
+                        child = XMLHelper::getNextSiblingElement(child);
+                        continue;
+                    }
+                    SessionInitiator* sihandler=conf.SessionInitiatorManager.newPlugin(type.get(),make_pair(child, getId()));
+                    handler=sihandler;
+                    pair<bool,const char*> si_id=handler->getString("id");
+                    if (si_id.first && si_id.second)
+                        m_sessionInitMap[si_id.second]=sihandler;
+                    if (!hardSessionInit) {
+                        pair<bool,bool> defprop=handler->getBool("isDefault");
+                        if (defprop.first) {
+                            if (defprop.second) {
+                                hardSessionInit=true;
+                                m_sessionInitDefault=sihandler;
+                            }
+                        }
+                        else if (!m_sessionInitDefault)
+                            m_sessionInitDefault=sihandler;
+                    }
+                }
+                else if (XMLString::equals(child->getLocalName(),_LogoutInitiator)) {
+                    auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                    if (!type.get() || !*(type.get())) {
+                        log.warn("LogoutInitiator element has no type attribute, skipping it...");
+                        child = XMLHelper::getNextSiblingElement(child);
+                        continue;
+                    }
+                    handler=conf.LogoutInitiatorManager.newPlugin(type.get(),make_pair(child, getId()));
+                }
+                else if (XMLString::equals(child->getLocalName(),_ArtifactResolutionService)) {
+                    auto_ptr_char bindprop(child->getAttributeNS(NULL,Binding));
+                    if (!bindprop.get() || !*(bindprop.get())) {
+                        log.warn("md:ArtifactResolutionService element has no Binding attribute, skipping it...");
+                        child = XMLHelper::getNextSiblingElement(child);
+                        continue;
+                    }
+                    handler=conf.ArtifactResolutionServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));
+
+                    if (!hardArt) {
+                        pair<bool,bool> defprop=handler->getBool("isDefault");
+                        if (defprop.first) {
+                            if (defprop.second) {
+                                hardArt=true;
+                                m_artifactResolutionDefault=handler;
+                            }
+                        }
+                        else if (!m_artifactResolutionDefault)
+                            m_artifactResolutionDefault=handler;
+                    }
+                }
+                else if (XMLString::equals(child->getLocalName(),_SingleLogoutService)) {
+                    auto_ptr_char bindprop(child->getAttributeNS(NULL,Binding));
+                    if (!bindprop.get() || !*(bindprop.get())) {
+                        log.warn("md:SingleLogoutService element has no Binding attribute, skipping it...");
+                        child = XMLHelper::getNextSiblingElement(child);
+                        continue;
+                    }
+                    handler=conf.SingleLogoutServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));
+                }
+                else if (XMLString::equals(child->getLocalName(),_ManageNameIDService)) {
+                    auto_ptr_char bindprop(child->getAttributeNS(NULL,Binding));
+                    if (!bindprop.get() || !*(bindprop.get())) {
+                        log.warn("md:ManageNameIDService element has no Binding attribute, skipping it...");
+                        child = XMLHelper::getNextSiblingElement(child);
+                        continue;
+                    }
+                    handler=conf.ManageNameIDServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));
+                }
+                else {
+                    auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                    if (!type.get() || !*(type.get())) {
+                        log.warn("Handler element has no type attribute, skipping it...");
+                        child = XMLHelper::getNextSiblingElement(child);
+                        continue;
+                    }
+                    handler=conf.HandlerManager.newPlugin(type.get(),make_pair(child, getId()));
+                }
+
+                m_handlers.push_back(handler);
+
+                // Insert into location map.
+                location=handler->getString("Location");
+                if (location.first && *location.second == '/')
+                    m_handlerMap[location.second]=handler;
+                else if (location.first)
+                    m_handlerMap[string("/") + location.second]=handler;
+
+            }
+            catch (exception& ex) {
+                log.error("caught exception processing handler element: %s", ex.what());
+            }
+
+            child = XMLHelper::getNextSiblingElement(child);
+        }
+
+        // Notification.
+        DOMNodeList* nlist=e->getElementsByTagNameNS(shibspconstants::SHIB2SPCONFIG_NS,Notify);
+        for (XMLSize_t i=0; nlist && i<nlist->getLength(); i++) {
+            if (nlist->item(i)->getParentNode()->isSameNode(e)) {
+                const XMLCh* channel = static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,Channel);
+                auto_ptr_char loc(static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,Location));
+                if (loc.get() && *loc.get()) {
+                    if (channel && *channel == chLatin_f)
+                        m_frontLogout.push_back(loc.get());
+                    else
+                        m_backLogout.push_back(loc.get());
+                }
+            }
+        }
+
+#ifndef SHIBSP_LITE
+        nlist=e->getElementsByTagNameNS(samlconstants::SAML20_NS,Audience::LOCAL_NAME);
+        if (nlist && nlist->getLength()) {
+            log.warn("use of <saml:Audience> elements outside of a Security Policy Rule is deprecated");
+            for (XMLSize_t i=0; i<nlist->getLength(); i++)
+                if (nlist->item(i)->getParentNode()->isSameNode(e) && nlist->item(i)->hasChildNodes())
+                    m_audiences.push_back(nlist->item(i)->getFirstChild()->getNodeValue());
+        }
+
+        if (conf.isEnabled(SPConfig::Metadata)) {
+            child = XMLHelper::getFirstChildElement(e,_MetadataProvider);
+            if (child) {
+                auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                log.info("building MetadataProvider of type %s...",type.get());
+                try {
+                    auto_ptr<MetadataProvider> mp(samlConf.MetadataProviderManager.newPlugin(type.get(),child));
+                    mp->init();
+                    m_metadata = mp.release();
+                }
+                catch (exception& ex) {
+                    log.crit("error building/initializing MetadataProvider: %s", ex.what());
+                }
+            }
+        }
+
+        if (conf.isEnabled(SPConfig::Trust)) {
+            child = XMLHelper::getFirstChildElement(e,_TrustEngine);
+            if (child) {
+                auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                log.info("building TrustEngine of type %s...",type.get());
+                try {
+                    m_trust = xmlConf.TrustEngineManager.newPlugin(type.get(),child);
+                }
+                catch (exception& ex) {
+                    log.crit("error building TrustEngine: %s", ex.what());
+                }
+            }
+        }
+
+        if (conf.isEnabled(SPConfig::AttributeResolution)) {
+            child = XMLHelper::getFirstChildElement(e,_AttributeExtractor);
+            if (child) {
+                auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                log.info("building AttributeExtractor of type %s...",type.get());
+                try {
+                    m_attrExtractor = conf.AttributeExtractorManager.newPlugin(type.get(),child);
+                }
+                catch (exception& ex) {
+                    log.crit("error building AttributeExtractor: %s", ex.what());
+                }
+            }
+
+            child = XMLHelper::getFirstChildElement(e,_AttributeFilter);
+            if (child) {
+                auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                log.info("building AttributeFilter of type %s...",type.get());
+                try {
+                    m_attrFilter = conf.AttributeFilterManager.newPlugin(type.get(),child);
+                }
+                catch (exception& ex) {
+                    log.crit("error building AttributeFilter: %s", ex.what());
+                }
+            }
+
+            child = XMLHelper::getFirstChildElement(e,_AttributeResolver);
+            if (child) {
+                auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                log.info("building AttributeResolver of type %s...",type.get());
+                try {
+                    m_attrResolver = conf.AttributeResolverManager.newPlugin(type.get(),child);
+                }
+                catch (exception& ex) {
+                    log.crit("error building AttributeResolver: %s", ex.what());
+                }
+            }
+
+            if (m_unsetHeaders.empty()) {
+                vector<string> unsetHeaders;
+                if (m_attrExtractor) {
+                    Locker extlock(m_attrExtractor);
+                    m_attrExtractor->getAttributeIds(unsetHeaders);
+                }
+                else if (m_base && m_base->m_attrExtractor) {
+                    Locker extlock(m_base->m_attrExtractor);
+                    m_base->m_attrExtractor->getAttributeIds(unsetHeaders);
+                }
+                if (m_attrResolver) {
+                    Locker reslock(m_attrResolver);
+                    m_attrResolver->getAttributeIds(unsetHeaders);
+                }
+                else if (m_base && m_base->m_attrResolver) {
+                    Locker extlock(m_base->m_attrResolver);
+                    m_base->m_attrResolver->getAttributeIds(unsetHeaders);
+                }
+                if (!unsetHeaders.empty()) {
+                    string transformedprefix(m_attributePrefix.second);
+                    const char* pch;
+                    pair<bool,const char*> prefix = getString("metadataAttributePrefix");
+                    if (prefix.first) {
+                        pch = prefix.second;
+                        while (*pch) {
+                            transformedprefix += (isalnum(*pch) ? toupper(*pch) : '_');
+                            pch++;
+                        }
+                    }
+                    for (vector<string>::const_iterator hdr = unsetHeaders.begin(); hdr!=unsetHeaders.end(); ++hdr) {
+                        string transformed;
+                        pch = hdr->c_str();
+                        while (*pch) {
+                            transformed += (isalnum(*pch) ? toupper(*pch) : '_');
+                            pch++;
+                        }
+                        m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + *hdr, m_attributePrefix.second + transformed));
+                        if (prefix.first)
+                            m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + prefix.second + *hdr, transformedprefix + transformed));
+                    }
+                }
+                m_unsetHeaders.push_back(pair<string,string>(m_attributePrefix.first + "Shib-Application-ID", m_attributePrefix.second + "SHIB_APPLICATION_ID"));
+            }
+        }
+
+        if (conf.isEnabled(SPConfig::Credentials)) {
+            child = XMLHelper::getFirstChildElement(e,_CredentialResolver);
+            if (child) {
+                auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                log.info("building CredentialResolver of type %s...",type.get());
+                try {
+                    m_credResolver = xmlConf.CredentialResolverManager.newPlugin(type.get(),child);
+                }
+                catch (exception& ex) {
+                    log.crit("error building CredentialResolver: %s", ex.what());
+                }
+            }
+        }
+
+        // Finally, load relying parties.
+        child = XMLHelper::getFirstChildElement(e,RelyingParty);
+        while (child) {
+            auto_ptr<DOMPropertySet> rp(new DOMPropertySet());
+            rp->load(child,NULL,this);
+            rp->setParent(this);
+            m_partyMap[child->getAttributeNS(NULL,saml2::Attribute::NAME_ATTRIB_NAME)]=rp.release();
+            child = XMLHelper::getNextSiblingElement(child,RelyingParty);
+        }
+#endif
+
+        // Out of process only, we register a listener endpoint.
+        if (!conf.isEnabled(SPConfig::InProcess)) {
+            ListenerService* listener = sp->getListenerService(false);
+            if (listener) {
+                string addr=string(getId()) + "::getHeaders::Application";
+                listener->regListener(addr.c_str(),this);
+            }
+            else
+                log.info("no ListenerService available, Application remoting disabled");
+        }
+    }
+    catch (exception&) {
+        cleanup();
+        throw;
+    }
+#ifndef _DEBUG
+    catch (...) {
+        cleanup();
+        throw;
+    }
+#endif
+}
+
+void XMLApplication::cleanup()
+{
+    ListenerService* listener=getServiceProvider().getListenerService(false);
+    if (listener && SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess) && !SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
+        string addr=string(getId()) + "::getHeaders::Application";
+        listener->unregListener(addr.c_str(),this);
+    }
+    for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());
+    m_handlers.clear();
+#ifndef SHIBSP_LITE
+    for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair<xstring,PropertySet>());
+    m_partyMap.clear();
+    delete m_credResolver;
+    m_credResolver = NULL;
+    delete m_attrResolver;
+    m_attrResolver = NULL;
+    delete m_attrFilter;
+    m_attrFilter = NULL;
+    delete m_attrExtractor;
+    m_attrExtractor = NULL;
+    delete m_trust;
+    m_trust = NULL;
+    delete m_metadata;
+    m_metadata = NULL;
+#endif
+}
+
+#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
+short
+#else
+DOMNodeFilter::FilterAction
+#endif
+XMLApplication::acceptNode(const DOMNode* node) const
+{
+    const XMLCh* name=node->getLocalName();
+    if (XMLString::equals(name,ApplicationOverride) ||
+        XMLString::equals(name,_Audience) ||
+        XMLString::equals(name,Notify) ||
+        XMLString::equals(name,_Handler) ||
+        XMLString::equals(name,_AssertionConsumerService) ||
+        XMLString::equals(name,_ArtifactResolutionService) ||
+        XMLString::equals(name,_LogoutInitiator) ||
+        XMLString::equals(name,_ManageNameIDService) ||
+        XMLString::equals(name,_SessionInitiator) ||
+        XMLString::equals(name,_SingleLogoutService) ||
+        XMLString::equals(name,RelyingParty) ||
+        XMLString::equals(name,_MetadataProvider) ||
+        XMLString::equals(name,_TrustEngine) ||
+        XMLString::equals(name,_CredentialResolver) ||
+        XMLString::equals(name,_AttributeFilter) ||
+        XMLString::equals(name,_AttributeExtractor) ||
+        XMLString::equals(name,_AttributeResolver))
+        return FILTER_REJECT;
+
+    return FILTER_ACCEPT;
+}
+
+#ifndef SHIBSP_LITE
+
+const PropertySet* XMLApplication::getRelyingParty(const EntityDescriptor* provider) const
+{
+    if (!provider)
+        return this;
+
+    map<xstring,PropertySet*>::const_iterator i=m_partyMap.find(provider->getEntityID());
+    if (i!=m_partyMap.end())
+        return i->second;
+    const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());
+    while (group) {
+        if (group->getName()) {
+            i=m_partyMap.find(group->getName());
+            if (i!=m_partyMap.end())
+                return i->second;
+        }
+        group=dynamic_cast<const EntitiesDescriptor*>(group->getParent());
+    }
+    return this;
+}
+
+const PropertySet* XMLApplication::getRelyingParty(const XMLCh* entityID) const
+{
+    if (!entityID)
+        return this;
+
+    map<xstring,PropertySet*>::const_iterator i=m_partyMap.find(entityID);
+    if (i!=m_partyMap.end())
+        return i->second;
+    return this;
+}
+
+#endif
+
+string XMLApplication::getNotificationURL(const char* resource, bool front, unsigned int index) const
+{
+    const vector<string>& locs = front ? m_frontLogout : m_backLogout;
+    if (locs.empty())
+        return m_base ? m_base->getNotificationURL(resource, front, index) : string();
+    else if (index >= locs.size())
+        return string();
+
+#ifdef HAVE_STRCASECMP
+    if (!resource || (strncasecmp(resource,"http://",7) && strncasecmp(resource,"https://",8)))
+#else
+    if (!resource || (strnicmp(resource,"http://",7) && strnicmp(resource,"https://",8)))
+#endif
+        throw ConfigurationException("Request URL was not absolute.");
+
+    const char* handler=locs[index].c_str();
+
+    // Should never happen...
+    if (!handler || (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)))
+        throw ConfigurationException(
+            "Invalid Location property ($1) in Notify element for Application ($2)",
+            params(2, handler ? handler : "null", getId())
+            );
+
+    // The "Location" property can be in one of three formats:
+    //
+    // 1) a full URI:       http://host/foo/bar
+    // 2) a hostless URI:   http:///foo/bar
+    // 3) a relative path:  /foo/bar
+    //
+    // #  Protocol  Host        Path
+    // 1  handler   handler     handler
+    // 2  handler   resource    handler
+    // 3  resource  resource    handler
+
+    const char* path = NULL;
+
+    // Decide whether to use the handler or the resource for the "protocol"
+    const char* prot;
+    if (*handler != '/') {
+        prot = handler;
+    }
+    else {
+        prot = resource;
+        path = handler;
+    }
+
+    // break apart the "protocol" string into protocol, host, and "the rest"
+    const char* colon=strchr(prot,':');
+    colon += 3;
+    const char* slash=strchr(colon,'/');
+    if (!path)
+        path = slash;
+
+    // Compute the actual protocol and store.
+    string notifyURL(prot, colon-prot);
+
+    // create the "host" from either the colon/slash or from the target string
+    // If prot == handler then we're in either #1 or #2, else #3.
+    // If slash == colon then we're in #2.
+    if (prot != handler || slash == colon) {
+        colon = strchr(resource, ':');
+        colon += 3;      // Get past the ://
+        slash = strchr(colon, '/');
+    }
+    string host(colon, (slash ? slash-colon : strlen(colon)));
+
+    // Build the URL
+    notifyURL += host + path;
+    return notifyURL;
+}
+
+void XMLApplication::clearHeader(SPRequest& request, const char* rawname, const char* cginame) const
+{
+    if (!m_attributePrefix.first.empty()) {
+        string temp = m_attributePrefix.first + rawname;
+        string temp2 = m_attributePrefix.second + (cginame + 5);
+        request.clearHeader(temp.c_str(), temp2.c_str());
+    }
+    else if (m_base) {
+        m_base->clearHeader(request, rawname, cginame);
+    }
+    else {
+        request.clearHeader(rawname, cginame);
+    }
+}
+
+void XMLApplication::setHeader(SPRequest& request, const char* name, const char* value) const
+{
+    if (!m_attributePrefix.first.empty()) {
+        string temp = m_attributePrefix.first + name;
+        request.setHeader(temp.c_str(), value);
+    }
+    else if (m_base) {
+        m_base->setHeader(request, name, value);
+    }
+    else {
+        request.setHeader(name, value);
+    }
+}
+
+string XMLApplication::getSecureHeader(const SPRequest& request, const char* name) const
+{
+    if (!m_attributePrefix.first.empty()) {
+        string temp = m_attributePrefix.first + name;
+        return request.getSecureHeader(temp.c_str());
+    }
+    else if (m_base) {
+        return m_base->getSecureHeader(request,name);
+    }
+    else {
+        return request.getSecureHeader(name);
+    }
+}
+
+const SessionInitiator* XMLApplication::getDefaultSessionInitiator() const
+{
+    if (m_sessionInitDefault) return m_sessionInitDefault;
+    return m_base ? m_base->getDefaultSessionInitiator() : NULL;
+}
+
+const SessionInitiator* XMLApplication::getSessionInitiatorById(const char* id) const
+{
+    map<string,const SessionInitiator*>::const_iterator i=m_sessionInitMap.find(id);
+    if (i!=m_sessionInitMap.end()) return i->second;
+    return m_base ? m_base->getSessionInitiatorById(id) : NULL;
+}
+
+const Handler* XMLApplication::getDefaultAssertionConsumerService() const
+{
+    if (m_acsDefault) return m_acsDefault;
+    return m_base ? m_base->getDefaultAssertionConsumerService() : NULL;
+}
+
+const Handler* XMLApplication::getAssertionConsumerServiceByIndex(unsigned short index) const
+{
+    map<unsigned int,const Handler*>::const_iterator i=m_acsIndexMap.find(index);
+    if (i!=m_acsIndexMap.end()) return i->second;
+    return m_base ? m_base->getAssertionConsumerServiceByIndex(index) : NULL;
+}
+
+const vector<const Handler*>& XMLApplication::getAssertionConsumerServicesByBinding(const XMLCh* binding) const
+{
+    ACSBindingMap::const_iterator i=m_acsBindingMap.find(binding);
+    if (i!=m_acsBindingMap.end())
+        return i->second;
+    return m_base ? m_base->getAssertionConsumerServicesByBinding(binding) : g_noHandlers;
+}
+
+const Handler* XMLApplication::getHandler(const char* path) const
+{
+    string wrap(path);
+    wrap = wrap.substr(0,wrap.find(';'));
+    map<string,const Handler*>::const_iterator i=m_handlerMap.find(wrap.substr(0,wrap.find('?')));
+    if (i!=m_handlerMap.end())
+        return i->second;
+    return m_base ? m_base->getHandler(path) : NULL;
+}
+
+void XMLApplication::getHandlers(vector<const Handler*>& handlers) const
+{
+    handlers.insert(handlers.end(), m_handlers.begin(), m_handlers.end());
+    if (m_base) {
+        for (map<string,const Handler*>::const_iterator h = m_base->m_handlerMap.begin(); h != m_base->m_handlerMap.end(); ++h) {
+            if (m_handlerMap.count(h->first) == 0)
+                handlers.push_back(h->second);
+        }
+    }
+}
+
+#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
+short
+#else
+DOMNodeFilter::FilterAction
+#endif
+XMLConfigImpl::acceptNode(const DOMNode* node) const
+{
+    if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB2SPCONFIG_NS))
+        return FILTER_ACCEPT;
+    const XMLCh* name=node->getLocalName();
+    if (XMLString::equals(name,ApplicationDefaults) ||
+        XMLString::equals(name,_ArtifactMap) ||
+        XMLString::equals(name,_Extensions) ||
+        XMLString::equals(name,Listener) ||
+        XMLString::equals(name,_RequestMapper) ||
+        XMLString::equals(name,_ReplayCache) ||
+        XMLString::equals(name,SecurityPolicies) ||
+        XMLString::equals(name,_SessionCache) ||
+        XMLString::equals(name,Site) ||
+        XMLString::equals(name,_StorageService) ||
+        XMLString::equals(name,TCPListener) ||
+        XMLString::equals(name,TransportOption) ||
+        XMLString::equals(name,UnixListener))
+        return FILTER_REJECT;
+
+    return FILTER_ACCEPT;
+}
+
+void XMLConfigImpl::doExtensions(const DOMElement* e, const char* label, Category& log)
+{
+    const DOMElement* exts=XMLHelper::getFirstChildElement(e,_Extensions);
+    if (exts) {
+        exts=XMLHelper::getFirstChildElement(exts,Library);
+        while (exts) {
+            auto_ptr_char path(exts->getAttributeNS(NULL,_path));
+            try {
+                if (path.get()) {
+                    if (!XMLToolingConfig::getConfig().load_library(path.get(),(void*)exts))
+                        throw ConfigurationException("XMLToolingConfig::load_library failed.");
+                    log.debug("loaded %s extension library (%s)", label, path.get());
+                }
+            }
+            catch (exception& e) {
+                const XMLCh* fatal=exts->getAttributeNS(NULL,_fatal);
+                if (fatal && (*fatal==chLatin_t || *fatal==chDigit_1)) {
+                    log.fatal("unable to load mandatory %s extension library %s: %s", label, path.get(), e.what());
+                    throw;
+                }
+                else {
+                    log.crit("unable to load optional %s extension library %s: %s", label, path.get(), e.what());
+                }
+            }
+            exts=XMLHelper::getNextSiblingElement(exts,Library);
+        }
+    }
+}
+
+XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer, Category& log)
+    : m_requestMapper(NULL), m_outer(outer), m_document(NULL)
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("XMLConfigImpl");
+#endif
+
+    try {
+        SPConfig& conf=SPConfig::getConfig();
+#ifndef SHIBSP_LITE
+        SAMLConfig& samlConf=SAMLConfig::getConfig();
+#endif
+        XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();
+        const DOMElement* SHAR=XMLHelper::getFirstChildElement(e,OutOfProcess);
+        const DOMElement* SHIRE=XMLHelper::getFirstChildElement(e,InProcess);
+
+        // Initialize log4cpp manually in order to redirect log messages as soon as possible.
+        if (conf.isEnabled(SPConfig::Logging)) {
+            const XMLCh* logconf=NULL;
+            if (conf.isEnabled(SPConfig::OutOfProcess))
+                logconf=SHAR->getAttributeNS(NULL,logger);
+            else if (conf.isEnabled(SPConfig::InProcess))
+                logconf=SHIRE->getAttributeNS(NULL,logger);
+            if (!logconf || !*logconf)
+                logconf=e->getAttributeNS(NULL,logger);
+            if (logconf && *logconf) {
+                auto_ptr_char logpath(logconf);
+                log.debug("loading new logging configuration from (%s), check log destination for status of configuration",logpath.get());
+                if (!XMLToolingConfig::getConfig().log_config(logpath.get()))
+                    log.crit("failed to load new logging configuration from (%s)", logpath.get());
+            }
+
+#ifndef SHIBSP_LITE
+            if (first)
+                m_outer->m_tranLog = new TransactionLog();
+#endif
+        }
+
+        // Re-log library versions now that logging is set up.
+        log.info("Shibboleth SP Version %s", PACKAGE_VERSION);
+#ifndef SHIBSP_LITE
+        log.info(
+            "Library versions: Xerces-C %s, XML-Security-C %s, XMLTooling-C %s, OpenSAML-C %s, Shibboleth %s",
+            XERCES_FULLVERSIONDOT, XSEC_FULLVERSIONDOT, XMLTOOLING_FULLVERSIONDOT, OPENSAML_FULLVERSIONDOT, SHIBSP_FULLVERSIONDOT
+            );
+#else
+        log.info(
+            "Library versions: Xerces-C %s, XMLTooling-C %s, Shibboleth %s",
+            XERCES_FULLVERSIONDOT, XMLTOOLING_FULLVERSIONDOT, SHIBSP_FULLVERSIONDOT
+            );
+#endif
+
+        // First load any property sets.
+        load(e,NULL,this);
+
+        const DOMElement* child;
+        string plugtype;
+
+        // Much of the processing can only occur on the first instantiation.
+        if (first) {
+            // Set clock skew.
+            pair<bool,unsigned int> skew=getUnsignedInt("clockSkew");
+            if (skew.first)
+                xmlConf.clock_skew_secs=min(skew.second,(60*60*24*7*28));
+
+            pair<bool,const char*> unsafe = getString("unsafeChars");
+            if (unsafe.first)
+                TemplateEngine::unsafe_chars = unsafe.second;
+
+            unsafe = getString("allowedSchemes");
+            if (unsafe.first) {
+                HTTPResponse::getAllowedSchemes().clear();
+                string schemes=unsafe.second;
+                unsigned int j_sch=0;
+                for (unsigned int i_sch=0;  i_sch < schemes.length();  i_sch++) {
+                    if (schemes.at(i_sch)==' ') {
+                        HTTPResponse::getAllowedSchemes().push_back(schemes.substr(j_sch, i_sch-j_sch));
+                        j_sch = i_sch + 1;
+                    }
+                }
+                HTTPResponse::getAllowedSchemes().push_back(schemes.substr(j_sch, schemes.length()-j_sch));
+            }
+
+            // Extensions
+            doExtensions(e, "global", log);
+            if (conf.isEnabled(SPConfig::OutOfProcess))
+                doExtensions(SHAR, "out of process", log);
+
+            if (conf.isEnabled(SPConfig::InProcess))
+                doExtensions(SHIRE, "in process", log);
+
+            // Instantiate the ListenerService and SessionCache objects.
+            if (conf.isEnabled(SPConfig::Listener)) {
+                child=XMLHelper::getFirstChildElement(e,UnixListener);
+                if (child)
+                    plugtype=UNIX_LISTENER_SERVICE;
+                else {
+                    child=XMLHelper::getFirstChildElement(e,TCPListener);
+                    if (child)
+                        plugtype=TCP_LISTENER_SERVICE;
+                    else {
+                        child=XMLHelper::getFirstChildElement(e,Listener);
+                        if (child) {
+                            auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                            if (type.get())
+                                plugtype=type.get();
+                        }
+                    }
+                }
+                if (child) {
+                    log.info("building ListenerService of type %s...", plugtype.c_str());
+                    m_outer->m_listener = conf.ListenerServiceManager.newPlugin(plugtype.c_str(), child);
+                }
+                else {
+                    log.fatal("can't build ListenerService, missing conf:Listener element?");
+                    throw ConfigurationException("Can't build ListenerService, missing conf:Listener element?");
+                }
+            }
+
+#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));
+            }
+#endif
+
+            if (conf.isEnabled(SPConfig::Caching)) {
+                if (conf.isEnabled(SPConfig::OutOfProcess)) {
+#ifndef SHIBSP_LITE
+                    // First build any StorageServices.
+                    child=XMLHelper::getFirstChildElement(e,_StorageService);
+                    while (child) {
+                        auto_ptr_char id(child->getAttributeNS(NULL,_id));
+                        auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                        try {
+                            log.info("building StorageService (%s) of type %s...", id.get(), type.get());
+                            m_outer->m_storage[id.get()] = xmlConf.StorageServiceManager.newPlugin(type.get(),child);
+                        }
+                        catch (exception& ex) {
+                            log.crit("failed to instantiate StorageService (%s): %s", id.get(), ex.what());
+                        }
+                        child=XMLHelper::getNextSiblingElement(child,_StorageService);
+                    }
+
+                    // Replay cache.
+                    StorageService* replaySS=NULL;
+                    child=XMLHelper::getFirstChildElement(e,_ReplayCache);
+                    if (child) {
+                        auto_ptr_char ssid(child->getAttributeNS(NULL,_StorageService));
+                        if (ssid.get() && *ssid.get()) {
+                            if (m_outer->m_storage.count(ssid.get()))
+                                replaySS = m_outer->m_storage[ssid.get()];
+                            if (replaySS)
+                                log.info("building ReplayCache on top of StorageService (%s)...", ssid.get());
+                            else
+                                log.warn("unable to locate StorageService (%s) for ReplayCache, using dedicated in-memory instance", ssid.get());
+                        }
+                        xmlConf.setReplayCache(new ReplayCache(replaySS));
+                    }
+                    else {
+                        log.warn("no ReplayCache built, missing conf:ReplayCache element?");
+                    }
+
+                    // ArtifactMap
+                    child=XMLHelper::getFirstChildElement(e,_ArtifactMap);
+                    if (child) {
+                        auto_ptr_char ssid(child->getAttributeNS(NULL,_StorageService));
+                        if (ssid.get() && *ssid.get() && m_outer->m_storage.count(ssid.get())) {
+                            log.info("building ArtifactMap on top of StorageService (%s)...", ssid.get());
+                            samlConf.setArtifactMap(new ArtifactMap(child, m_outer->m_storage[ssid.get()]));
+                        }
+                    }
+                    if (samlConf.getArtifactMap()==NULL) {
+                        log.info("building in-memory ArtifactMap...");
+                        samlConf.setArtifactMap(new ArtifactMap(child));
+                    }
+#endif
+                }
+                child=XMLHelper::getFirstChildElement(e,_SessionCache);
+                if (child) {
+                    auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                    log.info("building SessionCache of type %s...",type.get());
+                    m_outer->m_sessionCache=conf.SessionCacheManager.newPlugin(type.get(), child);
+                }
+                else {
+                    log.fatal("can't build SessionCache, missing conf:SessionCache element?");
+                    throw ConfigurationException("Can't build SessionCache, missing conf:SessionCache element?");
+                }
+            }
+        } // end of first-time-only stuff
+
+        // Back to the fully dynamic stuff...next up is the RequestMapper.
+        if (conf.isEnabled(SPConfig::RequestMapping)) {
+            child=XMLHelper::getFirstChildElement(e,_RequestMapper);
+            if (child) {
+                auto_ptr_char type(child->getAttributeNS(NULL,_type));
+                log.info("building RequestMapper of type %s...",type.get());
+                m_requestMapper=conf.RequestMapperManager.newPlugin(type.get(),child);
+            }
+            else {
+                log.fatal("can't build RequestMapper, missing conf:RequestMapper element?");
+                throw ConfigurationException("Can't build RequestMapper, missing conf:RequestMapper element?");
+            }
+        }
+
+#ifndef SHIBSP_LITE
+        // Load security policies.
+        child = XMLHelper::getLastChildElement(e,SecurityPolicies);
+        if (child) {
+            PolicyNodeFilter filter;
+            child = XMLHelper::getFirstChildElement(child,Policy);
+            while (child) {
+                auto_ptr_char id(child->getAttributeNS(NULL,_id));
+                pair< PropertySet*,vector<const SecurityPolicyRule*> >& rules = m_policyMap[id.get()];
+                rules.first = NULL;
+                auto_ptr<DOMPropertySet> settings(new DOMPropertySet());
+                settings->load(child, NULL, &filter);
+                rules.first = settings.release();
+
+                // Process PolicyRule elements.
+                const DOMElement* rule = XMLHelper::getFirstChildElement(child,PolicyRule);
+                while (rule) {
+                    auto_ptr_char type(rule->getAttributeNS(NULL,_type));
+                    try {
+                        rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule));
+                    }
+                    catch (exception& ex) {
+                        log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());
+                    }
+                    rule = XMLHelper::getNextSiblingElement(rule,PolicyRule);
+                }
+
+                if (rules.second.size() == 0) {
+                    // Process Rule elements.
+                    log.warn("detected legacy Policy configuration, please convert to new PolicyRule syntax");
+                    rule = XMLHelper::getFirstChildElement(child,Rule);
+                    while (rule) {
+                        auto_ptr_char type(rule->getAttributeNS(NULL,_type));
+                        try {
+                            rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule));
+                        }
+                        catch (exception& ex) {
+                            log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());
+                        }
+                        rule = XMLHelper::getNextSiblingElement(rule,Rule);
+                    }
+
+                    // Manually add a basic Conditions rule.
+                    log.info("installing a default Conditions rule in policy (%s) for compatibility with legacy configuration", id.get());
+                    rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(CONDITIONS_POLICY_RULE, NULL));
+                }
+
+                child = XMLHelper::getNextSiblingElement(child,Policy);
+            }
+        }
+
+        // Process TransportOption elements.
+        child = XMLHelper::getLastChildElement(e,TransportOption);
+        while (child) {
+            if (child->hasChildNodes()) {
+                auto_ptr_char provider(child->getAttributeNS(NULL,_provider));
+                auto_ptr_char option(child->getAttributeNS(NULL,_option));
+                auto_ptr_char value(child->getFirstChild()->getNodeValue());
+                if (provider.get() && *provider.get() && option.get() && *option.get() && value.get() && *value.get()) {
+                    m_transportOptions.push_back(make_pair(string(provider.get()), make_pair(string(option.get()), string(value.get()))));
+                }
+            }
+            child = XMLHelper::getPreviousSiblingElement(child,TransportOption);
+        }
+#endif
+
+        // Load the default application. This actually has a fixed ID of "default". ;-)
+        child=XMLHelper::getLastChildElement(e,ApplicationDefaults);
+        if (!child) {
+            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,child);
+        m_appmap[defapp->getId()]=defapp;
+
+        // Load any overrides.
+        child = XMLHelper::getFirstChildElement(child,ApplicationOverride);
+        while (child) {
+            auto_ptr<XMLApplication> iapp(new XMLApplication(m_outer,child,defapp));
+            if (m_appmap.count(iapp->getId()))
+                log.crit("found conf:ApplicationOverride element with duplicate id attribute (%s), skipping it", iapp->getId());
+            else {
+                const char* iappid=iapp->getId();
+                m_appmap[iappid]=iapp.release();
+            }
+
+            child = XMLHelper::getNextSiblingElement(child,ApplicationOverride);
+        }
+    }
+    catch (exception&) {
+        cleanup();
+        throw;
+    }
+}
+
+XMLConfigImpl::~XMLConfigImpl()
+{
+    cleanup();
+}
+
+void XMLConfigImpl::cleanup()
+{
+    for_each(m_appmap.begin(),m_appmap.end(),cleanup_pair<string,Application>());
+    m_appmap.clear();
+#ifndef SHIBSP_LITE
+    for (map< string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::iterator i=m_policyMap.begin(); i!=m_policyMap.end(); ++i) {
+        delete i->second.first;
+        for_each(i->second.second.begin(), i->second.second.end(), xmltooling::cleanup<SecurityPolicyRule>());
+    }
+    m_policyMap.clear();
+#endif
+    delete m_requestMapper;
+    m_requestMapper = NULL;
+    if (m_document)
+        m_document->release();
+    m_document = NULL;
+}
+
+#ifndef SHIBSP_LITE
+void XMLConfig::receive(DDF& in, ostream& out)
+{
+    if (!strcmp(in.name(), "get::RelayState")) {
+        const char* id = in["id"].string();
+        const char* key = in["key"].string();
+        if (!id || !key)
+            throw ListenerException("Required parameters missing for RelayState recovery.");
+
+        string relayState;
+        StorageService* storage = getStorageService(id);
+        if (storage) {
+            if (storage->readString("RelayState",key,&relayState)>0) {
+                if (in["clear"].integer())
+                    storage->deleteString("RelayState",key);
+            }
+        }
+        else {
+            Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error(
+                "Storage-backed RelayState with invalid StorageService ID (%s)", id
+                );
+        }
+
+        // Repack for return to caller.
+        DDF ret=DDF(NULL).unsafe_string(relayState.c_str());
+        DDFJanitor jret(ret);
+        out << ret;
+    }
+    else if (!strcmp(in.name(), "set::RelayState")) {
+        const char* id = in["id"].string();
+        const char* value = in["value"].string();
+        if (!id || !value)
+            throw ListenerException("Required parameters missing for RelayState creation.");
+
+        string rsKey;
+        StorageService* storage = getStorageService(id);
+        if (storage) {
+            SAMLConfig::getConfig().generateRandomBytes(rsKey,20);
+            rsKey = SAMLArtifact::toHex(rsKey);
+            storage->createString("RelayState", rsKey.c_str(), value, time(NULL) + 600);
+        }
+        else {
+            Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error(
+                "Storage-backed RelayState with invalid StorageService ID (%s)", id
+                );
+        }
+
+        // Repack for return to caller.
+        DDF ret=DDF(NULL).string(rsKey.c_str());
+        DDFJanitor jret(ret);
+        out << ret;
+    }
+    else if (!strcmp(in.name(), "get::PostData")) {
+        const char* id = in["id"].string();
+        const char* key = in["key"].string();
+        if (!id || !key)
+            throw ListenerException("Required parameters missing for PostData recovery.");
+
+        string postData;
+        StorageService* storage = getStorageService(id);
+        if (storage) {
+            if (storage->readString("PostData",key,&postData) > 0) {
+                storage->deleteString("PostData",key);
+            }
+        }
+        else {
+            Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error(
+                "Storage-backed PostData with invalid StorageService ID (%s)", id
+                );
+        }
+        // If the data's empty, we'll send nothing back.
+        // If not, we don't need to round trip it, just send back the serialized DDF list.
+        if (postData.empty()) {
+            DDF ret(NULL);
+            DDFJanitor jret(ret);
+            out << ret;
+        }
+        else {
+            out << postData;
+        }
+    }
+    else if (!strcmp(in.name(), "set::PostData")) {
+        const char* id = in["id"].string();
+        if (!id || !in["parameters"].islist())
+            throw ListenerException("Required parameters missing for PostData creation.");
+
+        string rsKey;
+        StorageService* storage = getStorageService(id);
+        if (storage) {
+            SAMLConfig::getConfig().generateRandomBytes(rsKey,20);
+            rsKey = SAMLArtifact::toHex(rsKey);
+            ostringstream params;
+            params << in["parameters"];
+            storage->createString("PostData", rsKey.c_str(), params.str().c_str(), time(NULL) + 600);
+        }
+        else {
+            Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error(
+                "Storage-backed PostData with invalid StorageService ID (%s)", id
+                );
+        }
+
+        // Repack for return to caller.
+        DDF ret=DDF(NULL).string(rsKey.c_str());
+        DDFJanitor jret(ret);
+        out << ret;
+    }
+}
+#endif
+
+pair<bool,DOMElement*> XMLConfig::load()
+{
+    // Load from source using base class.
+    pair<bool,DOMElement*> raw = ReloadableXMLFile::load();
+
+    // If we own it, wrap it.
+    XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);
+
+    XMLConfigImpl* impl = new XMLConfigImpl(raw.second,(m_impl==NULL),this,m_log);
+
+    // If we held the document, transfer it to the impl. If we didn't, it's a no-op.
+    impl->setDocument(docjanitor.release());
+
+    delete m_impl;
+    m_impl = impl;
+
+    return make_pair(false,(DOMElement*)NULL);
+}
index 2f9ac99..473e06a 100644 (file)
@@ -24,7 +24,7 @@
 #define __shibsp_paths_h__
 
 /** Default schema catalogs. */
-#define SHIBSP_SCHEMAS "/opt/shibboleth-sp/share/xml/xmltooling/catalog.xml:/opt/shibboleth-sp/share/xml/opensaml/saml20-catalog.xml:/opt/shibboleth-sp/share/xml/opensaml/saml11-catalog.xml:/opt/shibboleth-sp/share/xml/shibboleth/catalog.xml"
+#define SHIBSP_SCHEMAS "/opt/shibboleth-sp/share/xml/xmltooling/catalog.xml:/usr/share/xml/opensaml/saml20-catalog.xml:/usr/share/xml/opensaml/saml11-catalog.xml:/opt/shibboleth-sp/share/xml/shibboleth/catalog.xml"
 
 /** Default name of SP configuration file. */
 #define SHIBSP_CONFIG "shibboleth2.xml"
index d69080c..c503f8b 100644 (file)
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //\r
 \r
 VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION 1,3,0,0\r
- PRODUCTVERSION 2,3,0,0\r
+ FILEVERSION 1,3,1,0\r
+ PRODUCTVERSION 2,3,1,0\r
  FILEFLAGSMASK 0x3fL\r
 #ifdef _DEBUG\r
  FILEFLAGS 0x1L\r
@@ -81,8 +81,8 @@ BEGIN
 #endif\r
 #endif\r
             VALUE "PrivateBuild", "\0"\r
-            VALUE "ProductName", "Shibboleth 2.3\0"\r
-            VALUE "ProductVersion", "2, 3, 0, 0\0"\r
+            VALUE "ProductName", "Shibboleth 2.3.1\0"\r
+            VALUE "ProductVersion", "2, 3, 1, 0\0"\r
             VALUE "SpecialBuild", "\0"\r
         END\r
     END\r
index e8707e4..80230ba 100644 (file)
@@ -39,7 +39,7 @@
 
 #define SHIBSP_VERSION_MAJOR 1
 #define SHIBSP_VERSION_MINOR 3
-#define SHIBSP_VERSION_REVISION 0
+#define SHIBSP_VERSION_REVISION 1
 
 /** DO NOT MODIFY BELOW THIS LINE */