#include <typeinfo>
#include <string>
+#include <sstream>
#include <exception>
#include <new>
assert(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE);
major = gssEapRadiusAttrProviderInit(&minor);
- if (major == GSS_S_COMPLETE)
- major = gssEapSamlAttrProvidersInit(&minor);
- if (major == GSS_S_COMPLETE)
- major = gssEapLocalAttrProviderInit(&minor);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = gssEapSamlAttrProvidersInit(&minor);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ /* Allow Shibboleth initialization failure to be non-fatal */
+ gssEapLocalAttrProviderInit(&minor);
+
+cleanup:
#ifdef GSSEAP_DEBUG
assert(major == GSS_S_COMPLETE);
#endif
}
static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
-static gss_buffer_desc gssEapAttrPrefixes[ATTR_TYPE_MAX + 1];
/*
* Register a provider for a particular type and prefix
*/
void
gss_eap_attr_ctx::registerProvider(unsigned int type,
- const char *prefix,
gss_eap_attr_create_provider factory)
{
assert(type <= ATTR_TYPE_MAX);
assert(gssEapAttrFactories[type] == NULL);
gssEapAttrFactories[type] = factory;
- if (prefix != NULL) {
- gssEapAttrPrefixes[type].value = (void *)prefix;
- gssEapAttrPrefixes[type].length = strlen(prefix);
- } else {
- gssEapAttrPrefixes[type].value = NULL;
- gssEapAttrPrefixes[type].length = 0;
- }
}
/*
assert(type <= ATTR_TYPE_MAX);
gssEapAttrFactories[type] = NULL;
- gssEapAttrPrefixes[type].value = NULL;
- gssEapAttrPrefixes[type].length = 0;
}
/*
* Convert an attribute prefix to a type
*/
unsigned int
-gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix)
+gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix) const
{
unsigned int i;
for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
- if (bufferEqual(&gssEapAttrPrefixes[i], prefix))
+ const char *pprefix;
+
+ if (!providerEnabled(i))
+ continue;
+
+ pprefix = m_providers[i]->prefix();
+ if (pprefix == NULL)
+ continue;
+
+ if (strlen(pprefix) == prefix->length &&
+ memcmp(pprefix, prefix->value, prefix->length) == 0)
return i;
}
/*
* Convert a type to an attribute prefix
*/
-const gss_buffer_t
-gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type)
+gss_buffer_desc
+gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type) const
{
+ gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
+
if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
- return GSS_C_NO_BUFFER;
+ return prefix;
+
+ if (!providerEnabled(type))
+ return prefix;
+
+ prefix.value = (void *)m_providers[type]->prefix();
+ if (prefix.value != NULL)
+ prefix.length = strlen((char *)prefix.value);
- return &gssEapAttrPrefixes[type];
+ return prefix;
}
bool
* Initialize a context from an existing context.
*/
bool
-gss_eap_attr_ctx::initFromExistingContext(const gss_eap_attr_ctx *manager)
+gss_eap_attr_ctx::initWithExistingContext(const gss_eap_attr_ctx *manager)
{
bool ret = true;
provider = m_providers[i];
- ret = provider->initFromExistingContext(this,
+ ret = provider->initWithExistingContext(this,
manager->m_providers[i]);
if (ret == false) {
releaseProvider(i);
* Initialize a context from a GSS credential and context.
*/
bool
-gss_eap_attr_ctx::initFromGssContext(const gss_cred_id_t cred,
+gss_eap_attr_ctx::initWithGssContext(const gss_cred_id_t cred,
const gss_ctx_id_t ctx)
{
bool ret = true;
provider = m_providers[i];
- ret = provider->initFromGssContext(this, cred, ctx);
+ ret = provider->initWithGssContext(this, cred, ctx);
if (ret == false) {
releaseProvider(i);
break;
return ret;
}
-/*
- * Initialize a context from an exported context or name token
- */
bool
-gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
+gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj)
{
- bool ret;
- gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
- gss_buffer_desc primaryBuf;
+ bool ret = false;
+ bool foundSource[ATTR_TYPE_MAX + 1];
+ unsigned int type;
- if (buffer->length < 4)
- return false;
+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
+ foundSource[type] = false;
- m_flags = load_uint32_be(buffer->value);
+ if (obj["version"].integer() != 1)
+ return false;
- primaryBuf.length = buffer->length - 4;
- primaryBuf.value = (char *)buffer->value + 4;
+ m_flags = obj["flags"].integer();
- ret = primaryProvider->initFromBuffer(this, &primaryBuf);
- if (ret == false)
- return ret;
+ JSONObject sources = obj["sources"];
- for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ /* Initialize providers from serialized state */
+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
gss_eap_attr_provider *provider;
+ const char *key;
- if (!providerEnabled(i)) {
- releaseProvider(i);
+ if (!providerEnabled(type)) {
+ releaseProvider(type);
continue;
}
- provider = m_providers[i];
- if (provider == primaryProvider)
+ provider = m_providers[type];
+ key = provider->name();
+ if (key == NULL)
+ continue;
+
+ JSONObject source = sources.get(key);
+ if (!source.isNull() &&
+ !provider->initWithJsonObject(this, source)) {
+ releaseProvider(type);
+ return false;
+ }
+
+ foundSource[type] = true;
+ }
+
+ /* Initialize remaining providers from initialized providers */
+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
+ gss_eap_attr_provider *provider;
+
+ if (foundSource[type] || !providerEnabled(type))
continue;
- ret = provider->initFromGssContext(this,
+ provider = m_providers[type];
+
+ ret = provider->initWithGssContext(this,
GSS_C_NO_CREDENTIAL,
GSS_C_NO_CONTEXT);
if (ret == false) {
- releaseProvider(i);
- break;
+ releaseProvider(type);
+ return false;
}
}
+ return true;
+}
+
+JSONObject
+gss_eap_attr_ctx::jsonRepresentation(void) const
+{
+ JSONObject obj, sources;
+ unsigned int i;
+
+ obj.set("version", 1);
+ obj.set("flags", m_flags);
+
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
+ const char *key;
+
+ provider = m_providers[i];
+ if (provider == NULL)
+ continue; /* provider not initialised */
+
+ key = provider->name();
+ if (key == NULL)
+ continue; /* provider does not have state */
+
+ JSONObject source = provider->jsonRepresentation();
+ sources.set(key, source);
+ }
+
+ obj.set("sources", sources);
+
+ return obj;
+}
+
+/*
+ * Initialize a context from an exported context or name token
+ */
+bool
+gss_eap_attr_ctx::initWithBuffer(const gss_buffer_t buffer)
+{
+ OM_uint32 major, minor;
+ bool ret;
+ char *s;
+ json_error_t error;
+
+ major = bufferToString(&minor, buffer, &s);
+ if (GSS_ERROR(major))
+ return false;
+
+ JSONObject obj = JSONObject::load(s, 0, &error);
+ if (!obj.isNull()) {
+ ret = initWithJsonObject(obj);
+ } else
+ ret = false;
+
+ GSSEAP_FREE(s);
+
return ret;
}
}
/*
- * Locate provider for a given prefix
- */
-gss_eap_attr_provider *
-gss_eap_attr_ctx::getProvider(const gss_buffer_t prefix) const
-{
- unsigned int type;
-
- type = attributePrefixToType(prefix);
-
- return m_providers[type];
-}
-
-/*
* Get primary provider. Only the primary provider is serialised when
* gss_export_sec_context() or gss_export_name_composite() is called.
*/
};
static bool
-addAttribute(const gss_eap_attr_provider *provider GSSEAP_UNUSED,
+addAttribute(const gss_eap_attr_ctx *manager,
+ const gss_eap_attr_provider *provider GSSEAP_UNUSED,
const gss_buffer_t attribute,
void *data)
{
OM_uint32 major, minor;
if (args->type != ATTR_TYPE_LOCAL) {
- gss_eap_attr_ctx::composeAttributeName(args->type, attribute, &qualified);
+ manager->composeAttributeName(args->type, attribute, &qualified);
major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
gss_release_buffer(&minor, &qualified);
} else {
unsigned int i;
major = gss_create_empty_buffer_set(&minor, attrs);
- if (GSS_ERROR(major)) {
- throw new std::bad_alloc;
- return false;
- }
+ if (GSS_ERROR(major))
+ throw std::bad_alloc();
args.attrs = *attrs;
void
gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
{
- const gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
- gss_buffer_desc tmp;
- unsigned char *p;
- OM_uint32 tmpMinor;
+ OM_uint32 minor;
+ char *s;
- primaryProvider->exportToBuffer(&tmp);
+ JSONObject obj = jsonRepresentation();
- buffer->length = 4 + tmp.length;
- buffer->value = GSSEAP_MALLOC(buffer->length);
- if (buffer->value == NULL)
- throw new std::bad_alloc;
+#if 0
+ obj.dump(stdout);
+#endif
- p = (unsigned char *)buffer->value;
- store_uint32_be(m_flags, p);
- memcpy(p + 4, tmp.value, tmp.length);
+ s = obj.dump(JSON_COMPACT);
- gss_release_buffer(&tmpMinor, &tmp);
+ if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
+ throw std::bad_alloc();
}
/*
OM_uint32 major;
/* Errors we handle ourselves */
- major = GSS_S_FAILURE;
-
if (typeid(e) == typeid(std::bad_alloc)) {
+ major = GSS_S_FAILURE;
*minor = ENOMEM;
goto cleanup;
+ } else if (typeid(e) == typeid(JSONException)) {
+ major = GSS_S_BAD_NAME;
+ *minor = GSSEAP_BAD_ATTR_TOKEN;
+ gssEapSaveStatusInfo(*minor, "%s", e.what());
+ goto cleanup;
}
/* Errors we delegate to providers */
}
cleanup:
-#if 0
- /* rethrow for now for debugging */
- throw e;
-#endif
-
assert(GSS_ERROR(major));
return major;
void
gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
unsigned int *type,
- gss_buffer_t suffix)
+ gss_buffer_t suffix) const
{
gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
gss_eap_attr_ctx::composeAttributeName(unsigned int type,
const gss_buffer_t suffix)
{
- const gss_buffer_t prefix = attributeTypeToPrefix(type);
+ gss_buffer_desc prefix = attributeTypeToPrefix(type);
- return composeAttributeName(prefix, suffix);
+ return composeAttributeName(&prefix, suffix);
}
/*
void
gss_eap_attr_ctx::composeAttributeName(unsigned int type,
const gss_buffer_t suffix,
- gss_buffer_t attribute)
+ gss_buffer_t attribute) const
{
- gss_buffer_t prefix = attributeTypeToPrefix(type);
+ gss_buffer_desc prefix = attributeTypeToPrefix(type);
- return composeAttributeName(prefix, suffix, attribute);
+ return composeAttributeName(&prefix, suffix, attribute);
}
/*
gss_buffer_t display_value,
int *more)
{
- *authenticated = 0;
- *complete = 0;
+ if (authenticated != NULL)
+ *authenticated = 0;
+ if (complete != NULL)
+ *complete = 0;
if (value != NULL) {
value->length = 0;
gss_name_t name)
{
gss_eap_attr_ctx *ctx = NULL;
+ OM_uint32 major = GSS_S_FAILURE;
assert(name->attrCtx == NULL);
if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
return GSS_S_UNAVAILABLE;
- if (buffer->length != 0) {
- try {
- ctx = new gss_eap_attr_ctx();
+ if (buffer->length == 0)
+ return GSS_S_COMPLETE;
- if (!ctx->initFromBuffer(buffer)) {
- delete ctx;
- *minor = GSSEAP_BAD_ATTR_TOKEN;
- return GSS_S_DEFECTIVE_TOKEN;
- }
+ try {
+ ctx = new gss_eap_attr_ctx();
+
+ if (ctx->initWithBuffer(buffer)) {
name->attrCtx = ctx;
- } catch (std::exception &e) {
- delete ctx;
- return name->attrCtx->mapException(minor, e);
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+ } else {
+ major = GSS_S_BAD_NAME;
+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
}
+ } catch (std::exception &e) {
+ if (ctx != NULL)
+ major = ctx->mapException(minor, e);
}
- return GSS_S_COMPLETE;
+ assert(major == GSS_S_COMPLETE || name->attrCtx == NULL);
+
+ if (GSS_ERROR(major))
+ delete ctx;
+
+ return major;
}
OM_uint32
gss_name_t out)
{
gss_eap_attr_ctx *ctx = NULL;
+ OM_uint32 major = GSS_S_FAILURE;
assert(out->attrCtx == NULL);
+ if (in->attrCtx == NULL) {
+ *minor = 0;
+ return GSS_S_COMPLETE;
+ }
+
if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
return GSS_S_UNAVAILABLE;
try {
- if (in->attrCtx != NULL) {
- ctx = new gss_eap_attr_ctx();
- if (!ctx->initFromExistingContext(in->attrCtx)) {
- delete ctx;
- *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
- return GSS_S_FAILURE;
- }
+ ctx = new gss_eap_attr_ctx();
+
+ if (ctx->initWithExistingContext(in->attrCtx)) {
out->attrCtx = ctx;
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+ } else {
+ major = GSS_S_FAILURE;
+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
}
} catch (std::exception &e) {
- delete ctx;
- return in->attrCtx->mapException(minor, e);
+ major = in->attrCtx->mapException(minor, e);
}
+ assert(major == GSS_S_COMPLETE || out->attrCtx == NULL);
+
+ if (GSS_ERROR(major))
+ delete ctx;
+
return GSS_S_COMPLETE;
}
assert(gssCtx != GSS_C_NO_CONTEXT);
+ *pAttrContext = NULL;
+
major = gssEapAttrProvidersInit(minor);
if (GSS_ERROR(major))
return major;
- *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
- major = GSS_S_FAILURE;
-
try {
- ctx = new gss_eap_attr_ctx();
- if (ctx->initFromGssContext(gssCred, gssCtx)) {
- *minor = 0;
+ /* Set *pAttrContext here to for reentrancy */
+ *pAttrContext = ctx = new gss_eap_attr_ctx();
+
+ if (ctx->initWithGssContext(gssCred, gssCtx)) {
+ *pExpiryTime = ctx->getExpiryTime();
major = GSS_S_COMPLETE;
+ *minor = 0;
} else {
- delete ctx;
+ major = GSS_S_FAILURE;
+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
}
} catch (std::exception &e) {
if (ctx != NULL)
major = ctx->mapException(minor, e);
}
- if (major == GSS_S_COMPLETE) {
- *pAttrContext = ctx;
- *pExpiryTime = ctx->getExpiryTime();
+ if (GSS_ERROR(major)) {
+ delete ctx;
+ *pAttrContext = NULL;
}
return major;