https://issues.shibboleth.net/jira/browse/SSPCPP-255 origin/maint-1.3 1.3.5
authorScott Cantor <cantor.2@osu.edu>
Wed, 4 Nov 2009 15:15:35 +0000 (15:15 +0000)
committerScott Cantor <cantor.2@osu.edu>
Wed, 4 Nov 2009 15:15:35 +0000 (15:15 +0000)
apache/mod_apache.cpp
doc/NEWS.txt
doc/README.txt
fastcgi/shibauthorizer.cpp
fastcgi/shibresponder.cpp
isapi_shib/isapi_shib.cpp
nsapi_shib/nsapi_shib.cpp
schemas/shibboleth-targetconfig-1.0.xsd

index 65066d9..e6ca506 100644 (file)
@@ -69,6 +69,7 @@ namespace {
     char* g_szSchemaDir = NULL;
     ShibTargetConfig* g_Config = NULL;
     string g_unsetHeaderValue,g_spoofKey;
+    set<string> g_allowedSchemes;
     bool g_checkSpoofing = true;
     bool g_catchAll = true;
     static const char* g_UserDataKey = "_shib_check_user_";
@@ -459,9 +460,12 @@ public:
     const string& content_type="text/html",
        const Iterator<header_t>& headers=EMPTY(header_t)
     ) {
+    checkString(content_type, "Detected control character in a response header.");
     m_req->content_type = ap_psprintf(m_req->pool, content_type.c_str());
     while (headers.hasNext()) {
         const header_t& h=headers.next();
+        checkString(h.first, "Detected control character in a response header.");
+        checkString(h.second, "Detected control character in a response header.");
         ap_table_set(m_req->headers_out, h.first.c_str(), h.second.c_str());
     }
     ap_send_http_header(m_req);
@@ -469,6 +473,9 @@ public:
     return (void*)((code==200) ? DONE : code);
   }
   virtual void* sendRedirect(const string& url) {
+    checkString(url, "Detected control character in an attempted redirect.");
+    if (g_allowedSchemes.find(url.substr(0, url.find(':'))) == g_allowedSchemes.end())
+        throw FatalProfileException("Invalid scheme in attempted redirect.");
     ap_table_set(m_req->headers_out, "Location", url.c_str());
     return (void*)REDIRECT;
   }
@@ -481,6 +488,15 @@ public:
   shib_server_config* m_sc;
   shib_request_config* m_rc;
   set<string> m_allhttp;
+
+private:
+  void checkString(const string& s, const char* msg) {
+    string::const_iterator e = s.end();
+    for (string::const_iterator i=s.begin(); i!=e; ++i) {
+        if (iscntrl(*i))
+            throw FatalProfileException(msg);
+    }
+  }
 };
 
 /********************************************************************************/
@@ -1137,14 +1153,30 @@ extern "C" void shib_child_init(apr_pool_t* p, server_rec* s)
         saml::Locker locker(conf);
         const IPropertySet* props=conf->getPropertySet("Local");
         if (props) {
-            pair<bool,const char*> unsetValue=props->getString("unsetHeaderValue");
-            if (unsetValue.first)
-                g_unsetHeaderValue = unsetValue.second;
+            pair<bool,const char*> str=props->getString("unsetHeaderValue");
+            if (str.first)
+                g_unsetHeaderValue = str.second;
+            str=props->getString("allowedSchemes");
+            if (str.first) {
+                string schemes=str.second;
+                unsigned int j=0;
+                for (unsigned int i=0;  i < schemes.length();  i++) {
+                    if (schemes.at(i)==' ') {
+                        g_allowedSchemes.insert(schemes.substr(j, i-j));
+                        j = i+1;
+                    }
+                }
+                g_allowedSchemes.insert(schemes.substr(j, schemes.length()-j));
+            }
             pair<bool,bool> flag=props->getBool("checkSpoofing");
             g_checkSpoofing = !flag.first || flag.second;
             flag=props->getBool("catchAll");
             g_catchAll = !flag.first || flag.second;
         }
+        if (g_allowedSchemes.empty()) {
+            g_allowedSchemes.insert("https");
+            g_allowedSchemes.insert("http");
+        }
     }
     catch (exception&) {
         ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() failed to initialize system");
index 93db4d5..07e2033 100644 (file)
@@ -1,3 +1,8 @@
+Nov 4, 2009
+Version 1.3.5
+
+Fix for secadv 20091104
+
 Aug 26, 2009
 Version 1.3.4
 
index 91e4793..6b13763 100644 (file)
@@ -1,5 +1,5 @@
-Aug 26, 2009
-Version 1.3.4
+Nov 4, 2009
+Version 1.3.5
 
 Welcome to Internet2's Shibboleth
 
index db811b4..745855d 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- *  Copyright 2001-2007 Internet2\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
@@ -32,6 +32,7 @@
 #include <fcgio.h>\r
 \r
 using namespace shibtarget;\r
+using namespace saml;\r
 using namespace std;\r
 \r
 typedef enum {\r
@@ -40,10 +41,21 @@ typedef enum {
     SHIB_RETURN_DONE\r
 } shib_return_t;\r
 \r
+set<string> g_allowedSchemes;\r
+\r
 class ShibTargetFCGIAuth : public ShibTarget\r
 {\r
     FCGX_Request* m_req;\r
     string m_cookie;\r
+\r
+    void checkString(const string& s, const char* msg) {\r
+        string::const_iterator e = s.end();\r
+        for (string::const_iterator i=s.begin(); i!=e; ++i) {\r
+            if (iscntrl(*i))\r
+                throw runtime_error(msg);\r
+        }\r
+    }\r
+\r
 public:\r
     map<string,string> m_headers;\r
 \r
@@ -143,9 +155,12 @@ public:
         const string& content_type="text/html",\r
         const saml::Iterator<header_t>& headers=EMPTY(header_t)) {\r
 \r
+        checkString(content_type, "Detected control character in a response header.");\r
         string hdr = m_cookie + "Connection: close\r\nContent-type: " + content_type + "\r\n";\r
         while (headers.hasNext()) {\r
             const header_t& h=headers.next();\r
+            checkString(h.first, "Detected control character in a response header.");\r
+            checkString(h.second, "Detected control character in a response header.");\r
             hdr += h.first + ": " + h.second + "\r\n";\r
         }\r
 \r
@@ -162,6 +177,9 @@ public:
     }\r
 \r
     virtual void* sendRedirect(const string& url) {\r
+        checkString(url, "Detected control character in an attempted redirect.");\r
+        if (g_allowedSchemes.find(url.substr(0, url.find(':'))) == g_allowedSchemes.end())\r
+            throw runtime_error("Invalid scheme in attempted redirect.");\r
         cout << "Status: 302 Please Wait" << "\r\n"\r
              << "Location: " << url << "\r\n"\r
              <<  m_cookie << "\r\n"\r
@@ -227,12 +245,36 @@ int main(void)
             cerr << "failed to load Shibboleth configuration" << endl;\r
             exit(1);\r
         }\r
+\r
+        IConfig* conf=g_Config->getINI();\r
+        Locker locker(conf);\r
+        const IPropertySet* props=conf->getPropertySet("Local");\r
+        if (props) {\r
+            pair<bool,const char*> str=props->getString("allowedSchemes");\r
+            if (str.first) {\r
+                string schemes=str.second;\r
+                unsigned int j=0;\r
+                for (unsigned int i=0;  i < schemes.length();  i++) {\r
+                    if (schemes.at(i)==' ') {\r
+                        g_allowedSchemes.insert(schemes.substr(j, i-j));\r
+                        j = i+1;\r
+                    }\r
+                }\r
+                g_allowedSchemes.insert(schemes.substr(j, schemes.length()-j));\r
+            }\r
+        }\r
+        if (g_allowedSchemes.empty()) {\r
+            g_allowedSchemes.insert("https");\r
+            g_allowedSchemes.insert("http");\r
+        }\r
     }\r
     catch (exception& e) {\r
         cerr << "exception while initializing Shibboleth configuration: " << e.what() << endl;\r
         exit(1);\r
     }\r
 \r
+\r
+\r
     // Load "authoritative" URL fields.\r
     char* var = getenv("SHIBSP_SERVER_NAME");\r
     if (var)\r
index 86c374c..f1b7dcf 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- *  Copyright 2001-2007 Internet2\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
@@ -32,6 +32,7 @@
 #include <fcgio.h>\r
 \r
 using namespace shibtarget;\r
+using namespace saml;\r
 using namespace std;\r
 \r
 typedef enum {\r
@@ -40,6 +41,8 @@ typedef enum {
     SHIB_RETURN_DONE\r
 } shib_return_t;\r
 \r
+set<string> g_allowedSchemes;\r
+\r
 class ShibTargetFCGI : public ShibTarget\r
 {\r
     FCGX_Request* m_req;\r
@@ -47,6 +50,14 @@ class ShibTargetFCGI : public ShibTarget
     string m_cookie;\r
     map<string, string> m_headers;\r
 \r
+    void checkString(const string& s, const char* msg) {\r
+        string::const_iterator e = s.end();\r
+        for (string::const_iterator i=s.begin(); i!=e; ++i) {\r
+            if (iscntrl(*i))\r
+                throw runtime_error(msg);\r
+        }\r
+    }\r
+\r
 public:\r
     ShibTargetFCGI(FCGX_Request* req, char* post_data, const char* scheme=NULL, const char* hostname=NULL, int port=0)\r
         : m_req(req), m_body(post_data) {\r
@@ -146,9 +157,12 @@ public:
         const string& content_type="text/html",\r
         const saml::Iterator<header_t>& headers=EMPTY(header_t)) {\r
 \r
+        checkString(content_type, "Detected control character in a response header.");\r
         string hdr = string ("Connection: close\r\nContent-type: ") + content_type + "\r\n" + m_cookie;\r
         while (headers.hasNext()) {\r
             const header_t& h=headers.next();\r
+            checkString(h.first, "Detected control character in a response header.");\r
+            checkString(h.second, "Detected control character in a response header.");\r
             hdr += h.first + ": " + h.second + "\r\n";\r
         }\r
 \r
@@ -164,6 +178,9 @@ public:
     }\r
 \r
     virtual void* sendRedirect(const string& url) {\r
+        checkString(url, "Detected control character in an attempted redirect.");\r
+        if (g_allowedSchemes.find(url.substr(0, url.find(':'))) == g_allowedSchemes.end())\r
+            throw runtime_error("Invalid scheme in attempted redirect.");\r
         cout << "Status: 302 Please Wait" << "\r\n" << "Location: " << url << "\r\n" << m_cookie << "\r\n"\r
             << "<HTML><BODY>Redirecting...</BODY></HTML>";\r
         return (void*)SHIB_RETURN_DONE;\r
@@ -260,6 +277,29 @@ int main(void)
             cerr << "failed to load Shibboleth configuration" << endl;\r
             exit(1);\r
         }\r
+\r
+        IConfig* conf=g_Config->getINI();\r
+        Locker locker(conf);\r
+        const IPropertySet* props=conf->getPropertySet("Local");\r
+        if (props) {\r
+            pair<bool,const char*> str=props->getString("allowedSchemes");\r
+            if (str.first) {\r
+                string schemes=str.second;\r
+                unsigned int j=0;\r
+                for (unsigned int i=0;  i < schemes.length();  i++) {\r
+                    if (schemes.at(i)==' ') {\r
+                        g_allowedSchemes.insert(schemes.substr(j, i-j));\r
+                        j = i+1;\r
+                    }\r
+                }\r
+                g_allowedSchemes.insert(schemes.substr(j, schemes.length()-j));\r
+            }\r
+        }\r
+        if (g_allowedSchemes.empty()) {\r
+            g_allowedSchemes.insert("https");\r
+            g_allowedSchemes.insert("http");\r
+        }\r
+\r
     }\r
     catch (exception& e) {\r
         cerr << "exception while initializing Shibboleth configuration:" << e.what() << endl;\r
index 810db5f..f30cab6 100644 (file)
@@ -91,6 +91,7 @@ namespace {
     map<string,site_t> g_Sites;
     bool g_bNormalizeRequest = true;
     string g_unsetHeaderValue,g_spoofKey;
+    set<string> g_allowedSchemes;
     bool g_checkSpoofing = true;
     bool g_catchAll = true;
     bool g_bSafeHeaderNames = false;
@@ -188,13 +189,27 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
             flag=props->getBool("catchAll");
             g_catchAll = !flag.first || flag.second;
 
-            pair<bool,const char*> unsetValue=props->getString("unsetHeaderValue");
-            if (unsetValue.first)
-                g_unsetHeaderValue = unsetValue.second;
+            pair<bool,const char*> str=props->getString("unsetHeaderValue");
+            if (str.first)
+                g_unsetHeaderValue = str.second;
+
+            str=props->getString("allowedSchemes");
+            if (str.first) {
+                string schemes=str.second;
+                unsigned int j=0;
+                for (unsigned int i=0;  i < schemes.length();  i++) {
+                    if (schemes.at(i)==' ') {
+                        g_allowedSchemes.insert(schemes.substr(j, i-j));
+                        j = i+1;
+                    }
+                }
+                g_allowedSchemes.insert(schemes.substr(j, schemes.length()-j));
+            }
+
             if (g_checkSpoofing) {
-                unsetValue = props->getString("spoofKey");
-                if (unsetValue.first)
-                    g_spoofKey = unsetValue.second;
+                str = props->getString("spoofKey");
+                if (str.first)
+                    g_spoofKey = str.second;
                 else {
                     LogEvent(NULL, EVENTLOG_WARNING_TYPE, 2100, NULL,
                             "Filter generating a pseudorandom anti-spoofing key, consider setting spoofKey yourself.");
@@ -222,6 +237,10 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
                 }
             }
         }
+        if (g_allowedSchemes.empty()) {
+            g_allowedSchemes.insert("https");
+            g_allowedSchemes.insert("http");
+        }
     }
     catch (exception&) {
         LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "Filter startup failed with an exception.");
@@ -370,6 +389,14 @@ class ShibTargetIsapiF : public ShibTarget
   dynabuf m_allhttp;
   bool m_firsttime;
 
+  void checkString(const string& s, const char* msg) {
+    string::const_iterator e = s.end();
+    for (string::const_iterator i=s.begin(); i!=e; ++i) {
+        if (iscntrl(*i))
+            throw FatalProfileException(msg);
+    }
+  }
+
 public:
     ShibTargetIsapiF(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, const site_t& site)
         : m_pfc(pfc), m_pn(pn), m_allhttp(4096), m_firsttime(true) {
@@ -500,9 +527,12 @@ public:
     int code=200,
     const string& content_type="text/html",
     const Iterator<header_t>& headers=EMPTY(header_t)) {
+    checkString(content_type, "Detected control character in a response header.");
     string hdr = string ("Connection: close\r\nContent-type: ") + content_type + "\r\n";
     while (headers.hasNext()) {
         const header_t& h=headers.next();
+        checkString(h.first, "Detected control character in a response header.");
+        checkString(h.second, "Detected control character in a response header.");
         hdr += h.first + ": " + h.second + "\r\n";
     }
     hdr += "\r\n";
@@ -518,6 +548,9 @@ public:
     return (void*)SF_STATUS_REQ_FINISHED;
   }
   virtual void* sendRedirect(const string& url) {
+    checkString(url, "Detected control character in an attempted redirect.");
+    if (g_allowedSchemes.find(url.substr(0, url.find(':'))) == g_allowedSchemes.end())
+        throw FatalProfileException("Invalid scheme in attempted redirect.");
     // XXX: Don't support the httpRedirect option, yet.
     string hdrs=m_cookie + string("Location: ") + url + "\r\n"
       "Content-Type: text/html\r\n"
@@ -650,6 +683,14 @@ class ShibTargetIsapiE : public ShibTarget
   LPEXTENSION_CONTROL_BLOCK m_lpECB;
   string m_cookie;
 
+  void checkString(const string& s, const char* msg) {
+    string::const_iterator e = s.end();
+    for (string::const_iterator i=s.begin(); i!=e; ++i) {
+        if (iscntrl(*i))
+            throw FatalProfileException(msg);
+    }
+  }
+
 public:
   ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site) {
     dynabuf ssl(5);
@@ -774,8 +815,11 @@ public:
     int code=200,
     const string& content_type="text/html",
     const Iterator<header_t>& headers=EMPTY(header_t)) {
+    checkString(content_type, "Detected control character in a response header.");
     string hdr = m_cookie + "Connection: close\r\nContent-type: " + content_type + "\r\n";
     for (int k = 0; k < headers.size(); k++) {
+      checkString(headers[k].first, "Detected control character in a response header.");
+      checkString(headers[k].second, "Detected control character in a response header.");
       hdr += headers[k].first + ": " + headers[k].second + "\r\n";
     }
     hdr += "\r\n";
@@ -792,6 +836,9 @@ public:
   }
   virtual void* sendRedirect(const string& url) {
     // XXX: Don't support the httpRedirect option, yet.
+    checkString(url, "Detected control character in an attempted redirect.");
+    if (g_allowedSchemes.find(url.substr(0, url.find(':'))) == g_allowedSchemes.end())
+        throw FatalProfileException("Invalid scheme in attempted redirect.");
     string hdrs = m_cookie + "Location: " + url + "\r\n"
       "Content-Type: text/html\r\n"
       "Content-Length: 40\r\n"
index 1925021..ef97932 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2001-2005 Internet2
+ *  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.
@@ -66,6 +66,7 @@ namespace {
     ShibTargetConfig* g_Config=NULL;
     string g_ServerName;
     string g_unsetHeaderValue;
+    set<string> g_allowedSchemes;
     bool g_checkSpoofing = false;
     bool g_catchAll = true;
 }
@@ -146,14 +147,32 @@ extern "C" NSAPI_PUBLIC int nsapi_shib_init(pblock* pb, Session* sn, Request* rq
         Locker locker(conf);
         const IPropertySet* props=conf->getPropertySet("Local");
         if (props) {
-            pair<bool,const char*> unsetValue=props->getString("unsetHeaderValue");
-            if (unsetValue.first)
-                g_unsetHeaderValue = unsetValue.second;
+            pair<bool,const char*> str=props->getString("unsetHeaderValue");
+            if (str.first)
+                g_unsetHeaderValue = str.second;
+
+            str=props->getString("allowedSchemes");
+            if (str.first) {
+                string schemes=str.second;
+                unsigned int j=0;
+                for (unsigned int i=0;  i < schemes.length();  i++) {
+                    if (schemes.at(i)==' ') {
+                        g_allowedSchemes.insert(schemes.substr(j, i-j));
+                        j = i+1;
+                    }
+                }
+                g_allowedSchemes.insert(schemes.substr(j, schemes.length()-j));
+            }
+
             pair<bool,bool> flag=props->getBool("checkSpoofing");
             g_checkSpoofing = !flag.first || flag.second;
             flag=props->getBool("catchAll");
             g_catchAll = !flag.first || flag.second;
         }
+        if (g_allowedSchemes.empty()) {
+            g_allowedSchemes.insert("https");
+            g_allowedSchemes.insert("http");
+        }
     }
     catch (exception&) {
         g_Config=NULL;
@@ -168,6 +187,14 @@ extern "C" NSAPI_PUBLIC int nsapi_shib_init(pblock* pb, Session* sn, Request* rq
 
 class ShibTargetNSAPI : public ShibTarget
 {
+  void checkString(const string& s, const char* msg) {
+    string::const_iterator e = s.end();
+    for (string::const_iterator i=s.begin(); i!=e; ++i) {
+        if (iscntrl(*i))
+            throw FatalProfileException(msg);
+    }
+  }
+
 public:
   ShibTargetNSAPI(pblock* pb, Session* sn, Request* rq) : m_pb(pb), m_sn(sn), m_rq(rq), m_firsttime(true) {
 
@@ -350,12 +377,15 @@ public:
     const string& content_type="text/html",
     const saml::Iterator<header_t>& headers=EMPTY(header_t)
     ) {
+    checkString(content_type, "Detected control character in a response header.");
     param_free(pblock_remove("content-type", m_rq->srvhdrs));
     pblock_nvinsert("content-type", content_type.c_str(), m_rq->srvhdrs);
     pblock_nninsert("content-length", msg.length(), m_rq->srvhdrs);
     pblock_nvinsert("connection","close",m_rq->srvhdrs);
     while (headers.hasNext()) {
         const header_t& h=headers.next();
+        checkString(h.first, "Detected control character in a response header.");
+        checkString(h.second, "Detected control character in a response header.");
         pblock_nvinsert(h.first.c_str(), h.second.c_str(), m_rq->srvhdrs);
     }
     protocol_status(m_sn, m_rq, code, NULL);
@@ -364,6 +394,9 @@ public:
     return (void*)REQ_EXIT;
   }
   virtual void* sendRedirect(const string& url) {
+    checkString(url, "Detected control character in an attempted redirect.");
+    if (g_allowedSchemes.find(url.substr(0, url.find(':'))) == g_allowedSchemes.end())
+        throw FatalProfileException("Invalid scheme in attempted redirect.");
     param_free(pblock_remove("content-type", m_rq->srvhdrs));
     pblock_nninsert("content-length", 0, m_rq->srvhdrs);
     pblock_nvinsert("expires", "01-Jan-1997 12:00:00 GMT", m_rq->srvhdrs);
index 8bf3002..e1b6e44 100644 (file)
@@ -7,7 +7,7 @@
        elementFormDefault="qualified"
        attributeFormDefault="unqualified"
        blockDefault="substitution"
-       version="1.3.2">
+       version="1.3.5">
 
        <import namespace="urn:oasis:names:tc:SAML:1.0:assertion" schemaLocation="cs-sstc-schema-assertion-1.1.xsd"/>
        <import namespace="urn:oasis:names:tc:SAML:2.0:metadata" schemaLocation="saml-schema-metadata-2.0.xsd"/>
@@ -38,7 +38,7 @@
                        <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                </sequence>
                <attribute name="type" type="conf:string" use="required"/>
-               <attribute name="uri" type="anyURI" use="optional"/>
+               <attribute name="uri" type="anyURI"/>
                <anyAttribute namespace="##any" processContents="lax"/>
        </complexType>
 
@@ -62,8 +62,8 @@
                        <element name="CredentialsProvider" type="conf:PluggableType" minOccurs="0" maxOccurs="unbounded"/>
                        <element ref="conf:AttributeFactory" minOccurs="0" maxOccurs="unbounded"/>
                </sequence>
-               <attribute name="logger" type="anyURI" use="optional"/>
-               <attribute name="clockSkew" type="unsignedInt" use="optional"/>
+               <attribute name="logger" type="anyURI"/>
+               <attribute name="clockSkew" type="unsignedInt"/>
                <anyAttribute namespace="##other" processContents="lax"/>
        </complexType>
 
@@ -79,7 +79,7 @@
                                                        <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                                                </sequence>
                                                <attribute name="path" type="anyURI" use="required"/>
-                                               <attribute name="fatal" type="boolean" use="optional"/>
+                                               <attribute name="fatal" type="boolean"/>
                                                <anyAttribute namespace="##other" processContents="lax"/>
                                        </complexType>
                                </element>
                                                        <element name="Argument" type="conf:string" minOccurs="0" maxOccurs="unbounded"/>
                                                </sequence>
                                                <attributeGroup ref="conf:SessionCacheProperties"/>
-                                               <attribute name="mysqlTimeout" type="unsignedInt" use="optional" default="14400"/>
-                                               <attribute name="storeAttributes" type="boolean" use="optional" default="false"/>
+                                               <attribute name="mysqlTimeout" type="unsignedInt" default="14400"/>
+                                               <attribute name="storeAttributes" type="boolean" default="false"/>
                                                <anyAttribute namespace="##other" processContents="lax"/>
                                        </complexType>
                                </element>
                        </choice>
                        <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                </sequence>
-               <attribute name="logger" type="anyURI" use="optional"/>
+               <attribute name="logger" type="anyURI"/>
                <anyAttribute namespace="##other" processContents="lax"/>
        </complexType>
 
        <attributeGroup name="SessionCacheProperties">
-       <attribute name="cleanupInterval" type="unsignedInt" use="optional" default="300"/>
-       <attribute name="cacheTimeout" type="unsignedInt" use="optional" default="28800"/>
-               <attribute name="AAConnectTimeout" type="unsignedInt" use="optional" default="15"/>
-               <attribute name="AATimeout" type="unsignedInt" use="optional" default="30"/>
-               <attribute name="defaultLifetime" type="unsignedInt" use="optional" default="1800"/>
-               <attribute name="retryInterval" type="unsignedInt" use="optional" default="300"/>
-               <attribute name="strictValidity" type="boolean" use="optional" default="true"/>
-               <attribute name="propagateErrors" type="boolean" use="optional" default="false"/>
+       <attribute name="cleanupInterval" type="unsignedInt" default="300"/>
+       <attribute name="cacheTimeout" type="unsignedInt" default="28800"/>
+               <attribute name="AAConnectTimeout" type="unsignedInt" default="15"/>
+               <attribute name="AATimeout" type="unsignedInt" default="30"/>
+               <attribute name="defaultLifetime" type="unsignedInt" default="1800"/>
+               <attribute name="retryInterval" type="unsignedInt" default="300"/>
+               <attribute name="strictValidity" type="boolean" default="true"/>
+               <attribute name="propagateErrors" type="boolean" default="false"/>
        </attributeGroup>
 
        <complexType name="LocalConfigurationType">
                        </element>
                        <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                </sequence>
-               <attribute name="logger" type="anyURI" use="optional"/>
-               <attribute name="localRelayState" type="boolean" use="optional" default="false"/>
-               <attribute name="unsetHeaderValue" type="conf:string" use="optional"/>
-               <attribute name="checkSpoofing" type="boolean" use="optional"/>
-        <attribute name="spoofKey" type="conf:string" use="optional"/>
-               <attribute name="catchAll" type="boolean" use="optional"/>
+               <attribute name="logger" type="anyURI"/>
+               <attribute name="localRelayState" type="boolean" default="false"/>
+               <attribute name="unsetHeaderValue" type="conf:string"/>
+               <attribute name="checkSpoofing" type="boolean"/>
+        <attribute name="spoofKey" type="conf:string"/>
+               <attribute name="catchAll" type="boolean"/>
+        <attribute name="allowedSchemes" type="conf:listOfStrings"/>
                <anyAttribute namespace="##other" processContents="lax"/>
        </complexType>
        
                                                </sequence>
                                                <attribute name="id" type="unsignedInt" use="required"/>
                                                <attribute name="name" type="conf:string" use="required"/>
-                                               <attribute name="port" type="unsignedInt" use="optional"/>
-                                               <attribute name="sslport" type="unsignedInt" use="optional"/>
-                                               <attribute name="scheme" type="conf:string" use="optional"/>
+                                               <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" use="optional"/>
-            <attribute name="safeHeaderNames" type="boolean" use="optional"/>
+                       <attribute name="normalizeRequest" type="boolean"/>
+            <attribute name="safeHeaderNames" type="boolean"/>
                        <anyAttribute namespace="##other" processContents="lax"/>
                </complexType>
        </element>
        </element>
        
        <attributeGroup name="ContentSettings">
-               <attribute name="authType" type="conf:string" use="optional"/>
-               <attribute name="requireSession" type="boolean" use="optional"/>
-               <attribute name="requireSessionWith" type="conf:string" use="optional"/>
-               <attribute name="exportAssertion" type="boolean" use="optional"/>
-               <attribute name="redirectToSSL" type="unsignedInt" use="optional"/>
+               <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"/>
                <anyAttribute namespace="##other" processContents="lax"/>
        </attributeGroup>
        <element name="AccessControlProvider" type="conf:PluggableType"/>
                                <element ref="conf:PathRegex"/>
                        </choice>
                </sequence>
-               <attribute name="scheme" use="optional">
+               <attribute name="scheme">
                            <simpleType>
                                <restriction base="string">
                                    <enumeration value="http"/>
                            </simpleType>
                </attribute>
                <attribute name="name" type="conf:string" use="required"/>
-               <attribute name="port" type="unsignedInt" use="optional"/>
-               <attribute name="applicationId" type="conf:string" use="optional"/>
+               <attribute name="port" type="unsignedInt"/>
+               <attribute name="applicationId" type="conf:string"/>
                <attributeGroup ref="conf:ContentSettings"/>
        </complexType>
     </element>
                        </choice>
                </sequence>
                <attribute name="name" type="conf:string" use="required"/>
-               <attribute name="applicationId" type="conf:string" use="optional"/>
+               <attribute name="applicationId" type="conf:string"/>
                <attributeGroup ref="conf:ContentSettings"/>
         </complexType>
     </element>
                        </sequence>
                        <attribute name="id" type="conf:string" fixed="default"/>
                        <attribute name="providerId" type="anyURI" use="required"/>
-                       <attribute name="homeURL" type="anyURI" use="optional"/>
+                       <attribute name="homeURL" type="anyURI"/>
                <anyAttribute namespace="##other" processContents="lax"/>
                </complexType>
        </element>
                                </choice>
                        </sequence>
                        <attribute name="id" type="conf:string" use="required"/>
-                       <attribute name="providerId" type="anyURI" use="optional"/>
-                       <attribute name="homeURL" type="anyURI" use="optional"/>
+                       <attribute name="providerId" type="anyURI"/>
+                       <attribute name="homeURL" type="anyURI"/>
                <anyAttribute namespace="##other" processContents="lax"/>
                </complexType>
        </element>
                                <element ref="md:SingleLogoutService"/>
                                <element name="ExtensionService" type="conf:PluggableType"/>
                        </choice>
-                       <!-- deprecated --> <attribute name="wayfURL" type="anyURI" use="optional"/>
-                       <!-- deprecated --> <attribute name="shireURL" type="anyURI" use="optional"/>
-                       <!-- deprecated --> <attribute name="shireSSL" type="boolean" use="optional"/>
-                       <attribute name="handlerURL" type="anyURI" use="optional"/>
-                       <attribute name="handlerSSL" type="boolean" use="optional" default="true"/>
-                       <attribute name="cookieName" type="conf:string" use="optional"/>
-                       <attribute name="cookieProps" type="conf:string" use="optional"/>
-                       <attribute name="idpHistory" type="boolean" use="optional" default="true"/>
-                       <attribute name="idpHistoryDays" type="unsignedInt" use="optional"/>
-                       <attribute name="lifetime" type="unsignedInt" use="optional"/>
-                       <attribute name="timeout" type="unsignedInt" use="optional"/>
-                       <attribute name="checkAddress" type="boolean" use="optional"/>
-                       <attribute name="consistentAddress" type="boolean" use="optional" default="true"/>
-                       <attribute name="checkReplay" type="boolean" use="optional" default="true"/>
+                       <!-- deprecated --> <attribute name="wayfURL" type="anyURI"/>
+                       <!-- deprecated --> <attribute name="shireURL" type="anyURI"/>
+                       <!-- deprecated --> <attribute name="shireSSL" type="boolean"/>
+                       <attribute name="handlerURL" type="anyURI"/>
+                       <attribute name="handlerSSL" type="boolean" default="true"/>
+                       <attribute name="cookieName" type="conf:string"/>
+                       <attribute name="cookieProps" type="conf:string"/>
+                       <attribute name="idpHistory" type="boolean" default="true"/>
+                       <attribute name="idpHistoryDays" type="unsignedInt"/>
+                       <attribute name="lifetime" type="unsignedInt"/>
+                       <attribute name="timeout" type="unsignedInt"/>
+                       <attribute name="checkAddress" type="boolean"/>
+                       <attribute name="consistentAddress" type="boolean" default="true"/>
+                       <attribute name="checkReplay" type="boolean" default="true"/>
                        <anyAttribute namespace="##other" processContents="lax"/>
                </complexType>
        </element>
                        </sequence>
                        <attribute name="Location" type="anyURI" use="required"/>
                        <attribute name="Binding" type="anyURI" use="required"/>
-                       <attribute name="wayfURL" type="anyURI" use="optional"/>
-                       <attribute name="wayfBinding" type="anyURI" use="optional"/>
-                       <attribute name="checkCDC" type="anyURI" use="optional"/>
-                       <attribute name="isDefault" type="boolean" use="optional"/>
-                       <attribute name="id" type="conf:string" use="optional"/>
+                       <attribute name="wayfURL" type="anyURI"/>
+                       <attribute name="wayfBinding" type="anyURI"/>
+                       <attribute name="checkCDC" type="anyURI"/>
+                       <attribute name="isDefault" type="boolean"/>
+                       <attribute name="id" type="conf:string"/>
                        <anyAttribute namespace="##any" processContents="lax"/>
                </complexType>
        </element>
                        <sequence>
                                <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                        </sequence>
-                       <!-- deprecated --> <attribute name="shire" type="anyURI" use="optional"/>
-                       <attribute name="session" type="anyURI" use="optional"/>
-                       <attribute name="metadata" type="anyURI" use="optional"/>
+                       <!-- deprecated --> <attribute name="shire" type="anyURI"/>
+                       <attribute name="session" type="anyURI"/>
+                       <attribute name="metadata" type="anyURI"/>
                        <attribute name="rm" type="anyURI" use="required"/>
-                       <attribute name="access" type="anyURI" use="optional"/>
-                       <attribute name="ssl" type="anyURI" use="optional"/>
-                       <attribute name="supportContact" type="conf:string" use="optional"/>
-                       <attribute name="logoLocation" type="anyURI" use="optional"/>
-                       <attribute name="styleSheet" type="anyURI" use="optional"/>
+                       <attribute name="access" type="anyURI"/>
+                       <attribute name="ssl" type="anyURI"/>
+                       <attribute name="supportContact" type="conf:string"/>
+                       <attribute name="logoLocation" type="anyURI"/>
+                       <attribute name="styleSheet" type="anyURI"/>
                        <anyAttribute namespace="##any" processContents="lax"/>
                </complexType>
        </element>
 
        <attributeGroup name="CredentialUseGroup">
-               <attribute name="TLS" type="conf:string" use="optional"/>
-               <attribute name="Signing" type="conf:string" use="optional"/>
-               <attribute name="signRequest" type="boolean" use="optional" default="false"/>
-               <attribute name="signatureAlg" type="anyURI" use="optional"/>
-               <attribute name="digestAlg" type="anyURI" use="optional"/>
-               <attribute name="signedResponse" type="boolean" use="optional" default="false"/>
-               <attribute name="signedAssertions" type="boolean" use="optional" default="false"/>
-               <attribute name="authType" use="optional">
+               <attribute name="TLS" type="conf:string"/>
+               <attribute name="Signing" type="conf:string"/>
+               <attribute name="signRequest" type="boolean" default="false"/>
+               <attribute name="signatureAlg" type="anyURI"/>
+               <attribute name="digestAlg" type="anyURI"/>
+               <attribute name="signedResponse" type="boolean" default="false"/>
+               <attribute name="signedAssertions" type="boolean" default="false"/>
+               <attribute name="authType">
                        <simpleType>
                                <restriction base="string">
                                        <enumeration value="basic"/>
                                </restriction>
                        </simpleType>
                </attribute>
-               <attribute name="authUsername" use="optional"/>
-               <attribute name="authPassword" use="optional"/>
+               <attribute name="authUsername"/>
+               <attribute name="authPassword"/>
        </attributeGroup>
 
        <element name="CredentialUse">