From: Mark Donnelly Date: Fri, 18 Apr 2014 12:49:33 +0000 (-0400) Subject: Parse gss_init_sec_context parameters out of a JSON string X-Git-Url: http://www.project-moonshot.org/gitweb/?p=gssweb.git;a=commitdiff_plain;h=9313e0be56ac9b97709acf61388bcd4c94197162 Parse gss_init_sec_context parameters out of a JSON string --- diff --git a/json_gssapi/CMakeLists.txt b/json_gssapi/CMakeLists.txt index 7b68788..cb2d217 100644 --- a/json_gssapi/CMakeLists.txt +++ b/json_gssapi/CMakeLists.txt @@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 2.8) project(json_gssapi) -add_executable(json_gssapi src/GSSCreateSecContextCommand.cpp src/GSSCommand.cpp main.cpp) -target_link_libraries(json_gssapi gss) +add_executable(json_gssapi src/GSSCreateSecContextCommand.cpp src/GSSCommand.cpp src/util_json.cpp main.cpp) +target_link_libraries(json_gssapi gssapi_krb5 jansson) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules/") diff --git a/json_gssapi/cmake_modules/FindCPPUNIT.cmake b/json_gssapi/cmake_modules/FindCPPUNIT.cmake new file mode 100644 index 0000000..4ee0094 --- /dev/null +++ b/json_gssapi/cmake_modules/FindCPPUNIT.cmake @@ -0,0 +1,54 @@ +# +# Find the CppUnit includes and library +# +# This module defines +# CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc. +# CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit. +# CPPUNIT_FOUND, If false, do not try to use CppUnit. + +# also defined, but not for general use are +# CPPUNIT_LIBRARY, where to find the CppUnit library. +# CPPUNIT_DEBUG_LIBRARY, where to find the CppUnit library in debug +# mode. + +SET(CPPUNIT_FOUND "NO") + +FIND_PATH(CPPUNIT_INCLUDE_DIR cppunit/TestCase.h /usr/local/include /usr/include) + +# With Win32, important to have both +IF(WIN32) + FIND_LIBRARY(CPPUNIT_LIBRARY cppunit + ${CPPUNIT_INCLUDE_DIR}/../lib + /usr/local/lib + /usr/lib) + FIND_LIBRARY(CPPUNIT_DEBUG_LIBRARY cppunitd + ${CPPUNIT_INCLUDE_DIR}/../lib + /usr/local/lib + /usr/lib) +ELSE(WIN32) + # On unix system, debug and release have the same name + FIND_LIBRARY(CPPUNIT_LIBRARY cppunit + ${CPPUNIT_INCLUDE_DIR}/../lib + /usr/local/lib + /usr/lib) + FIND_LIBRARY(CPPUNIT_DEBUG_LIBRARY cppunit + ${CPPUNIT_INCLUDE_DIR}/../lib + /usr/local/lib + /usr/lib) +ENDIF(WIN32) + +IF(CPPUNIT_INCLUDE_DIR) + IF(CPPUNIT_LIBRARY) + SET(CPPUNIT_FOUND "YES") + SET(CPPUNIT_LIBRARIES ${CPPUNIT_LIBRARY} ${CMAKE_DL_LIBS}) + SET(CPPUNIT_DEBUG_LIBRARIES ${CPPUNIT_DEBUG_LIBRARY} ${CMAKE_DL_LIBS}) + ELSE (CPPUNIT_LIBRARY) + IF (CPPUNIT_FIND_REQUIRED) + MESSAGE(SEND_ERROR "Could not find library CppUnit.") + ENDIF (CPPUNIT_FIND_REQUIRED) + ENDIF(CPPUNIT_LIBRARY) +ELSE(CPPUNIT_INCLUDE_DIR) + IF (CPPUNIT_FIND_REQUIRED) + MESSAGE(SEND_ERROR "Could not find library CppUnit.") + ENDIF(CPPUNIT_FIND_REQUIRED) +ENDIF(CPPUNIT_INCLUDE_DIR) diff --git a/json_gssapi/src/CMakeLists.txt b/json_gssapi/src/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/json_gssapi/src/GSSCommand.cpp b/json_gssapi/src/GSSCommand.cpp new file mode 100644 index 0000000..22993da --- /dev/null +++ b/json_gssapi/src/GSSCommand.cpp @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2014 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + +#include "GSSCommand.h" diff --git a/json_gssapi/src/GSSCommand.h b/json_gssapi/src/GSSCommand.h new file mode 100644 index 0000000..20955af --- /dev/null +++ b/json_gssapi/src/GSSCommand.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + +#ifndef GSSCOMMAND_H +#define GSSCOMMAND_H + +#include "util_json.h" +#include + +class GSSCommand +{ +public: + GSSCommand() {}; + GSSCommand(void *fn) : function(fn) {}; + GSSCommand(JSONObject params, void *fn) : parameters(params), function(fn) { }; + + void *getGSSFunction() { return function; }; + virtual void execute() { std::cout << "\ninside GSSCommand::invoke()\n"; }; +protected: + void *function; + JSONObject parameters; +}; + +#endif // GSSCOMMAND_H diff --git a/json_gssapi/src/GSSCreateSecContextCommand.cpp b/json_gssapi/src/GSSCreateSecContextCommand.cpp new file mode 100644 index 0000000..94719d1 --- /dev/null +++ b/json_gssapi/src/GSSCreateSecContextCommand.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2014 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + +#include "GSSCreateSecContextCommand.h" +#include +#include +#include + +typedef OM_uint32 (*init_sec_context)( + OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* claimant_cred_handle */ + gss_ctx_id_t *, /* context_handle */ + gss_name_t, /* target_name */ + gss_OID, /* mech_type (used to be const) */ + OM_uint32, /* req_flags */ + OM_uint32, /* time_req */ + gss_channel_bindings_t, /* input_chan_bindings */ + gss_buffer_t, /* input_token */ + gss_OID *, /* actual_mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32 *, /* ret_flags */ + OM_uint32 * /* time_req */ +); + +/* Helper function - import the OID from a string */ +gss_OID str_to_oid(const char *mech_type_str = NULL) +{ + /* Variables */ + gss_buffer_t gssbuffOID; + gss_OID gssoidTargetOID; + OM_uint32 major; + OM_uint32 minor; + + /* Error checking */ + if (mech_type_str == NULL || + *mech_type_str == 0) + return NULL; + + /* Setup */ + gssbuffOID = (gss_buffer_t)malloc(sizeof(gss_buffer_desc_struct)); + + /* Main */ + gssbuffOID->value = (void *)(mech_type_str); + gssbuffOID->length = strlen(mech_type_str); + major = gss_str_to_oid(&minor, + gssbuffOID, + &gssoidTargetOID); + if (major != GSS_S_COMPLETE) + throw "Error converting string to OID: " + minor; + + /* Cleanup */ + free(gssbuffOID); + + /* Return */ + return gssoidTargetOID; +} + +void +GSSCreateSecContextCommand::execute() +{ + init_sec_context fn = (init_sec_context)function; + + input_token = GSS_C_NO_BUFFER; + output_token = (gss_buffer_t)malloc(sizeof(gss_buffer_desc)); + + retVal = fn( + &minor_status, + GSS_C_NO_CREDENTIAL, + &context_handle, + target_name, + mech_type, + req_flags, + time_req, + GSS_C_NO_CHANNEL_BINDINGS, + input_token, + &actual_mech_type, + output_token, + &ret_flags, + &time_rec); +} + +const char* GSSCreateSecContextCommand::getTargetDisplayName() +{ + /* Variables */ + gss_buffer_t output_name; + gss_OID output_type; + OM_uint32 major, minor; + const char *ret; + + /* error checking */ + + /* Setup */ + output_name = (gss_buffer_t)malloc(sizeof(gss_buffer_desc_struct)); + output_type = (gss_OID)malloc(sizeof(gss_OID_desc_struct)); + + /* Main */ + major = gss_display_name(&minor, target_name, output_name, &output_type); + if (major == GSS_S_COMPLETE) + ret = (const char *)output_name->value; + else + ret = NULL; + + /* cleanup */ + free(output_name); + free(output_type); + + /* return */ + return( (char *)(output_name->value) ); +} + +const char* GSSCreateSecContextCommand::getMechType() +{ + gss_buffer_t output; + OM_uint32 major, minor; + const char *retVal; + + /* error checking */ + if (mech_type == NULL) + return NULL; + + /* Setup */ + output = (gss_buffer_t)malloc(sizeof(gss_buffer_desc_struct)); + + /* main */ + major = gss_oid_to_str(&minor, mech_type, output); + if (major == GSS_S_COMPLETE) + retVal = (const char *)output->value; + else + retVal = NULL; + + /* cleanup */ + free(output); + + /* return */ + return( retVal ); +} + +bool GSSCreateSecContextCommand::loadParameters(JSONObject *params) +{ + /* Variables */ + OM_uint32 major, minor; + gss_buffer_t gssbuffTargetName; + const char *buffer; + + /* Error checking */ + // Should I zeroOut? + + /* Setup */ + + /* Main processing */ + // Easy stuff + this->time_req = (OM_uint32)( (*params)["time_req"].integer() ); + this->req_flags = (OM_uint32)( (*params)["req_flags"].integer() ); + + // context_handle + // -- just treat the value passed in as correct. + context_handle = (gss_ctx_id_t)( (*params)["context_handle"].integer() ); + + // target_name + buffer = (*params)["target_name"].string(); + if (buffer != NULL && *buffer != 0) + { + gssbuffTargetName = (gss_buffer_t)malloc(sizeof(gss_buffer_desc_struct)); + gssbuffTargetName->value = (void *)buffer; + gssbuffTargetName->length = strlen( buffer ); + + major = gss_import_name(&minor, + gssbuffTargetName, + GSS_C_NO_OID, + &target_name); + if (major != GSS_S_COMPLETE) + throw "Error importing target_name: " + minor; + + free(gssbuffTargetName); + } + + // mech_type + mech_type = str_to_oid( (*params)["mech_type"].string() ); + + // input_token + buffer = (*params)["input_token"].string(); + if (buffer != NULL && *buffer != 0) + { + this->input_token = (gss_buffer_t)malloc(sizeof(gss_buffer_desc_struct)); + this->input_token->value = (void *)buffer; + this->input_token->length = strlen(buffer); + } + + /* Cleanup */ + + + /* Return */ + return true; +} + +bool GSSCreateSecContextCommand::zeroOut(bool initialized) +{ + /* Error checking */ + /* Variables */ + OM_uint32 minor; + gss_buffer_t output; + + /* Setup */ + output = (gss_buffer_t)malloc(sizeof(gss_buffer_desc_struct)); + + /* Main */ + + // Free up existing memory if it's been set. + if (initialized) + { + if (this->context_handle != NULL) + gss_delete_sec_context(&minor, &(this->context_handle), output); + + if (this->target_name != NULL) + gss_release_name(&minor, &(this->target_name)); + + if (mech_type != NULL) + gss_release_oid(&minor, &(this->mech_type)); + + if (this->input_token != NULL) + { + gss_release_buffer(&minor, this->input_token); + free(this->input_token); + } + + if (this->actual_mech_type != NULL) + gss_release_oid(&minor, &(this->actual_mech_type)); + + if (this->output_token != NULL) + { + gss_release_buffer(&minor, this->output_token); + free( this->output_token ); + } + } + + // Now set things to reasonable defaults + this->retVal = 0; + this->minor_status = 0; + this->req_flags = 0; + this->time_req = 0; + this->ret_flags = 0; + this->time_rec = 0; + + this->context_handle = GSS_C_NO_CONTEXT; + this->target_name = GSS_C_NO_NAME; + mech_type = str_to_oid( "{ 1 2 840 113554 1 2 1 4 }" ); + this->input_token = GSS_C_NO_BUFFER; + this->actual_mech_type = GSS_C_NO_OID; + this->output_token = GSS_C_NO_BUFFER; + memset((void *)&(this->parameters), 0, sizeof(JSONObject)); + + /* Cleanup */ + free(output); + + /* Return */ + return(true); +} + +GSSCreateSecContextCommand::GSSCreateSecContextCommand( + JSONObject *params, + void *fn) : GSSCommand(params, fn) +{ + zeroOut(false); + loadParameters(params); +} + +GSSCreateSecContextCommand::GSSCreateSecContextCommand(void *fn) : GSSCommand(fn) +{ + zeroOut(false); +} \ No newline at end of file diff --git a/json_gssapi/src/GSSCreateSecContextCommand.h b/json_gssapi/src/GSSCreateSecContextCommand.h new file mode 100644 index 0000000..4eb1bdf --- /dev/null +++ b/json_gssapi/src/GSSCreateSecContextCommand.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + +#ifndef GSSCREATESECCONTEXTCOMMAND_H +#define GSSCREATESECCONTEXTCOMMAND_H + +#include "GSSCommand.h" +#include + +class GSSCreateSecContextCommand : public GSSCommand +{ +public: + + OM_uint32 retVal; + OM_uint32 minor_status; + gss_ctx_id_t context_handle; + gss_name_t target_name; + gss_OID mech_type; + OM_uint32 req_flags; + OM_uint32 time_req; + gss_buffer_t input_token; + gss_OID actual_mech_type; + gss_buffer_t output_token; + OM_uint32 ret_flags; + OM_uint32 time_rec; + + + void execute(); + GSSCreateSecContextCommand(void *fn = (void *)&gss_init_sec_context); + GSSCreateSecContextCommand(JSONObject *params, void *fn = (void *)&gss_init_sec_context); + + bool loadParameters(JSONObject *params); + bool zeroOut(bool initialized = true); + + + // accessors + OM_uint32 getReqFlags() { return req_flags; } + OM_uint32 getTimeReq() { return time_req; } + gss_ctx_id_t getContextHandle() { return context_handle; } + + // complex accessors + const char * getTargetDisplayName(); + const char * getMechType(); + +private: +}; + +#endif // GSSCREATESECCONTEXTCOMMAND_H diff --git a/json_gssapi/src/util_json.cpp b/json_gssapi/src/util_json.cpp new file mode 100644 index 0000000..dbd453e --- /dev/null +++ b/json_gssapi/src/util_json.cpp @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * JSONObject utilities. + */ + +#include "util_json.h" + +#include +#include +#include +#include +#include + +#define JSON_INIT(obj) do { \ + if ((obj) == NULL) \ + throw std::bad_alloc(); \ + m_obj = (obj); \ + } while (0) + +#define JSON_CHECK_CONTAINER() do { \ + if (!json_is_object(m_obj) && !json_is_array(m_obj)) { \ + std::string s("JSONObject is not a container"); \ + throw JSONException(m_obj); \ + } \ + } while (0) + +#define JSON_CHECK_OBJECT() do { \ + if (!json_is_object(m_obj)) { \ + std::string s("JSONObject is not a dictionary"); \ + throw JSONException(m_obj, JSON_OBJECT); \ + } \ + } while (0) + +#define JSON_CHECK_ARRAY() do { \ + if (!json_is_array(m_obj)) { \ + throw JSONException(m_obj, JSON_ARRAY); \ + } \ + } while (0) + +#define JSON_CHECK(s) do { \ + if ((s) != 0) \ + throw JSONException(); \ + } while (0) + +JSONObject +JSONObject::load(const char *input, size_t flags, json_error_t *error) +{ + json_t *obj; + + obj = json_loads(input, flags, error); + + return JSONObject(obj, false); +} + +JSONObject +JSONObject::load(FILE *fp, size_t flags, json_error_t *error) +{ + json_t *obj; + + obj = json_loadf(fp, flags, error); + + return JSONObject(obj, false); +} + +char * +JSONObject::dump(size_t flags) const +{ + char *s = json_dumps(m_obj, flags); + + if (s == NULL) + throw std::bad_alloc(); + + return s; +} + +void +JSONObject::dump(FILE *fp, size_t flags) const +{ + int r = json_dumpf(m_obj, fp, flags); + + if (r != 0) + throw std::bad_alloc(); +} + +size_t +JSONObject::size(void) const +{ + if (json_is_object(m_obj)) + return json_object_size(m_obj); + else if (json_is_array(m_obj)) + return json_array_size(m_obj); + else + return 0; +} + +JSONObject::JSONObject(json_t *obj, bool retain) +{ + if (retain) + json_incref(obj); + JSON_INIT(obj); +} + +JSONObject::JSONObject(const char *value) +{ + json_t *obj = json_string(value); + + JSON_INIT(obj); +} + +JSONObject::JSONObject(json_int_t value) +{ + json_t *obj = json_integer(value); + + JSON_INIT(obj); +} + +JSONObject::JSONObject(double value) +{ + json_t *obj = json_real(value); + + JSON_INIT(obj); +} + +JSONObject::JSONObject(bool value) +{ + json_t *obj = value ? json_true() : json_false(); + + JSON_INIT(obj); +} + +JSONObject::JSONObject(void) +{ + json_t *obj = json_object(); + + JSON_INIT(obj); +} + +JSONObject +JSONObject::object(void) +{ + return JSONObject(); +} + +JSONObject +JSONObject::null(void) +{ + return JSONObject(json_null(), false); +} + +JSONObject +JSONObject::array(void) +{ + return JSONObject(json_array(), false); +} + +void +JSONObject::set(const char *key, JSONObject &value) +{ + JSON_CHECK_OBJECT(); + JSON_CHECK(json_object_set_new(m_obj, key, value.get())); +} + +void +JSONObject::set(const char *key, const char *value) +{ + JSONObject jobj(value); + set(key, jobj); +} + +void +JSONObject::set(const char *key, json_int_t value) +{ + JSONObject jobj(value); + set(key, jobj); +} + +void +JSONObject::del(const char *key) +{ + json_object_del(m_obj, key); +} + +JSONObject +JSONObject::get(const char *key) const +{ + json_t *obj; + + obj = json_object_get(m_obj, key); + if (obj == NULL) + return JSONObject::null(); + + return JSONObject(obj, true); +} + +JSONObject +JSONObject::get(size_t index) const +{ + json_t *obj; + + obj = json_array_get(m_obj, index); + if (obj == NULL) + return JSONObject::null(); + + return JSONObject(obj, true); +} + +void +JSONObject::update(JSONObject &value) +{ + JSON_CHECK_OBJECT(); + json_t *other = value.get(); + JSON_CHECK(json_object_update(m_obj, other)); + json_decref(other); +} + +JSONObject +JSONObject::operator[](size_t index) const +{ + return get(index); +} + +JSONObject +JSONObject::operator[](const char *key) const +{ + return get(key); +} + +void +JSONObject::append(JSONObject &value) +{ + JSON_CHECK_ARRAY(); + JSON_CHECK(json_array_append_new(m_obj, value.get())); +} + +void +JSONObject::insert(size_t index, JSONObject &value) +{ + JSON_CHECK_ARRAY(); + JSON_CHECK(json_array_insert_new(m_obj, index, value.get())); +} + +void +JSONObject::remove(size_t index) +{ + JSON_CHECK_ARRAY(); + JSON_CHECK(json_array_remove(m_obj, index)); +} + +void +JSONObject::clear(void) +{ + JSON_CHECK_CONTAINER(); + + if (json_is_object(m_obj)) { + JSON_CHECK(json_object_clear(m_obj)); + } else if (json_is_array(m_obj)) { + JSON_CHECK(json_array_clear(m_obj)); + } +} + +void +JSONObject::extend(JSONObject &value) +{ + JSON_CHECK_ARRAY(); + json_t *other = value.get(); + JSON_CHECK(json_array_extend(m_obj, other)); + json_decref(other); +} + +const char * +JSONObject::string(void) const +{ + return json_string_value(m_obj); +} + +json_int_t +JSONObject::integer(void) const +{ + return json_integer_value(m_obj); +} + +double +JSONObject::real(void) const +{ + return json_real_value(m_obj); +} + +double +JSONObject::number(void) const +{ + return json_number_value(m_obj); +} + +bool JSONObject::isObject(void) const +{ + return json_is_object(m_obj); +} + +bool JSONObject::isArray(void) const +{ + return json_is_array(m_obj); +} + +bool JSONObject::isString(void) const +{ + return json_is_string(m_obj); +} + +bool JSONObject::isInteger(void) const +{ + return json_is_integer(m_obj); +} + +bool JSONObject::isNumber(void) const +{ + return json_is_number(m_obj); +} + +bool JSONObject::isBoolean(void) const +{ + return json_is_boolean(m_obj); +} + +bool JSONObject::isNull(void) const +{ + return json_is_null(m_obj); +} + +JSONIterator::JSONIterator(const JSONObject &obj) +{ + m_obj = obj.get(); + m_iter = json_object_iter(m_obj); +} + +JSONIterator::~JSONIterator(void) +{ + json_decref(m_obj); +} + +const char * +JSONIterator::key(void) const +{ + return json_object_iter_key(m_iter); +} + +JSONObject +JSONIterator::value(void) const +{ + return JSONObject(json_object_iter_value(m_iter)); +} + +bool +JSONIterator::next(void) +{ + m_iter = json_object_iter_next(m_obj, m_iter); + return m_iter != NULL; +} + +JSONException::JSONException(json_t *obj, json_type type) +{ + char *s = NULL; + const char *t; + + m_obj = json_incref(obj); + m_type = type; + + if (obj != NULL) + s = json_dumps(m_obj, 0); + + switch (type) { + case JSON_OBJECT: t = "OBJECT"; break; + case JSON_ARRAY: t = "ARRAY"; break; + case JSON_STRING: t = "STRING"; break; + case JSON_INTEGER: t = "INTEGER"; break; + case JSON_REAL: t = "REAL"; break; + case JSON_TRUE: t = "TRUE"; break; + case JSON_FALSE: t = "FALSE"; break; + case JSON_NULL: t = "NULL"; break; + default: t = "UNKNOWN"; break; + } + + if (obj != NULL) { + m_reason = "Invalid JSON object: " + std::string(s); + if (type != JSON_NULL) + m_reason += " (excepted type " + std::string(t) + ")"; + } else { + m_reason = "Internal JSON error"; + } + + if (s != NULL) + free(s); +} diff --git a/json_gssapi/src/util_json.h b/json_gssapi/src/util_json.h new file mode 100644 index 0000000..c9358df --- /dev/null +++ b/json_gssapi/src/util_json.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * JSON object wrapper with not-entirely-toll-free DDF bridging. + */ + +#ifndef _UTIL_JSON_H_ +#define _UTIL_JSON_H_ 1 + +#ifdef __cplusplus +#include +#include + +#include + + +class JSONObject; + +class JSONException : public std::exception { +public: + JSONException(json_t *obj = NULL, json_type type = JSON_NULL); + + ~JSONException(void) throw() { + json_decref(m_obj); + } + + virtual const char *what(void) const throw() { + return m_reason.c_str(); + } + +private: + json_t *m_obj; + json_type m_type; + std::string m_reason; +}; + +class JSONIterator { +public: + JSONIterator(const JSONObject &obj); + ~JSONIterator(void); + const char *key(void) const; + JSONObject value(void) const; + bool next(void); + +private: + json_t *m_obj; + void *m_iter; +}; + +class JSONObject { +public: + static JSONObject load(const char *input, size_t flags, json_error_t *error); + static JSONObject load(FILE *, size_t flags, json_error_t *error); + + static JSONObject object(void); + static JSONObject array(void); + static JSONObject null(void); + + char *dump(size_t flags = 0) const; + void dump(FILE *fp, size_t flags = JSON_INDENT(4)) const; + + json_type type(void) const { return json_typeof(m_obj); } + size_t size(void) const; + + JSONObject(void); + JSONObject(const char *value); + JSONObject(json_int_t value); + JSONObject(double value); + JSONObject(bool value); + + void set(const char *key, JSONObject &value); + void set(const char *key, const char *value); + void set(const char *key, json_int_t value); + void del(const char *key); + void update(JSONObject &value); + JSONIterator iterator(void) const { return JSONIterator(*this); } + JSONObject get(const char *key) const; + JSONObject operator[](const char *key) const; + + JSONObject get(size_t index) const; + JSONObject operator[](size_t index) const; + void append(JSONObject &value); + void insert(size_t index, JSONObject &value); + void remove(size_t index); + void clear(void); + void extend(JSONObject &value); + + const char *string(void) const; + json_int_t integer(void) const; + double real(void) const; + double number(void) const; +#ifdef HAVE_SHIBRESOLVER + DDF ddf(void) const; +#endif + + bool isObject(void) const; + bool isArray(void) const; + bool isString(void) const; + bool isInteger(void) const; + bool isNumber(void) const; + bool isBoolean(void) const; + bool isNull(void) const; + + ~JSONObject(void) + { + if (m_obj != NULL) + json_decref(m_obj); + } + + JSONObject(const JSONObject &obj) + { + m_obj = json_incref(obj.m_obj); + } + + JSONObject& operator=(const JSONObject &obj) + { + if (this != &obj) + set(obj.m_obj); + return *this; + } + +private: + friend class JSONIterator; + + json_t *get(void) const { + return json_incref(m_obj); + } + + void set(json_t *obj) { + if (m_obj != obj) { + json_decref(m_obj); + m_obj = json_incref(m_obj); + } + } + + JSONObject(json_t *obj, bool retain = true); + + json_t *m_obj; +}; + + +#endif /* __cplusplus */ + +#endif /* _UTIL_JSON_H_ */ diff --git a/json_gssapi/test/CMakeLists.txt b/json_gssapi/test/CMakeLists.txt new file mode 100644 index 0000000..f43e6e5 --- /dev/null +++ b/json_gssapi/test/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories(${CMAKE_SOURCE_DIR}/src) + +add_executable(test InitSecContextMock.cpp GSSCreateSecContextTest.cpp test_run.cpp JSONParseTest.cpp ../src/GSSCreateSecContextCommand.cpp ../src/util_json.cpp) + +target_link_libraries(test cppunit gssapi_krb5 jansson) + +# install(TARGETS test RUNTIME DESTINATION bin) diff --git a/json_gssapi/test/GSSCreateSecContextTest.cpp b/json_gssapi/test/GSSCreateSecContextTest.cpp new file mode 100644 index 0000000..0cf7ad5 --- /dev/null +++ b/json_gssapi/test/GSSCreateSecContextTest.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2014 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + + +#include "GSSCreateSecContextTest.h" +#include "GSSCreateSecContextCommand.h" +#include "InitSecContextMock.h" +#include +#include +#include +#include "util_json.h" + +// Registers the fixture into the 'registry' +CPPUNIT_TEST_SUITE_REGISTRATION( GSSCreateSecContextTest ); + + + +OM_uint32 KRB5_CALLCONV +mock_init_sec( + OM_uint32 *minor_status, + gss_cred_id_t claimant_cred_handle, + gss_ctx_id_t *context_handle, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + InitSecContextMock::visited = true; + + /* Copy in the input to this function */ + InitSecContextMock::claimant_cred_handle = claimant_cred_handle; + InitSecContextMock::target_name = target_name; + InitSecContextMock::mech_type = mech_type; + InitSecContextMock::req_flags = req_flags; + InitSecContextMock::time_req = time_req; + InitSecContextMock::input_chan_bindings = input_chan_bindings; + InitSecContextMock::input_token = input_token; + + /* Copy out the output from this function */ + *minor_status = InitSecContextMock::minor_status; + *actual_mech_type = InitSecContextMock::actual_mech_type; + output_token->length = InitSecContextMock::output_token->length; + output_token->value = InitSecContextMock::output_token->value; + *ret_flags = InitSecContextMock::ret_flags; + *time_rec = InitSecContextMock::time_rec; + + /* Handle the one that's I/O */ + if (*context_handle == GSS_C_NO_CONTEXT) + { + *context_handle = InitSecContextMock::context_handle; + } else if (*context_handle != InitSecContextMock::context_handle) + { + InitSecContextMock::invalidContextHandle = true; + } + + return InitSecContextMock::retVal; +} + + +void +GSSCreateSecContextTest::setUp() +{ + InitSecContextMock::reset(); +} + +void +GSSCreateSecContextTest::tearDown() +{ +} + +void +GSSCreateSecContextTest::testConstructor() +{ + GSSCreateSecContextCommand cmd = GSSCreateSecContextCommand(); + void *cmdFn; + void *GSSFn; + + cmdFn = cmd.getGSSFunction(); + GSSFn = (void *)&gss_init_sec_context; + CPPUNIT_ASSERT_MESSAGE("The default constructor for GSSCreateSecContextCommand should assign the function gss_init_sec_context", cmdFn == GSSFn); +} + + +void GSSCreateSecContextTest::testConstructorWithJSONObject() +{ + const char* input = "{\"req_flags\": \"1\", \ + \"time_req\": \"2\", \ + \"mech_type\": \"{ 1 2 840 113554 1 2 1 4 }\", \ + \"target_name\": \"me@my.sha/DOW\"}"; + + json_error_t jsonErr; + JSONObject json = JSONObject::load(input, 0, &jsonErr); + + GSSCreateSecContextCommand cmd = GSSCreateSecContextCommand( + &json, + (void *)&mock_init_sec + ); + + + const char *from_json = json["target_name"].string(); + const char *from_cmd = cmd.getTargetDisplayName(); + + CPPUNIT_ASSERT_MESSAGE( + "The object does not have a target name.", + ( strcmp(from_json, from_cmd) == 0 ) + ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The context_handle values differ.", + json["context_handle"].integer(), + (json_int_t)cmd.getContextHandle() + ); + + CPPUNIT_ASSERT_MESSAGE( + "The mech_type values differ.", + ( strcmp(json["mech_type"].string(), cmd.getMechType()) == 0 ) + ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The req_flags differ.", + (int)json["req_flags"].integer(), + (int)cmd.getReqFlags() + ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The req_flags differ.", + (int)json["time_req"].integer(), + (int)cmd.getTimeReq() + ); + + +} + +void +GSSCreateSecContextTest::testEmptyCall() +{ + GSSCreateSecContextCommand cmd ((void *)&mock_init_sec); + + /* Set expectations on what the GSS function will be called with */ + cmd.time_req = rand() % 1024; + cmd.req_flags = rand() % 1024; + cmd.target_name = NULL; + cmd.context_handle = GSS_C_NO_CONTEXT; + + CPPUNIT_ASSERT_MESSAGE( + "The mech_type values differ.", + ( strcmp("{ 1 2 840 113554 1 2 1 4 }", cmd.getMechType()) == 0 ) + ); + + + + /* Set expectations on what the GSS function will produce */ + InitSecContextMock::retVal = rand() % 1024; + InitSecContextMock::minor_status = rand() % 1024; + InitSecContextMock::context_handle = GSS_C_NO_CONTEXT; + InitSecContextMock::actual_mech_type = NULL; + InitSecContextMock::output_token = (gss_buffer_t)malloc(sizeof(gss_buffer_desc)); + InitSecContextMock::output_token->value = (void *)"http@project-moonshot.org/PROJECT-MOONSHOT.ORG\0"; + InitSecContextMock::output_token->length = strlen((char *)InitSecContextMock::output_token->value); + InitSecContextMock::ret_flags = rand() % 1024; + InitSecContextMock::time_req = rand() % 1024; + + cmd.execute(); + + /* Check that init_sec_context's inputs are sent correctly */ + CPPUNIT_ASSERT_MESSAGE( + "The GSS function was not invoked!", + InitSecContextMock::visited + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The time_req field was not used in the call to init_sec_context", + cmd.time_req, + InitSecContextMock::time_req + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The req_flags field was not used in the call to init_sec_context", + cmd.req_flags, + InitSecContextMock::req_flags + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The mech_type field was not used in the call to init_sec_context", + cmd.mech_type, + InitSecContextMock::mech_type + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "The target_name field was not used in the call to init_sec_context", + cmd.target_name, + InitSecContextMock::target_name + ); + + + /* Check that init_sec_context's outputs are captured correctly */ + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Return value was not copied back to the command.", + InitSecContextMock::retVal, + cmd.retVal + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Status was not copied back to the command.", + InitSecContextMock::minor_status, + cmd.minor_status + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "context_handle was not copied back to the command.", + InitSecContextMock::context_handle, + cmd.context_handle + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "actual_mech_type was not copied back to the command.", + InitSecContextMock::actual_mech_type, + cmd.actual_mech_type + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "output_token was not copied back to the command.", + InitSecContextMock::output_token->value, + cmd.output_token->value + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "ret_flags was not copied back to the command.", + InitSecContextMock::ret_flags, + cmd.ret_flags + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "time_rec was not copied back to the command.", + InitSecContextMock::time_rec, + cmd.time_rec + ); +} + diff --git a/json_gssapi/test/GSSCreateSecContextTest.h b/json_gssapi/test/GSSCreateSecContextTest.h new file mode 100644 index 0000000..e2cb910 --- /dev/null +++ b/json_gssapi/test/GSSCreateSecContextTest.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + +#ifndef GSSCREATESECCONTEXTTEST_H +#define GSSCREATESECCONTEXTTEST_H + +// #include +#include + +#include +#include "GSSCreateSecContextCommand.h" + +#include + +class GSSCreateSecContextTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( GSSCreateSecContextTest ); + CPPUNIT_TEST( testConstructor ); + CPPUNIT_TEST( testConstructorWithJSONObject ); + CPPUNIT_TEST( testEmptyCall ); + CPPUNIT_TEST_SUITE_END(); + + + +public: + void setUp(); + void tearDown(); + + + void testConstructor(); + void testConstructorWithJSONObject(); + void testEmptyCall(); + +private: + GSSCreateSecContextCommand command; +}; + +#endif // GSSCREATESECCONTEXTTEST_H diff --git a/json_gssapi/test/InitSecContextMock.cpp b/json_gssapi/test/InitSecContextMock.cpp new file mode 100644 index 0000000..b18df38 --- /dev/null +++ b/json_gssapi/test/InitSecContextMock.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + +#include "InitSecContextMock.h" +#include + +OM_uint32 InitSecContextMock::retVal = 0; +OM_uint32 InitSecContextMock::minor_status = 0; +OM_uint32 InitSecContextMock::req_flags = 0; +OM_uint32 InitSecContextMock::time_req = 0; +OM_uint32 InitSecContextMock::ret_flags = 0; +OM_uint32 InitSecContextMock::time_rec = 0; + +bool InitSecContextMock::visited = false; +bool InitSecContextMock::invalidContextHandle = false; + +gss_cred_id_t InitSecContextMock::claimant_cred_handle = NULL; +gss_ctx_id_t InitSecContextMock::context_handle = NULL; +gss_name_t InitSecContextMock::target_name = NULL; +gss_OID InitSecContextMock::mech_type = NULL; +gss_channel_bindings_t InitSecContextMock::input_chan_bindings = NULL; +gss_buffer_t InitSecContextMock::input_token = NULL; +gss_OID InitSecContextMock::actual_mech_type = NULL; +gss_buffer_t InitSecContextMock::output_token = NULL; + +void InitSecContextMock::reset() +{ + retVal = 0; + minor_status = 0; + nullify((void **)&claimant_cred_handle); + nullify((void **)&context_handle); + nullify((void **)&target_name); + nullify((void **)&mech_type); + req_flags = 0; + time_req = 0; + nullify((void **)&input_chan_bindings); + nullify((void **)&input_token); + nullify((void **)&actual_mech_type); + nullify((void **)&output_token); + ret_flags = 0; + time_rec = 0; + visited = false; + invalidContextHandle = false; + +} diff --git a/json_gssapi/test/InitSecContextMock.h b/json_gssapi/test/InitSecContextMock.h new file mode 100644 index 0000000..171bb41 --- /dev/null +++ b/json_gssapi/test/InitSecContextMock.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 + * + * For license details, see the LICENSE file in the root of this project. + * + */ + +#ifndef INITSECCONTEXTMOCK_H +#define INITSECCONTEXTMOCK_H + +#include +#include +#include + +class InitSecContextMock +{ +public: + static OM_uint32 retVal; + static OM_uint32 minor_status; + static gss_cred_id_t claimant_cred_handle; + static gss_ctx_id_t context_handle; + static gss_name_t target_name; + static gss_OID mech_type; + static OM_uint32 req_flags; + static OM_uint32 time_req; + static gss_channel_bindings_t input_chan_bindings; + static gss_buffer_t input_token; + static gss_OID actual_mech_type; + static gss_buffer_t output_token; + static OM_uint32 ret_flags; + static OM_uint32 time_rec; + + static bool visited; + static bool invalidContextHandle; + + static void nullify(void **ptr) + { + if (!ptr) + { + std::cout << std::endl << "Nullify called with a void ** that is NULL at the top level" << std::endl; + return; + } + if (*ptr) + { + free(*ptr); + *ptr = NULL; + } + } + + static void reset(); +}; + +#endif // INITSECCONTEXTMOCK_H diff --git a/json_gssapi/test/JSONParseTest.cpp b/json_gssapi/test/JSONParseTest.cpp new file mode 100644 index 0000000..ef51470 --- /dev/null +++ b/json_gssapi/test/JSONParseTest.cpp @@ -0,0 +1,23 @@ +#include "JSONParseTest.h" + +// Registers the fixture into the 'registry' +CPPUNIT_TEST_SUITE_REGISTRATION( JSONParseTest ); + + +void +JSONParseTest::setUp() +{ +} + + +void +JSONParseTest::tearDown() +{ +} + + +void +JSONParseTest::testConstructor() +{ +// CPPUNIT_FAIL( "not implemented, go away" ); +} \ No newline at end of file diff --git a/json_gssapi/test/JSONParseTest.h b/json_gssapi/test/JSONParseTest.h new file mode 100644 index 0000000..846b263 --- /dev/null +++ b/json_gssapi/test/JSONParseTest.h @@ -0,0 +1,19 @@ +#ifndef JSONPARSETEST_H +#define JSONPARSETEST_H + +#include + +class JSONParseTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( JSONParseTest ); + CPPUNIT_TEST( testConstructor ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testConstructor(); +}; + +#endif // JSONPARSETEST_H \ No newline at end of file diff --git a/json_gssapi/test/test_run.cpp b/json_gssapi/test/test_run.cpp new file mode 100644 index 0000000..084feeb --- /dev/null +++ b/json_gssapi/test/test_run.cpp @@ -0,0 +1,24 @@ +// ? #include "stdafx.h" +#include +#include +#include + + +int main(int argc, char* argv[]) +{ + // Get the top level suite from the registry + CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); + + // Adds the test to the list of test to run + CppUnit::TextUi::TestRunner runner; + runner.addTest( suite ); + + // Change the default outputter to a compiler error format outputter + runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), + std::cerr ) ); + // Run the tests. + bool wasSucessful = runner.run(); + + // Return error code 1 if the one of test failed. + return wasSucessful ? 0 : 1; +}