map Shibboleth/OpenSAML exceptions to mech errors
authorLuke Howard <lukeh@padl.com>
Thu, 21 Oct 2010 13:36:25 +0000 (00:36 +1100)
committerLuke Howard <lukeh@padl.com>
Thu, 21 Oct 2010 13:36:25 +0000 (00:36 +1100)
gsseap_err.et
util_attr.cpp
util_attr.h
util_saml.cpp
util_saml.h
util_shib.cpp
util_shib.h

index 0f4420a..dd4fca3 100644 (file)
@@ -36,87 +36,107 @@ error_table eapg
 # Protocol errors that can be returned in an error token. This should match
 # up with makeErrorToken in accept_sec_context.c.
 #
-error_code GSSEAP_RESERVED,                 ""
-error_code GSSEAP_WRONG_SIZE,               "Buffer is incorrect size"
-error_code GSSEAP_WRONG_MECH,               "Mechanism OID is incorrect"
-error_code GSSEAP_BAD_TOK_HEADER,           "Token header is malformed or corrupt"
-error_code GSSEAP_TOK_TRUNC,                "Token is missing data"
-error_code GSSEAP_BAD_DIRECTION,            "Packet was replayed in wrong direction"
-error_code GSSEAP_WRONG_TOK_ID,             "Received token ID does not match expected token ID"
-error_code GSSEAP_CRIT_EXT_UNAVAILABLE,     "Critical extension unavailable"
-error_code GSSEAP_MISSING_REQUIRED_EXT,     "Missing required extension"
-error_code GSSEAP_KEY_UNAVAILABLE,          "EAP key unavailable"
-error_code GSSEAP_KEY_TOO_SHORT,            "EAP key too short"
-error_code GSSEAP_RADIUS_AUTH_FAILURE,      "Authentication rejected by RADIUS server"
-error_code GSSEAP_UNKNOWN_RADIUS_CODE,      "Received unknown response code from RADIUS server"
-error_code GSSEAP_MISSING_EAP_REQUEST,      "RADIUS response is missing EAP request"
-error_code GSSEAP_GENERIC_RADIUS_ERROR,     "Generic RADIUS error"
+error_code GSSEAP_RESERVED,                     ""
+error_code GSSEAP_WRONG_SIZE,                   "Buffer is incorrect size"
+error_code GSSEAP_WRONG_MECH,                   "Mechanism OID is incorrect"
+error_code GSSEAP_BAD_TOK_HEADER,               "Token header is malformed or corrupt"
+error_code GSSEAP_TOK_TRUNC,                    "Token is missing data"
+error_code GSSEAP_BAD_DIRECTION,                "Packet was replayed in wrong direction"
+error_code GSSEAP_WRONG_TOK_ID,                 "Received token ID does not match expected token ID"
+error_code GSSEAP_CRIT_EXT_UNAVAILABLE,         "Critical extension unavailable"
+error_code GSSEAP_MISSING_REQUIRED_EXT,         "Missing required extension"
+error_code GSSEAP_KEY_UNAVAILABLE,              "EAP key unavailable"
+error_code GSSEAP_KEY_TOO_SHORT,                "EAP key too short"
+error_code GSSEAP_RADIUS_AUTH_FAILURE,          "Authentication rejected by RADIUS server"
+error_code GSSEAP_UNKNOWN_RADIUS_CODE,          "Received unknown response code from RADIUS server"
+error_code GSSEAP_MISSING_EAP_REQUEST,          "RADIUS response is missing EAP request"
+error_code GSSEAP_GENERIC_RADIUS_ERROR,         "Generic RADIUS error"
 
 #
 # Context errors
 #
-error_code GSSEAP_CONTEXT_ESTABLISHED,      "Context is already fully established"
-error_code GSSEAP_CONTEXT_INCOMPLETE,       "Attempt to use incomplete security context"
-error_code GSSEAP_BAD_CONTEXT_TOKEN,        "Context token is malformed or corrupt"
-error_code GSSEAP_BAD_ERROR_TOKEN,          "Error token is malformed or corrupt"
-error_code GSSEAP_BAD_CONTEXT_OPTION,       "Bad context option"
+error_code GSSEAP_CONTEXT_ESTABLISHED,          "Context is already fully established"
+error_code GSSEAP_CONTEXT_INCOMPLETE,           "Attempt to use incomplete security context"
+error_code GSSEAP_BAD_CONTEXT_TOKEN,            "Context token is malformed or corrupt"
+error_code GSSEAP_BAD_ERROR_TOKEN,              "Error token is malformed or corrupt"
+error_code GSSEAP_BAD_CONTEXT_OPTION,           "Bad context option"
 
 #
 # Name errors
 #
-error_code GSSEAP_BAD_SERVICE_NAME,         "Name is not a valid service name"
-error_code GSSEAP_BAD_INITIATOR_NAME,       "Initiator identity must be a valid name"
-error_code GSSEAP_NO_HOSTNAME,              "Could not determine local host name"
+error_code GSSEAP_BAD_SERVICE_NAME,             "Name is not a valid service name"
+error_code GSSEAP_BAD_INITIATOR_NAME,           "Initiator identity must be a valid name"
+error_code GSSEAP_NO_HOSTNAME,                  "Could not determine local host name"
 
 #
 # Credential errors
 #
-error_code GSSEAP_BAD_USAGE,                "Credential usage type is unknown"
-error_code GSSEAP_CRED_USAGE_MISMATCH,      "Credential usage does not match requested usage"
-error_code GSSEAP_CRED_MECH_MISMATCH,       "Credential is not usable with this mechanism"
-error_code GSSEAP_BAD_CRED_OPTION,          "Bad credential option"
+error_code GSSEAP_BAD_USAGE,                    "Credential usage type is unknown"
+error_code GSSEAP_CRED_USAGE_MISMATCH,          "Credential usage does not match requested usage"
+error_code GSSEAP_CRED_MECH_MISMATCH,           "Credential is not usable with this mechanism"
+error_code GSSEAP_BAD_CRED_OPTION,              "Bad credential option"
 
 #
 # Wrap/unwrap/PRF errors
 #
-error_code GSSEAP_BAD_WRAP_TOKEN,           "Bad RFC 4121 wrap or MIC token"
-error_code GSSEAP_MISSING_IOV,              "IOV is missing required buffer"
-error_code GSSEAP_BAD_STREAM_IOV,           "Stream IOV can only contain a single data buffer"
-error_code GSSEAP_BAD_PADDING_IOV,          "Padding IOV is not permitted for RFC 4121 tokens"
-error_code GSSEAP_UNKNOWN_QOP,              "Unknown quality of protection specified"
-error_code GSSEAP_INPUT_TOO_LONG,           "PRF input too long"
-error_code GSSEAP_BAD_PRF_KEY,              "PRF key usage type is unknown"
+error_code GSSEAP_BAD_WRAP_TOKEN,               "Bad RFC 4121 wrap or MIC token"
+error_code GSSEAP_MISSING_IOV,                  "IOV is missing required buffer"
+error_code GSSEAP_BAD_STREAM_IOV,               "Stream IOV can only contain a single data buffer"
+error_code GSSEAP_BAD_PADDING_IOV,              "Padding IOV is not permitted for RFC 4121 tokens"
+error_code GSSEAP_UNKNOWN_QOP,                  "Unknown quality of protection specified"
+error_code GSSEAP_INPUT_TOO_LONG,               "PRF input too long"
+error_code GSSEAP_BAD_PRF_KEY,                  "PRF key usage type is unknown"
 
 #
 # libeap errors
 #
-error_code GSSEAP_LIBEAP_INIT_FAILURE,      "Failed to initialise EAP library"
-error_code GSSEAP_PEER_SM_INIT_FAILURE,     "Failed to create EAP state machine"
-error_code GSSEAP_PEER_AUTH_FAILURE,        "EAP peer authentication failure"
-error_code GSSEAP_PEER_BAD_MESSAGE,         "Received bad EAP message"
+error_code GSSEAP_LIBEAP_INIT_FAILURE,          "Failed to initialize EAP library"
+error_code GSSEAP_PEER_SM_INIT_FAILURE,         "Failed to create EAP state machine"
+error_code GSSEAP_PEER_AUTH_FAILURE,            "EAP peer authentication failure"
+error_code GSSEAP_PEER_BAD_MESSAGE,             "Received bad EAP message"
 
 #
 # RadSec initialisation errors
 #
-error_code GSSEAP_RADSEC_INIT_FAILURE,      "Failed to initialise RadSec library"
-error_code GSSEAP_RADSEC_CONTEXT_FAILURE,   "Failed to create RadSec context"
+error_code GSSEAP_RADSEC_INIT_FAILURE,          "Failed to initialize RadSec library"
+error_code GSSEAP_RADSEC_CONTEXT_FAILURE,       "Failed to create RadSec context"
 
 #
-# SAML/Shibboleth/attribute errors
+# Attribute errors
 #
-error_code GSSEAP_SAML_INIT_FAILURE,        "Failed to initialise SAML library"
-error_code GSSEAP_SHIB_INIT_FAILURE,        "Failed to initialise Shibboleth"
-error_code GSSEAP_NO_ATTR_CONTEXT,          "Name has no attributes"
-error_code GSSEAP_NO_ATTR_PROVIDERS,        "Failed to initialise attribute providers"
-error_code GSSEAP_NO_SUCH_ATTR,             "Unknown naming attribute"
-error_code GSSEAP_BAD_ATTR_TOKEN,           "Serialised attributes are malformed or corrupt"
-error_code GSSEAP_ATTR_CONTEXT_FAILURE,     "Failed to initialise attribute context"
+error_code GSSEAP_NO_ATTR_CONTEXT,              "Name has no attributes"
+error_code GSSEAP_NO_ATTR_PROVIDERS,            "Failed to initialize attribute providers"
+error_code GSSEAP_NO_SUCH_ATTR,                 "Unknown naming attribute"
+error_code GSSEAP_BAD_ATTR_TOKEN,               "Serialised attributes are malformed or corrupt"
+error_code GSSEAP_ATTR_CONTEXT_FAILURE,         "Failed to initialize attribute context"
+
+#
+# OpenSAML errors
+#
+error_code GSSEAP_SAML_INIT_FAILURE,            "Failed to initialize SAML library"
+error_code GSSEAP_SAML_SEC_POLICY_FAILURE,      "Failed to process SAML security policy"
+error_code GSSEAP_SAML_BINDING_FAILURE,         "Failed in SAML binding processing"
+error_code GSSEAP_SAML_PROFILE_FAILURE,         "Failed to process SAML profile"
+error_code GSSEAP_SAML_FATAL_PROFILE_FAILURE,   "Non-recoverable failure in SAML profile processing"
+error_code GSSEAP_SAML_RETRY_PROFILE_FAILURE,   "Temporary failure in SAML profile processing"
+error_code GSSEAP_SAML_METADATA_FAILURE,        "Failure related to SAML metadata use"
+
+#
+# Shibboleth errors
+#
+error_code GSSEAP_SHIB_INIT_FAILURE,            "Failed to initialize Shibboleth"
+error_code GSSEAP_SHIB_ATTR_FAILURE,            "Failure during local attribute processing"
+error_code GSSEAP_SHIB_ATTR_EXTRACT_FAILURE,    "Failed to extract local attributes"
+error_code GSSEAP_SHIB_ATTR_FILTER_FAILURE,     "Failed to filter local attributes"
+error_code GSSEAP_SHIB_ATTR_RESOLVE_FAILURE,    "Failed to resolve local attributes"
+error_code GSSEAP_SHIB_CONFIG_FAILURE,          "Local attribute configuration failure"
+error_code GSSEAP_SHIB_LISTENER_FAILURE,        "Failed to communicate with local attribute server"
 
 #
 # Extensions
 #
-error_code GSSEAP_BINDINGS_MISMATCH,        "Channel bindings do not match"
-error_code GSSEAP_NO_MECHGLUE_SYMBOL,       "Could not find symbol in mechanism glue"
-error_code GSSEAP_BAD_INVOCATION,           "Bad mechanism invoke OID"
+error_code GSSEAP_BINDINGS_MISMATCH,            "Channel bindings do not match"
+error_code GSSEAP_NO_MECHGLUE_SYMBOL,           "Could not find symbol in mechanism glue"
+error_code GSSEAP_BAD_INVOCATION,               "Bad mechanism invoke OID"
 
 end
index a428984..e5fb568 100644 (file)
@@ -601,25 +601,47 @@ gss_eap_attr_ctx::getExpiryTime(void) const
     return expiryTime;
 }
 
-/*
- * Map C++ exception to GSS status
- */
-static OM_uint32
-mapException(OM_uint32 *minor, std::exception &e)
+OM_uint32
+gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
 {
-    OM_uint32 major = GSS_S_FAILURE;
+    unsigned int i;
+    OM_uint32 major;
+
+    /* Errors we handle ourselves */
+    major = GSS_S_FAILURE;
 
-    /* XXX TODO implement other mappings */
-    if (typeid(e) == typeid(std::bad_alloc))
+    if (typeid(e) == typeid(std::bad_alloc)) {
         *minor = ENOMEM;
-    else
-        *minor = 0;
+        goto cleanup;
+    }
 
-#ifdef GSSEAP_DEBUG
+    /* Errors we delegate to providers */
+    major = GSS_S_CONTINUE_NEEDED;
+
+    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+        gss_eap_attr_provider *provider = m_providers[i];
+
+        if (provider == NULL)
+            continue;
+
+        major = provider->mapException(minor, e);
+        if (major != GSS_S_CONTINUE_NEEDED)
+            break;
+    }
+
+    if (major == GSS_S_CONTINUE_NEEDED) {
+        *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
+        major = GSS_S_FAILURE;
+    }
+
+cleanup:
+#if 0
     /* rethrow for now for debugging */
     throw e;
 #endif
 
+    assert(GSS_ERROR(major));
+
     return major;
 }
 
@@ -757,7 +779,7 @@ gssEapInquireName(OM_uint32 *minor,
             return GSS_S_UNAVAILABLE;
         }
     } catch (std::exception &e) {
-        return mapException(minor, e);
+        return name->attrCtx->mapException(minor, e);
     }
 
     return GSS_S_COMPLETE;
@@ -804,7 +826,7 @@ gssEapGetNameAttribute(OM_uint32 *minor,
             return GSS_S_UNAVAILABLE;
         }
     } catch (std::exception &e) {
-        return mapException(minor, e);
+        return name->attrCtx->mapException(minor, e);
     }
 
     return GSS_S_COMPLETE;
@@ -830,8 +852,8 @@ gssEapDeleteNameAttribute(OM_uint32 *minor,
                                  (int)attr->length, (char *)attr->value);
             return GSS_S_UNAVAILABLE;
         }
-    } catch (std::exception &ex) {
-        return mapException(minor, ex);
+    } catch (std::exception &e) {
+        return name->attrCtx->mapException(minor, e);
     }
 
     return GSS_S_COMPLETE;
@@ -859,8 +881,8 @@ gssEapSetNameAttribute(OM_uint32 *minor,
                                  (int)attr->length, (char *)attr->value);
             return GSS_S_UNAVAILABLE;
         }
-    } catch (std::exception &ex) {
-        return mapException(minor, ex);
+    } catch (std::exception &e) {
+        return name->attrCtx->mapException(minor, e);
     }
 
     return GSS_S_COMPLETE;
@@ -884,7 +906,7 @@ gssEapExportAttrContext(OM_uint32 *minor,
     try {
         name->attrCtx->exportToBuffer(buffer);
     } catch (std::exception &e) {
-        return mapException(minor, e);
+        return name->attrCtx->mapException(minor, e);
     }
 
     return GSS_S_COMPLETE;
@@ -914,7 +936,7 @@ gssEapImportAttrContext(OM_uint32 *minor,
             name->attrCtx = ctx;
         } catch (std::exception &e) {
             delete ctx;
-            return mapException(minor, e);
+            return name->attrCtx->mapException(minor, e);
         }
     }
 
@@ -945,7 +967,7 @@ gssEapDuplicateAttrContext(OM_uint32 *minor,
         }
     } catch (std::exception &e) {
         delete ctx;
-        return mapException(minor, e);
+        return in->attrCtx->mapException(minor, e);
     }
 
     return GSS_S_COMPLETE;
@@ -969,7 +991,7 @@ gssEapMapNameToAny(OM_uint32 *minor,
     try {
         *output = name->attrCtx->mapToAny(authenticated, type_id);
     } catch (std::exception &e) {
-        return mapException(minor, e);
+        return name->attrCtx->mapException(minor, e);
     }
 
     return GSS_S_COMPLETE;
@@ -994,7 +1016,7 @@ gssEapReleaseAnyNameMapping(OM_uint32 *minor,
             name->attrCtx->releaseAnyNameMapping(type_id, *input);
         *input = NULL;
     } catch (std::exception &e) {
-        return mapException(minor, e);
+        return name->attrCtx->mapException(minor, e);
     }
 
     return GSS_S_COMPLETE;
@@ -1025,19 +1047,29 @@ gssEapCreateAttrContext(OM_uint32 *minor,
 
     assert(gssCtx != GSS_C_NO_CONTEXT);
 
+    *pAttrContext = NULL;
+
     major = gssEapAttrProvidersInit(minor);
     if (GSS_ERROR(major))
         return major;
 
-    ctx = new gss_eap_attr_ctx();
-    if (!ctx->initFromGssContext(gssCred, gssCtx)) {
+    try {
+        ctx = new gss_eap_attr_ctx();
+        if (!ctx->initFromGssContext(gssCred, gssCtx)) {
+            delete ctx;
+            *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
+            return GSS_S_FAILURE;
+        }
+    } catch (std::exception &e) {
+        major = ctx->mapException(minor, e);
         delete ctx;
-        *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
-        return GSS_S_FAILURE;
+        return major;
     }
 
     gssCtx->expiryTime = ctx->getExpiryTime();
 
+    *pAttrContext = ctx;
+
     *minor = 0;
     return GSS_S_COMPLETE;
 }
index b0e3c05..9f28a90 100644 (file)
@@ -116,6 +116,9 @@ public:
 
     virtual time_t getExpiryTime(void) const { return 0; }
 
+    virtual OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const
+    { return GSS_S_CONTINUE_NEEDED; }
+
     static bool init(void) { return true; }
     static void finalize(void) {}
 
@@ -208,6 +211,7 @@ public:
     unregisterProvider(unsigned int type);
 
     time_t getExpiryTime(void) const;
+    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
 
 private:
     bool providerEnabled(unsigned int type) const;
index 7e61300..41ef77e 100644 (file)
 #include <xmltooling/util/ParserPool.h>
 #include <xmltooling/util/DateTime.h>
 
+#include <saml/exceptions.h>
 #include <saml/saml1/core/Assertions.h>
 #include <saml/saml2/core/Assertions.h>
 #include <saml/saml2/metadata/Metadata.h>
+#include <saml/saml2/metadata/MetadataProvider.h>
 
 using namespace xmltooling;
 using namespace opensaml::saml2md;
@@ -227,6 +229,28 @@ gss_eap_saml_assertion_provider::getExpiryTime(void) const
     return expiryTime;
 }
 
+OM_uint32
+gss_eap_saml_assertion_provider::mapException(OM_uint32 *minor,
+                                              std::exception &e) const
+{
+    if (typeid(e) == typeid(SecurityPolicyException))
+        *minor = GSSEAP_SAML_SEC_POLICY_FAILURE;
+    else if (typeid(e) == typeid(BindingException))
+        *minor = GSSEAP_SAML_BINDING_FAILURE;
+    else if (typeid(e) == typeid(ProfileException))
+        *minor = GSSEAP_SAML_PROFILE_FAILURE;
+    else if (typeid(e) == typeid(FatalProfileException))
+        *minor = GSSEAP_SAML_FATAL_PROFILE_FAILURE;
+    else if (typeid(e) == typeid(RetryableProfileException))
+        *minor = GSSEAP_SAML_RETRY_PROFILE_FAILURE;
+    else if (typeid(e) == typeid(MetadataException))
+        *minor = GSSEAP_SAML_METADATA_FAILURE;
+    else
+        return GSS_S_CONTINUE_NEEDED;
+
+    return GSS_S_FAILURE;
+}
+
 bool
 gss_eap_saml_assertion_provider::getAttribute(const gss_buffer_t attr,
                                               int *authenticated,
index 6be1c08..f3cb3cd 100644 (file)
@@ -88,6 +88,7 @@ public:
     }
 
     time_t getExpiryTime(void) const;
+    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
 
     static bool init(void);
     static void finalize(void);
index c02abfb..7ae23a8 100644 (file)
@@ -171,8 +171,10 @@ gss_eap_shib_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
     resolver = ShibbolethResolver::create();
 
     if (gssCred != GSS_C_NO_CREDENTIAL &&
-        gssEapDisplayName(&minor, gssCred->name, &nameBuf, NULL) == GSS_S_COMPLETE)
+        gssEapDisplayName(&minor, gssCred->name, &nameBuf, NULL) == GSS_S_COMPLETE) {
         resolver->setApplicationID((const char *)nameBuf.value);
+        gss_release_buffer(&minor, &nameBuf);
+    }
 
     m_authenticated = false;
 
@@ -192,12 +194,13 @@ gss_eap_shib_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
         m_attributes = resolver->getResolvedAttributes();
         resolver->getResolvedAttributes().clear();
     } catch (exception &e) {
+#if 0
+        delete resolver;
+        throw e;
+#endif
     }
 
-    gss_release_buffer(&minor, &nameBuf);
-
     delete resolver;
-
     return true;
 }
 
@@ -459,6 +462,28 @@ gss_eap_shib_attr_provider::finalize(void)
     ShibbolethResolver::term();
 }
 
+OM_uint32
+gss_eap_shib_attr_provider::mapException(OM_uint32 *minor,
+                                         std::exception &e) const
+{
+    if (typeid(e) == typeid(AttributeException))
+        *minor = GSSEAP_SHIB_ATTR_FAILURE;
+    else if (typeid(e) == typeid(AttributeExtractionException))
+        *minor = GSSEAP_SHIB_ATTR_EXTRACT_FAILURE;
+    else if (typeid(e) == typeid(AttributeFilteringException))
+        *minor = GSSEAP_SHIB_ATTR_FILTER_FAILURE;
+    else if (typeid(e) == typeid(AttributeResolutionException))
+        *minor = GSSEAP_SHIB_ATTR_RESOLVE_FAILURE;
+    else if (typeid(e) == typeid(ConfigurationException))
+        *minor = GSSEAP_SHIB_CONFIG_FAILURE;
+    else if (typeid(e) == typeid(ListenerException))
+        *minor = GSSEAP_SHIB_LISTENER_FAILURE;
+    else
+        return GSS_S_CONTINUE_NEEDED;
+
+    return GSS_S_FAILURE;
+}
+
 gss_eap_attr_provider *
 gss_eap_shib_attr_provider::createAttrContext(void)
 {
index 8224547..f9ede20 100644 (file)
@@ -83,6 +83,8 @@ public:
     static bool init(void);
     static void finalize(void);
 
+    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
+
     static gss_eap_attr_provider *createAttrContext(void);
 
 private: