From f7ca2a597d3248cb70c0de4258c8a7bcd1df1302 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Petr=20P=C3=ADsa=C5=99?= Date: Sun, 22 Jul 2012 11:11:38 +0200 Subject: [PATCH] test: Introduce isds_change_password This implements some services on ISDS side. Here we have independend ISDS server implementation :D --- test/simline/Makefile.am | 6 +- test/simline/basic_authentication.c | 7 +- test/simline/hotp_authentication.c | 7 +- ...sic_authentication.c => isds_change_password.c} | 62 ++++---- test/simline/server.c | 22 +-- test/simline/server.h | 8 ++ test/simline/service.c | 156 ++++++++++++++++++--- test/simline/service.h | 4 +- test/simline/totp_authentication.c | 7 +- 9 files changed, 208 insertions(+), 71 deletions(-) copy test/simline/{basic_authentication.c => isds_change_password.c} (68%) diff --git a/test/simline/Makefile.am b/test/simline/Makefile.am index b9f18e1..71d6877 100644 --- a/test/simline/Makefile.am +++ b/test/simline/Makefile.am @@ -16,19 +16,21 @@ export HOME=@top_builddir@ TESTS = if BUILD_CURL -TESTS += basic_authentication hotp_authentication totp_authentication +TESTS += basic_authentication hotp_authentication totp_authentication \ + isds_change_password endif noinst_PROGRAMS = $(TESTS) common = ../test.c ../test.h ../test-tools.h http.c http.h server.c server.h \ - service.c service.h + service.c service.h services.h # Access public API only basic_authentication_SOURCES = basic_authentication.c $(common) hotp_authentication_SOURCES = hotp_authentication.c $(common) totp_authentication_SOURCES = totp_authentication.c $(common) +isds_change_password_SOURCES = isds_change_password.c $(common) # Tests that need .gnupg #guess_raw_type.log load_raw.log: prepare_environment.log diff --git a/test/simline/basic_authentication.c b/test/simline/basic_authentication.c index 5b10bbe..818a379 100644 --- a/test/simline/basic_authentication.c +++ b/test/simline/basic_authentication.c @@ -57,10 +57,15 @@ int main(int argc, char **argv) { } { + const struct service_configuration services[] = { + { SERVICE_DS_Dz_DummyOperation, NULL }, + { SERVICE_END, NULL } + }; const struct arguments_basic_authentication server_arguments = { .username = username, .password = password, - .isds_deviations = 1 + .isds_deviations = 1, + .services = services }; error = start_server(&server_process, &server_address, server_basic_authentication, &server_arguments); diff --git a/test/simline/hotp_authentication.c b/test/simline/hotp_authentication.c index 2f4c060..2eba07d 100644 --- a/test/simline/hotp_authentication.c +++ b/test/simline/hotp_authentication.c @@ -90,12 +90,17 @@ int main(int argc, char **argv) { } { + const struct service_configuration services[] = { + { SERVICE_DS_Dz_DummyOperation, NULL }, + { SERVICE_END, NULL } + }; const struct arguments_otp_authentication server_arguments = { .method = AUTH_OTP_HMAC, .username = username, .password = password, .otp = otp_code, - .isds_deviations = 1 + .isds_deviations = 1, + .services = services }; error = start_server(&server_process, &server_address, server_otp_authentication, &server_arguments); diff --git a/test/simline/basic_authentication.c b/test/simline/isds_change_password.c similarity index 68% copy from test/simline/basic_authentication.c copy to test/simline/isds_change_password.c index 5b10bbe..dad7513 100644 --- a/test/simline/basic_authentication.c +++ b/test/simline/isds_change_password.c @@ -30,7 +30,20 @@ static int test_login(const isds_error error, struct isds_ctx *context, isds_strerror(error), isds_strerror(err), isds_long_message(context)); - isds_logout(context); + PASS_TEST; +} + +static int test_isds_change_password(const isds_error error, + struct isds_ctx *context, const char *old_password, + const char *new_password, struct isds_otp *otp) { + isds_error err; + + err = isds_change_password(context, old_password, new_password, otp); + if (error != err) + FAIL_TEST("Wrong return code: expected=%s, returned=%s (%s)", + isds_strerror(error), isds_strerror(err), + isds_long_message(context)); + PASS_TEST; } @@ -41,7 +54,7 @@ int main(int argc, char **argv) { struct isds_ctx *context = NULL; char *url = NULL; - INIT_TEST("basic authentication"); + INIT_TEST("isds_change_password"); if (unsetenv("http_proxy")) { ABORT_UNIT("Could not remove http_proxy variable from environment\n"); @@ -57,10 +70,16 @@ int main(int argc, char **argv) { } { + const struct service_configuration services[] = { + { SERVICE_DS_Dz_DummyOperation, NULL }, + { SERVICE_DS_DsManage_ChangeISDSPassword, password }, + { SERVICE_END, NULL } + }; const struct arguments_basic_authentication server_arguments = { .username = username, .password = password, - .isds_deviations = 1 + .isds_deviations = 1, + .services = services }; error = start_server(&server_process, &server_address, server_basic_authentication, &server_arguments); @@ -78,11 +97,12 @@ int main(int argc, char **argv) { } free(server_address); - TEST("invalid credentials", test_login, IE_NOT_LOGGED_IN, context, - url, "7777777", "nbuusr1", NULL, NULL); - - TEST("valid login", test_login, IE_SUCCESS, context, + TEST("login", test_login, IE_SUCCESS, context, url, username, password, NULL, NULL); + TEST("bad old password", test_isds_change_password, IE_INVAL, context, + "bad old password", "h2k$aana", NULL); + TEST("valid request", test_isds_change_password, IE_SUCCESS, context, + password, "h2k$aana", NULL); if (-1 == stop_server(server_process)) { ABORT_UNIT(server_error); @@ -92,34 +112,8 @@ int main(int argc, char **argv) { url = NULL; } - { - error = start_server(&server_process, &server_address, - server_out_of_order, NULL); - if (error == -1) { - isds_ctx_free(&context); - isds_cleanup(); - ABORT_UNIT(server_error); - } - if (-1 == test_asprintf(&url, "http://%s/", server_address)) { - free(server_address); - stop_server(server_process); - isds_ctx_free(&context); - isds_cleanup(); - ABORT_UNIT("Could not format ISDS URL"); - } - free(server_address); - - TEST("log into out-of-order server", test_login, IE_SOAP, context, - url, username, password, NULL, NULL); - - if (-1 == stop_server(server_process)) { - ABORT_UNIT(server_error); - } - - free(url); - url = NULL; - } + isds_logout(context); isds_ctx_free(&context); isds_cleanup(); SUM_TEST(); diff --git a/test/simline/server.c b/test/simline/server.c index d5ef04b..1685489 100644 --- a/test/simline/server.c +++ b/test/simline/server.c @@ -114,8 +114,9 @@ char *socket2address(int socket) { /* Process ISDS WS ping */ -static void do_ws(int client_socket, const struct http_request *request, - const char *required_base_path) { +static void do_ws(int client_socket, + const struct service_configuration *ws_configuration, + const struct http_request *request, const char *required_base_path) { char *end_point = request->uri; /* Pointer to string in request */ if (request->method != HTTP_METHOD_POST) { @@ -134,7 +135,8 @@ static void do_ws(int client_socket, const struct http_request *request, end_point += required_base_path_length; } - soap(client_socket, request->body, request->body_length, end_point); + soap(client_socket, ws_configuration, request->body, request->body_length, + end_point); } @@ -176,7 +178,8 @@ void server_basic_authentication(int server_socket, switch(http_authenticate_basic(request, arguments->username, arguments->password)) { case HTTP_ERROR_SUCCESS: - do_ws(client_socket, request, ws_base_path_basic); + do_ws(client_socket, arguments->services, request, + ws_base_path_basic); break; case HTTP_ERROR_CLIENT: if (arguments->isds_deviations) @@ -193,7 +196,8 @@ void server_basic_authentication(int server_socket, http_send_response_401_basic(client_socket); } } else { - do_ws(client_socket, request, ws_base_path_basic); + do_ws(client_socket, arguments->services, request, + ws_base_path_basic); } } else { /* HTTP method unsupported per ISDS specification */ @@ -415,7 +419,8 @@ static void do_as_logout(int client_socket, const struct http_request *request, /* Process ISDS WS ping authorized by cookie */ -static void do_ws_with_cookie(int client_socket, const struct http_request *request, +static void do_ws_with_cookie(int client_socket, + const struct http_request *request, const struct arguments_otp_authentication *arguments, const char *valid_base_path) { const char *received_cookie = @@ -423,7 +428,7 @@ static void do_ws_with_cookie(int client_socket, const struct http_request *requ if (authorization_cookie_value != NULL && received_cookie != NULL && !strcmp(authorization_cookie_value, received_cookie)) - do_ws(client_socket, request, valid_base_path); + do_ws(client_socket, arguments->services, request, valid_base_path); else http_send_response_403(client_socket); } @@ -484,7 +489,8 @@ void server_otp_authentication(int server_socket, } } else { if (!strcmp(request->uri, ws_path)) { - do_ws(client_socket, request, ws_base_path_otp); + do_ws(client_socket, arguments->services, request, + ws_base_path_otp); } else { http_send_response_400(client_socket, "Unknown path for TOTP authenticating service"); diff --git a/test/simline/server.h b/test/simline/server.h index 698c2cf..b1de86d 100644 --- a/test/simline/server.h +++ b/test/simline/server.h @@ -1,6 +1,8 @@ #ifndef __ISDS_SERVER_H #define __ISDS_SERVER_H +#include "services.h" + extern const char *server_error; /* Save pointer to static error message if not yet set */ @@ -26,6 +28,9 @@ struct arguments_basic_authentication { if not conflicts with ISDS specification. Otherwise server mimics real ISDS implementation as much as possible. */ + const struct service_configuration *services; /* Array of enabled + services. Last name must + be SERVICE_END. */ }; /* Do the server protocol. @@ -53,6 +58,9 @@ struct arguments_otp_authentication { if not conflicts with ISDS specification. Otherwise server mimics real ISDS implementation as much as possible. */ + const struct service_configuration *services; /* Array of enabled + services. Last name must + be SERVICE_END. */ }; /* Do the server protocol with OTP authentication. diff --git a/test/simline/service.c b/test/simline/service.c index 6efbcb6..f8c9051 100644 --- a/test/simline/service.c +++ b/test/simline/service.c @@ -1,5 +1,7 @@ +#define _XOPEN_SOURCE 500 /* For strdup(3) */ #include "../test-tools.h" #include "http.h" +#include "services.h" #include #include #include @@ -30,19 +32,46 @@ typedef enum { struct service { + service_id id; const char *end_point; const xmlChar *name; - int (*function) (int, xmlDocPtr, xmlXPathContextPtr, xmlNodePtr, - xmlDocPtr, xmlNodePtr); + http_error (*function) (int, xmlDocPtr, xmlXPathContextPtr, xmlNodePtr, + xmlDocPtr, xmlNodePtr, const void *arguments); }; +/* Following EXTRACT_* macros expect @xpath_ctx, @message, and leave label */ +#define EXTRACT_STRING(element, string) { \ + xmlXPathObjectPtr result = NULL; \ + result = xmlXPathEvalExpression(BAD_CAST element "/text()", xpath_ctx); \ + if (NULL == result) { \ + error = HTTP_ERROR_SERVER; \ + goto leave; \ + } \ + if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) { \ + if (result->nodesetval->nodeNr > 1) { \ + xmlXPathFreeObject(result); \ + test_asprintf(&message, "Multiple %s element", element); \ + error = HTTP_ERROR_CLIENT; \ + goto leave; \ + } \ + (string) = (char *) \ + xmlXPathCastNodeSetToString(result->nodesetval); \ + if (!(string)) { \ + xmlXPathFreeObject(result); \ + error = HTTP_ERROR_SERVER; \ + goto leave; \ + } \ + } \ + xmlXPathFreeObject(result); \ +} + /* Following INSERT_* macros expect @error and leave label */ #define INSERT_STRING_WITH_NS(parent, ns, element, string) \ { \ xmlNodePtr node = xmlNewTextChild(parent, ns, BAD_CAST (element), \ (xmlChar *) (string)); \ if (NULL == node) { \ - error = -1; \ + error = HTTP_ERROR_SERVER; \ goto leave; \ } \ } @@ -54,7 +83,7 @@ struct service { { \ (child) = xmlNewChild((parent), NULL, BAD_CAST (element), NULL); \ if (NULL == (child)) { \ - error = -1; \ + error = HTTP_ERROR_SERVER; \ goto leave; \ } \ } @@ -66,34 +95,102 @@ struct service { * @message is UTF-8 encoded message * @db_ref_number is optinal reference number propagated if not @dm * @return 0 on success, otherwise non-0. */ -static int insert_isds_status(xmlNodePtr parent, _Bool dm, - const xmlChar * code, const xmlChar *message, +static http_error insert_isds_status(xmlNodePtr parent, _Bool dm, + const xmlChar *code, const xmlChar *message, const xmlChar *db_ref_number) { - int error = 0; + http_error error = HTTP_ERROR_SUCCESS; xmlNodePtr status; + + if (NULL == code || NULL == message) { + error = HTTP_ERROR_SERVER; + goto leave; + } + INSERT_ELEMENT(status, parent, (dm) ? "dmStatus" : "dbStatus"); - INSERT_STRING(status, (dm) ? "dmStatusCode" : "dbStatusCode", "0000"); - INSERT_STRING(status, (dm) ? "dmStatusMessage" : "dbStatusMessage", "Success"); + INSERT_STRING(status, (dm) ? "dmStatusCode" : "dbStatusCode", code); + INSERT_STRING(status, (dm) ? "dmStatusMessage" : "dbStatusMessage", message); if (!dm && NULL != db_ref_number) { INSERT_STRING(status, "dbStatusRefNumber", db_ref_number); } + leave: return error; } -/* Parse and respond to DummyOperation */ -static int service_DummyOperation(int socket, const xmlDocPtr soap_request, +/* Implement DummyOperation */ +static http_error service_DummyOperation(int socket, const xmlDocPtr soap_request, xmlXPathContextPtr xpath_ctx, xmlNodePtr isds_request, - xmlDocPtr soap_response, xmlNodePtr isds_response) { + xmlDocPtr soap_response, xmlNodePtr isds_response, + const void *arguments) { return insert_isds_status(isds_response, 1, BAD_CAST "0000", BAD_CAST "Success", NULL); } +/* Implement ChangeISDSPassword. + * @arguments is current password as const char * */ +static http_error service_ChangeISDSPassword(int socket, + const xmlDocPtr soap_request, xmlXPathContextPtr xpath_ctx, + const xmlNodePtr isds_request, + xmlDocPtr soap_response, xmlNodePtr isds_response, + const void *arguments) { + http_error error = HTTP_ERROR_SUCCESS; + char *message = NULL; + const char *current_password = (const char *)arguments; + char *old_password = NULL, *new_password = NULL; + + if (NULL == current_password) { + error = HTTP_ERROR_SERVER; + goto leave; + } + + /* Parse request */ + EXTRACT_STRING("isds:dbOldPassword", old_password); + if (NULL == old_password) { + message = strdup("Empty isds:dbOldPassword"); + error = HTTP_ERROR_CLIENT; + goto leave; + } + EXTRACT_STRING("isds:dbNewPassword", new_password); + if (NULL == new_password) { + message = strdup("Empty isds:dbOldPassword"); + error = HTTP_ERROR_CLIENT; + goto leave; + } + + /* Check defined cases */ + if (strcmp(current_password, old_password)) { + error = insert_isds_status(isds_response, 0, BAD_CAST "1090", + BAD_CAST "Bad current password", NULL); + if (error == HTTP_ERROR_SUCCESS) error = HTTP_ERROR_CLIENT; + } else { + error = insert_isds_status(isds_response, 0, BAD_CAST "0000", + BAD_CAST "Success", NULL); + } + goto end; +leave: + if (HTTP_ERROR_CLIENT == error) { + http_error next_error = insert_isds_status(isds_response, 0, + BAD_CAST "9999", BAD_CAST message, NULL); + if (HTTP_ERROR_SUCCESS != next_error) error = next_error; + } +end: + free(old_password); + free(new_password); + free(message); + return error; +} + + /* List of implemented services */ static struct service services[] = { - { "DS/dz", BAD_CAST "DummyOperation", service_DummyOperation }, + { SERVICE_DS_Dz_DummyOperation, + "DS/dz", BAD_CAST "DummyOperation", + service_DummyOperation }, + { SERVICE_DS_DsManage_ChangeISDSPassword, + "DS/DsManage", BAD_CAST "ChangeISDSPassword", + service_ChangeISDSPassword }, }; @@ -139,8 +236,8 @@ static int register_namespaces(xmlXPathContextPtr xpath_ctx, /* Parse soap request, pass it to service endpoint and respond to it. * It sends final HTTP response. */ -void soap(int socket, const void *request, size_t request_length, - const char *end_point) { +void soap(int socket, const struct service_configuration *configuration, + const void *request, size_t request_length, const char *end_point) { xmlDocPtr request_doc = NULL; xmlXPathContextPtr xpath_ctx = NULL; xmlXPathObjectPtr request_soap_body = NULL; @@ -155,6 +252,11 @@ void soap(int socket, const void *request, size_t request_length, xmlSaveCtxtPtr save_ctx = NULL; + if (NULL == configuration) { + http_send_response_500(socket, "Second argument of soap() is NULL"); + return; + } + if (NULL == request || request_length == 0) { http_send_response_400(socket, "Client sent empty body"); return; @@ -277,13 +379,23 @@ void soap(int socket, const void *request, size_t request_length, for (int i = 0; i < sizeof(services)/sizeof(services[0]); i++) { if (!strcmp(services[i].end_point, end_point) && !xmlStrcmp(services[i].name, isds_request->name)) { - service_handled = 1; - if (!services[i].function(socket, request_doc, xpath_ctx, isds_request, - response_doc, isds_response)) { - service_passed = 1; - } else { - http_send_response_500(socket, - "Internal server error while processing ISDS request"); + /* Check if the configuration is enabled and find configuration */ + for (const struct service_configuration *service = configuration; + service->name != SERVICE_END; service++) { + if (service->name == services[i].id) { + service_handled = 1; + xpath_ctx->node = isds_request; + if (HTTP_ERROR_SERVER != services[i].function(socket, + request_doc, xpath_ctx, isds_request, + response_doc, isds_response, + service->arguments)) { + service_passed = 1; + } else { + http_send_response_500(socket, + "Internal server error while processing " + "ISDS request"); + } + } } break; } diff --git a/test/simline/service.h b/test/simline/service.h index 92a2c42..f312eb2 100644 --- a/test/simline/service.h +++ b/test/simline/service.h @@ -5,7 +5,7 @@ /* Parse soap request, pass it to service endpoint and respond to it. * It sends final HTTP response. */ -void soap(int socket, const void *request, size_t request_length, - const char *end_point); +void soap(int socket, const struct service_configuration *configuration, + const void *request, size_t request_length, const char *end_point); #endif diff --git a/test/simline/totp_authentication.c b/test/simline/totp_authentication.c index 829be42..562ac78 100644 --- a/test/simline/totp_authentication.c +++ b/test/simline/totp_authentication.c @@ -91,12 +91,17 @@ int main(int argc, char **argv) { } { + const struct service_configuration services[] = { + { SERVICE_DS_Dz_DummyOperation, NULL }, + { SERVICE_END, NULL } + }; const struct arguments_otp_authentication server_arguments = { .method = AUTH_OTP_TIME, .username = username, .password = password, .otp = (char *) otp_code, - .isds_deviations = 1 + .isds_deviations = 1, + .services = services }; error = start_server(&server_process, &server_address, server_otp_authentication, &server_arguments); -- 2.11.4.GIT