From c868dc31b04857d1c4a0b2b51a7b9f8e54edad23 Mon Sep 17 00:00:00 2001 From: Andrew Martinez Date: Wed, 27 Jan 2021 16:23:10 -0500 Subject: [PATCH 1/2] inital mfa --- inc_internal/auth_queries.h | 45 +++++ inc_internal/internal_model.h | 13 +- inc_internal/posture.h | 1 - inc_internal/ziti_ctrl.h | 18 ++ inc_internal/zt_internal.h | 3 + includes/ziti/error_defs.h | 8 +- includes/ziti/ziti.h | 180 +++++++++++++++++- includes/ziti/ziti_model.h | 18 ++ library/CMakeLists.txt | 1 + library/auth_queries.c | 335 ++++++++++++++++++++++++++++++++++ library/internal_model.c | 8 + library/posture.c | 2 +- library/ziti.c | 132 +++++++------- library/ziti_ctrl.c | 99 +++++++++- 14 files changed, 788 insertions(+), 75 deletions(-) create mode 100644 inc_internal/auth_queries.h create mode 100644 library/auth_queries.c diff --git a/inc_internal/auth_queries.h b/inc_internal/auth_queries.h new file mode 100644 index 00000000..8edd8172 --- /dev/null +++ b/inc_internal/auth_queries.h @@ -0,0 +1,45 @@ +/* +Copyright (c) 2020 Netfoundry, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef ZITI_SDK_AUTH_QUERIES_H +#define ZITI_SDK_AUTH_QUERIES_H + +#include +#include "zt_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "zt_internal.h" +#include + +struct auth_queries { + bool outstanding_auth_queries; + bool awaiting_mfa_cb; +}; + +extern void ziti_auth_query_init(struct ziti_ctx *ztx); +extern void ziti_auth_query_free(struct auth_queries* aq); + +void ziti_auth_query_process(ziti_context ztx, void(*cb)(ziti_context ztx)); + +#ifdef __cplusplus +} +#endif + + +#endif //ZITI_SDK_AUTH_QUERIES_H diff --git a/inc_internal/internal_model.h b/inc_internal/internal_model.h index ce8a45ca..f607f9b4 100644 --- a/inc_internal/internal_model.h +++ b/inc_internal/internal_model.h @@ -43,7 +43,8 @@ XX(token, string, none, token, __VA_ARGS__) \ XX(expires, timestamp, ptr, expiresAt, __VA_ARGS__) \ XX(updated, timestamp, ptr, updatedAt, __VA_ARGS__) \ XX(identity, ziti_identity, ptr, identity, __VA_ARGS__) \ -XX(posture_query_set, ziti_posture_query_set, array, postureQueries, __VA_ARGS__) +XX(posture_query_set, ziti_posture_query_set, array, postureQueries, __VA_ARGS__) \ +XX(auth_queries, ziti_auth_query_mfa, array, authQueries, __VA_ARGS__) #define ZITI_ERROR_MODEL(XX, ...) \ XX(err, int, none, , __VA_ARGS__) \ @@ -115,6 +116,12 @@ XX(signers, string, array, signerFingerprints, __VA_ARGS__) #define ZITI_SERVICE_UPDATE(XX, ...) \ XX(last_change, string, none, lastChangeAt, __VA_ARGS__) +#define ZITI_MFA_CODE_REQ(XX, ...) \ +XX(code, string, none, code, __VA_ARGS__) + +#define ZITI_MFA_RECOVERY_CODES_MODEL(XX, ...) \ +XX(recovery_codes, string, array, recoveryCodes, __VA_ARGS__) + #ifdef __cplusplus extern "C" { #endif @@ -152,6 +159,10 @@ DECLARE_MODEL(ziti_pr_domain_req, ZITI_PR_DOMAIN_REQ) DECLARE_MODEL(ziti_service_update, ZITI_SERVICE_UPDATE) +DECLARE_MODEL(ziti_mfa_code_req, ZITI_MFA_CODE_REQ) + +DECLARE_MODEL(ziti_mfa_recovery_codes, ZITI_MFA_RECOVERY_CODES_MODEL) + #ifdef __cplusplus } #endif diff --git a/inc_internal/posture.h b/inc_internal/posture.h index cd9533ff..8174b84b 100644 --- a/inc_internal/posture.h +++ b/inc_internal/posture.h @@ -34,7 +34,6 @@ struct posture_checks { // map model_map *current_responses; - // mapcode = code; + + size_t len; + char* body = ziti_mfa_code_req_to_json(code_req, 0, &len); + + FREE(code_req) + + return body; +} + +extern void ziti_auth_query_init(ziti_context ztx) { + if (ztx->auth_queries == NULL) { + NEWP(aq, struct auth_queries); + aq->outstanding_auth_queries = false; + aq->awaiting_mfa_cb = false; + ztx->auth_queries = aq; + } +} + +extern void ziti_auth_query_free(struct auth_queries *aq) { + FREE(aq) +} + +void ziti_auth_query_mfa_cb(ziti_context ztx, void *v_mfa_ctx, char *code, ziti_ar_mfa_status_cb status_cb, void* status_ctx) { + ztx->auth_queries->awaiting_mfa_cb = false; + ziti_mfa_auth_ctx *mfa_ctx = v_mfa_ctx; + mfa_ctx->status_cb = status_cb; + mfa_ctx->status_ctx = status_ctx; + + if (code == NULL) { + ZITI_LOG(ERROR, "expected mfa auth query to return non empty string, trying again"); + ziti_auth_query_mfa_process(mfa_ctx); + } + + char *body = ziti_mfa_code_body(code); + + ziti_ctrl_login_mfa(&ztx->controller, body, strlen(body), ziti_auth_query_mfa_auth_internal_cb, mfa_ctx); +} + +void ziti_auth_query_mfa_process(ziti_mfa_auth_ctx *mfa_ctx) { + if (!mfa_ctx->ztx->auth_queries->awaiting_mfa_cb) { + mfa_ctx->ztx->auth_queries->awaiting_mfa_cb = true; + mfa_ctx->ztx->opts->aq_mfa_cb(mfa_ctx->ztx, mfa_ctx, mfa_ctx->query, ziti_auth_query_mfa_cb); + } +} + +void ziti_auth_query_process(ziti_context ztx, void(*cb)(ziti_context)) { + ziti_auth_query_mfa **aq; + + ziti_auth_query_mfa *ziti_mfa = NULL; + if (ztx->session->auth_queries != NULL) { + for (aq = ztx->session->auth_queries; *aq != NULL; aq++) { + ziti_auth_query_mfa *current_aq = *aq; + + if (strncmp(current_aq->type_id, AUTH_QUERY_TYPE_MFA, strlen(AUTH_QUERY_TYPE_MFA)) == 0 && + strncmp(current_aq->provider, MFA_PROVIDER_ZITI, strlen(MFA_PROVIDER_ZITI)) == 0) { + if (ziti_mfa == NULL) { + ziti_mfa = current_aq; + } else { + ZITI_LOG(ERROR, "multiple auth queries for [type: %s] [provider: %s], cannot continue", current_aq->type_id, current_aq->provider); + cb(ztx); + return; + } + } else { + ZITI_LOG(ERROR, "could not process authentication query [type: %s] [provider: %s], unknown type or provider", current_aq->type_id, current_aq->provider); + cb(ztx); //fail with unsupported auth query + return; + } + } + } + + if (ziti_mfa == NULL) { + ztx->auth_queries->outstanding_auth_queries = false; + ztx->auth_queries->awaiting_mfa_cb = false; + cb(ztx); //succeed no mfa to handle + return; + } + + ztx->auth_queries->outstanding_auth_queries = true; + + if (ztx->opts->aq_mfa_cb == NULL) { + ZITI_LOG(ERROR, "could not process authentication query [type: %s] [provider: %s], no callback handler specified", ziti_mfa->type_id, ziti_mfa->provider); + cb(ztx); //fail with unsupported auth query + return; + } + + ziti_mfa_auth_ctx *mfa_ctx = calloc(1, sizeof(ziti_mfa_auth_ctx)); + mfa_ctx->ztx = ztx; + mfa_ctx->cb = cb; + mfa_ctx->query = ziti_mfa; + + ziti_auth_query_mfa_process(mfa_ctx); +} + +void ziti_mfa_enroll_get_internal_cb(ziti_mfa_enrollment *mfa_enrollment, ziti_error *err, void *ctx); + +void ziti_mfa_enroll_post_internal_cb(void *empty, ziti_error *err, void *ctx) { + ziti_mfa_enroll_cb_ctx *mfa_enroll_cb_ctx = ctx; + + if (err == NULL) { + ziti_ctrl_get_mfa(&mfa_enroll_cb_ctx->ztx->controller, ziti_mfa_enroll_get_internal_cb, ctx); + } else { + ZITI_LOG(ERROR, "error during create MFA call: %d - %s - %s", err->http_code, err->code, err->message); + mfa_enroll_cb_ctx->cb(mfa_enroll_cb_ctx->ztx, err->err, NULL, mfa_enroll_cb_ctx->cb_ctx); + FREE(err) + FREE(ctx) + } +} + +void ziti_mfa_enroll_get_internal_cb(ziti_mfa_enrollment *mfa_enrollment, ziti_error *err, void *ctx) { + ziti_mfa_enroll_cb_ctx *mfa_enroll_cb_ctx = ctx; + + if (err != NULL) { + if (err->http_code != 404) { + ZITI_LOG(ERROR, "error during enroll MFA call: %d - %s - %s", err->http_code, err->code, err->message); + mfa_enroll_cb_ctx->cb(mfa_enroll_cb_ctx->ztx, err->err, NULL, mfa_enroll_cb_ctx->cb_ctx); + FREE(err) + FREE(ctx) + return; + } + FREE(err) + } + + if (mfa_enrollment == NULL) { + ziti_ctrl_post_mfa(&mfa_enroll_cb_ctx->ztx->controller, ziti_mfa_enroll_post_internal_cb, ctx); + } else { + mfa_enroll_cb_ctx->cb(mfa_enroll_cb_ctx->ztx, ZITI_OK, mfa_enrollment, mfa_enroll_cb_ctx->cb_ctx); + FREE(ctx) + free_ziti_mfa_enrollment(mfa_enrollment); + } +} + +void ziti_mfa_enroll(ziti_context ztx, ziti_mfa_enroll_cb enroll_cb, void *ctx) { + NEWP(mfa_enroll_cb_ctx, ziti_mfa_enroll_cb_ctx); + + mfa_enroll_cb_ctx->ztx = ztx; + mfa_enroll_cb_ctx->cb = enroll_cb; + mfa_enroll_cb_ctx->cb_ctx = ctx; + + ziti_ctrl_get_mfa(&ztx->controller, ziti_mfa_enroll_get_internal_cb, mfa_enroll_cb_ctx); +} + +void ziti_mfa_remove_internal_cb(void *empty, ziti_error *err, void *ctx) { + ziti_mfa_cb_ctx *mfa_cb_ctx = ctx; + + if (err != NULL) { + ZITI_LOG(ERROR, "error during remove MFA call: %d - %s - %s", err->http_code, err->code, err->message); + mfa_cb_ctx->cb(mfa_cb_ctx->ztx, err->err, mfa_cb_ctx->cb_ctx); + FREE(err) + } else { + mfa_cb_ctx->cb(mfa_cb_ctx->ztx, ZITI_OK, mfa_cb_ctx->cb_ctx); + } + + FREE(mfa_cb_ctx->code) + FREE(ctx) +} + +void ziti_mfa_remove(ziti_context ztx, char *code, ziti_mfa_cb remove_cb, void *ctx) { + NEWP(mfa_cb_ctx, ziti_mfa_cb_ctx); + mfa_cb_ctx->ztx = ztx; + mfa_cb_ctx->cb = remove_cb; + mfa_cb_ctx->cb_ctx = ctx; + mfa_cb_ctx->code = strdup(code); + + ziti_ctrl_delete_mfa(&ztx->controller, mfa_cb_ctx->code, ziti_mfa_remove_internal_cb, mfa_cb_ctx); +} + +void ziti_mfa_verify_internal_cb(void *empty, ziti_error *err, void *ctx) { + ziti_mfa_cb_ctx *mfa_cb_ctx = ctx; + + if (err != NULL) { + ZITI_LOG(ERROR, "error during verify MFA call: %d - %s - %s", err->http_code, err->code, err->message); + mfa_cb_ctx->cb(mfa_cb_ctx->ztx, err->err, mfa_cb_ctx->cb_ctx); + FREE(err) + } else { + mfa_cb_ctx->cb(mfa_cb_ctx->ztx, ZITI_OK, mfa_cb_ctx->cb_ctx); + } + + FREE(ctx) +} + +void ziti_mfa_verify(ziti_context ztx, char *code, ziti_mfa_cb verify_cb, void *ctx) { + NEWP(mfa_cb_ctx, ziti_mfa_cb_ctx); + mfa_cb_ctx->ztx = ztx; + mfa_cb_ctx->cb = verify_cb; + mfa_cb_ctx->cb_ctx = ctx; + + char *body = ziti_mfa_code_body(code); + + ziti_ctrl_post_mfa_verify(&ztx->controller, body, strlen(body), ziti_mfa_verify_internal_cb, mfa_cb_ctx); +} + +void ziti_auth_query_mfa_auth_internal_cb(void *empty, ziti_error *err, void *ctx) { + ziti_mfa_auth_ctx *mfa_ctx = ctx; + ziti_context ztx = mfa_ctx->ztx; + if (err != NULL) { + ZITI_LOG(ERROR, "error during MFA auth call: %d - %s - %s", err->http_code, err->code, err->message); + + + + if(mfa_ctx->status_cb != NULL) { + mfa_ctx->status_cb(ztx, mfa_ctx, err->err, mfa_ctx->status_ctx); + } else { + ZITI_LOG(WARN, "no mfa status callback provided, mfa failed, status was: %d", err->err); + } + FREE(ctx) + FREE(err) + return; + } else { + mfa_ctx->ztx->auth_queries->outstanding_auth_queries = false; + + if(mfa_ctx->status_cb != NULL) { + mfa_ctx->status_cb(ztx, mfa_ctx, ZITI_OK, mfa_ctx->status_ctx); + } else { + ZITI_LOG(WARN, "no mfa status callback provided, mfa was a success, status was: %d", err->err); + } + + mfa_ctx->cb(ztx); + FREE(ctx) + } +} + +void ziti_mfa_get_recovery_codes_internal_cb(ziti_mfa_recovery_codes *rc, ziti_error *err, void *ctx) { + ziti_mfa_recovery_codes_cb_ctx *mfa_recovery_codes_cb_ctx = ctx; + + if (err != NULL) { + ZITI_LOG(ERROR, "error during get recovery codes MFA call: %d - %s - %s", err->http_code, err->code, err->message); + mfa_recovery_codes_cb_ctx->cb(mfa_recovery_codes_cb_ctx->ztx, err->err, NULL, mfa_recovery_codes_cb_ctx->cb_ctx); + FREE(err) + } else { + mfa_recovery_codes_cb_ctx->cb(mfa_recovery_codes_cb_ctx->ztx, ZITI_OK, rc->recovery_codes, mfa_recovery_codes_cb_ctx->cb_ctx); + free_ziti_mfa_recovery_codes(rc); + } + + FREE(mfa_recovery_codes_cb_ctx->code) + FREE(ctx) +} + +void ziti_mfa_get_recovery_codes(ziti_context ztx, char *code, ziti_mfa_recovery_codes_cb get_cb, void *ctx) { + NEWP(mfa_rc_cb_ctx, ziti_mfa_recovery_codes_cb_ctx); + mfa_rc_cb_ctx->ztx = ztx; + mfa_rc_cb_ctx->cb = get_cb; + mfa_rc_cb_ctx->cb_ctx = ctx; + mfa_rc_cb_ctx->code = strdup(code); + + ziti_ctrl_get_mfa_recovery_codes(&ztx->controller, mfa_rc_cb_ctx->code, ziti_mfa_get_recovery_codes_internal_cb, mfa_rc_cb_ctx); +} + +void ziti_mfa_post_recovery_codes_internal_cb(void *empty, ziti_error *err, void *ctx) { + ziti_mfa_recovery_codes_cb_ctx *mfa_recovery_codes_cb_ctx = ctx; + + if (err != NULL) { + ZITI_LOG(ERROR, "error during create recovery codes MFA call: %d - %s - %s", err->http_code, err->code, err->message); + mfa_recovery_codes_cb_ctx->cb(mfa_recovery_codes_cb_ctx->ztx, err->err, NULL, mfa_recovery_codes_cb_ctx->cb_ctx); + FREE(err) + } else { + ziti_mfa_get_recovery_codes(mfa_recovery_codes_cb_ctx->ztx, mfa_recovery_codes_cb_ctx->code, mfa_recovery_codes_cb_ctx->cb, mfa_recovery_codes_cb_ctx->cb_ctx); + } + + FREE(ctx) +} + +void ziti_mfa_new_recovery_codes(ziti_context ztx, char *code, ziti_mfa_recovery_codes_cb new_cb, void *ctx) { + NEWP(mfa_rc_cb_ctx, ziti_mfa_recovery_codes_cb_ctx); + mfa_rc_cb_ctx->ztx = ztx; + mfa_rc_cb_ctx->cb = new_cb; + mfa_rc_cb_ctx->cb_ctx = ctx; + mfa_rc_cb_ctx->code = code; + + char *body = ziti_mfa_code_body(code); + + ziti_ctrl_post_mfa_recovery_codes(&ztx->controller, body, strlen(body), ziti_mfa_post_recovery_codes_internal_cb, mfa_rc_cb_ctx); +} diff --git a/library/internal_model.c b/library/internal_model.c index ac16ad65..e4106025 100644 --- a/library/internal_model.c +++ b/library/internal_model.c @@ -51,6 +51,8 @@ IMPL_MODEL(ziti_version, ZITI_VERSION_MODEL) IMPL_MODEL(ziti_identity, ZITI_IDENTITY_MODEL) +IMPL_MODEL(ziti_auth_query_mfa, ZITI_AUTH_QUERY_MFA_MODEL) + IMPL_MODEL(ziti_session, ZITI_SESSION_MODEL) IMPL_MODEL(ziti_error, ZITI_ERROR_MODEL) @@ -79,6 +81,12 @@ IMPL_MODEL(ziti_pr_domain_req, ZITI_PR_DOMAIN_REQ) IMPL_MODEL(ziti_service_update, ZITI_SERVICE_UPDATE) +IMPL_MODEL(ziti_mfa_recovery_codes, ZITI_MFA_RECOVERY_CODES_MODEL) + +IMPL_MODEL(ziti_mfa_enrollment, ZITI_MFA_ENROLLMENT_MODEL) + +IMPL_MODEL(ziti_mfa_code_req, ZITI_MFA_CODE_REQ) + const char *ziti_service_get_raw_config(ziti_service *service, const char *cfg_type) { return (const char *) model_map_get(&service->config, cfg_type); } diff --git a/library/posture.c b/library/posture.c index 0eaef2bc..b3f3ad9d 100644 --- a/library/posture.c +++ b/library/posture.c @@ -525,4 +525,4 @@ static void ziti_pr_handle_process(ziti_context ztx, char *id, char *path, bool free(null_term_signers); ziti_collect_pr(ztx, path, obj, obj_len); -} \ No newline at end of file +} diff --git a/library/ziti.c b/library/ziti.c index 50d419c4..3f8998c6 100644 --- a/library/ziti.c +++ b/library/ziti.c @@ -24,11 +24,10 @@ limitations under the License. #include "zt_internal.h" #include #include +#include #if _WIN32 - #include - #endif #ifndef MAXPATHLEN @@ -41,7 +40,7 @@ limitations under the License. #endif #endif -#define ZTX_LOG(lvl,fmt, ...) ZITI_LOG(lvl, "ztx[%d] " fmt, ztx->id, ##__VA_ARGS__) +#define ZTX_LOG(lvl, fmt, ...) ZITI_LOG(lvl, "ztx[%d] " fmt, ztx->id, ##__VA_ARGS__) static const char *ALL_CONFIG_TYPES[] = { "all", @@ -223,8 +222,8 @@ static void ziti_init_async(uv_async_t *ar) { ziti_fmt_time(time_str, sizeof(time_str), &start_time); ZTX_LOG(INFO, "Ziti C SDK version %s @%s(%s) starting at (%s.%03d)", - ziti_get_build_version(false), ziti_git_commit(), ziti_git_branch(), - time_str, start_time.tv_usec / 1000); + ziti_get_build_version(false), ziti_git_commit(), ziti_git_branch(), + time_str, start_time.tv_usec / 1000); ZTX_LOG(INFO, "Loading from config[%s] controller[%s]", ztx->opts->config, ztx->opts->controller); init_req->login = true; @@ -298,7 +297,7 @@ int ziti_set_timeout(ziti_context ztx, int timeout) { static void on_logout(void *msg, ziti_error *err, void *arg) { ziti_context ztx = arg; ZTX_LOG(DEBUG, "identity[%s] logout %s", - ztx->session->identity->name, err ? "failed" : "success"); + ztx->session->identity->name, err ? "failed" : "success"); free_ziti_session(ztx->session); free(ztx->session); @@ -330,7 +329,7 @@ int ziti_ctx_free(ziti_context *ctxp) { if ((*ctxp)->tlsCtx != NULL) { (*ctxp)->tlsCtx->api->free_ctx((*ctxp)->tlsCtx); } - + ziti_auth_query_free((*ctxp)->auth_queries); ziti_posture_checks_free((*ctxp)->posture_checks); model_map_clear(&(*ctxp)->services, free_ziti_service); model_map_clear(&(*ctxp)->sessions, free_ziti_net_session); @@ -359,8 +358,7 @@ void ziti_dump(ziti_context ztx, int (*printer)(void *arg, const char *fmt, ...) if (ztx->session) { printer(ctx, "Session Info: id[%s] name[%s] api_session[%s]\n", ztx->session->identity->id, ztx->session->identity->name, ztx->session->id); - } - else { + } else { printer(ctx, "No Session found\n"); } @@ -388,8 +386,7 @@ void ziti_dump(ziti_context ztx, int (*printer)(void *arg, const char *fmt, ...) printer(ctx, "ch[%d](%s) ", ch->id, url); if (ziti_channel_is_connected(ch)) { printer(ctx, "connected [latency=%ld]\n", (long) ch->latency); - } - else { + } else { printer(ctx, "Disconnected\n", (long) ch->latency); } } @@ -503,6 +500,7 @@ int ziti_listen_with_options(ziti_connection serv_conn, const char *service, zit static void session_refresh(uv_timer_t *t) { ziti_context ztx = t->data; + struct ziti_init_req *req = calloc(1, sizeof(struct ziti_init_req)); req->ztx = ztx; @@ -523,8 +521,7 @@ static void session_refresh(uv_timer_t *t) { if (login) { ZTX_LOG(DEBUG, "requesting new API session"); ziti_ctrl_login(&ztx->controller, ztx->opts->config_types, session_cb, req); - } - else { + } else { ZTX_LOG(DEBUG, "refreshing API session"); ziti_ctrl_current_api_session(&ztx->controller, session_cb, req); } @@ -562,12 +559,11 @@ static void update_services(ziti_service_array services, ziti_error *error, void if (error) { ZTX_LOG(ERROR, "failed to get service updates err[%s/%s] from ctrl[%s]", error->code, error->message, - ztx->opts->controller); + ztx->opts->controller); if (error->err == ZITI_NOT_AUTHORIZED) { ZTX_LOG(WARN, "API session is no longer valid. Trying to re-auth"); ziti_re_auth(ztx); - } - else { + } else { update_ctrl_status(ztx, ZITI_CONTROLLER_UNAVAILABLE, error->message); } return; @@ -653,8 +649,7 @@ static void update_services(ziti_service_array services, ziti_error *error, void if (addIdx > 0 || remIdx > 0 || chIdx > 0) { ZTX_LOG(DEBUG, "sending service event %d added, %d removed, %d changed", addIdx, remIdx, chIdx); ziti_send_event(ztx, &ev); - } - else { + } else { ZTX_LOG(VERBOSE, "no services added, changed, or removed"); } @@ -681,14 +676,13 @@ static void check_service_update(ziti_service_update *update, ziti_error *err, v ZTX_LOG(INFO, "Controller does not support /current-api-session/service-updates API"); ztx->no_service_updates_api = true; } - } - else if (ztx->last_update == NULL || strcmp(ztx->last_update, update->last_change) != 0) { + } else if (ztx->last_update == NULL || strcmp(ztx->last_update, update->last_change) != 0) { ZTX_LOG(VERBOSE, "ztx last_update = %s", update->last_change); FREE(ztx->last_update); ztx->last_update = update->last_change; } else { ZTX_LOG(VERBOSE, "not updating: last_update is same previous (%s == %s)", update->last_change, - ztx->last_update); + ztx->last_update); free_ziti_service_update(update); need_update = false; @@ -703,10 +697,15 @@ static void check_service_update(ziti_service_update *update, ziti_error *err, v static void services_refresh(uv_timer_t *t) { ziti_context ztx = t->data; + + if (ztx->auth_queries->outstanding_auth_queries) { + ZITI_LOG(DEBUG, "service refresh stopped, outstanding auth queries"); + return; + } + if (ztx->no_service_updates_api) { ziti_ctrl_get_services(&ztx->controller, update_services, ztx); - } - else { + } else { ziti_ctrl_get_services_update(&ztx->controller, check_service_update, ztx); } } @@ -717,8 +716,7 @@ static void edge_routers_cb(ziti_edge_router_array ers, ziti_error *err, void *c if (err) { if (err->http_code == 404) { ztx->no_current_edge_routers = true; - } - else { + } else { ZTX_LOG(ERROR, "failed to get current edge routers: %s/%s", err->code, err->message); } return; @@ -752,6 +750,41 @@ static void edge_routers_cb(ziti_edge_router_array ers, ziti_error *err, void *c free(ers); } +static void session_post_auth_query_cb(ziti_context ztx){ + ziti_session *session = ztx->session; + + uv_timeval64_t now; + uv_gettimeofday(&now); + + int time_diff = (int) (now.tv_sec - session->updated->tv_sec); + if (abs(time_diff) > 10) { + ZITI_LOG(ERROR, "local clock is %d seconds %s UTC (as reported by controller)", abs(time_diff), + time_diff > 0 ? "ahead" : "behind"); + } + + if (session->expires) { + // adjust expiration to local time if needed + session->expires->tv_sec += time_diff; + ZTX_LOG(DEBUG, "ziti API session expires in %ld seconds", (long) (session->expires->tv_sec - now.tv_sec)); + long delay = (session->expires->tv_sec - now.tv_sec) - 10; + uv_timer_start(&ztx->session_timer, session_refresh, delay * 1000, 0); + } + + if (ztx->opts->refresh_interval > 0 && !uv_is_active((const uv_handle_t *) &ztx->refresh_timer)) { + ZTX_LOG(DEBUG, "refresh_interval set to %ld seconds", ztx->opts->refresh_interval); + services_refresh(&ztx->refresh_timer); + } else if (ztx->opts->refresh_interval == 0) { + ZTX_LOG(DEBUG, "refresh_interval not specified"); + uv_timer_stop(&ztx->refresh_timer); + } + + ziti_posture_init(ztx, 20); + + if (!ztx->no_current_edge_routers) { + ziti_ctrl_current_edge_routers(&ztx->controller, edge_routers_cb, ztx); + } +} + static void session_cb(ziti_session *session, ziti_error *err, void *ctx) { struct ziti_init_req *init_req = ctx; ziti_context ztx = init_req->ztx; @@ -768,41 +801,13 @@ static void session_cb(ziti_session *session, ziti_error *err, void *ctx) { free_ziti_session(old_session); FREE(old_session); - uv_timeval64_t now; - uv_gettimeofday(&now); - - int time_diff = (int) (now.tv_sec - session->updated->tv_sec); - if (abs(time_diff) > 10) { - ZITI_LOG(ERROR, "local clock is %d seconds %s UTC (as reported by controller)", abs(time_diff), - time_diff > 0 ? "ahead" : "behind"); - } - - if (session->expires) { - // adjust expiration to local time if needed - session->expires->tv_sec += time_diff; - ZTX_LOG(DEBUG, "ziti API session expires in %ld seconds", (long) (session->expires->tv_sec - now.tv_sec)); - long delay = (session->expires->tv_sec - now.tv_sec) - 10; - uv_timer_start(&ztx->session_timer, session_refresh, delay * 1000, 0); - } - - if (ztx->opts->refresh_interval > 0 && !uv_is_active((const uv_handle_t *) &ztx->refresh_timer)) { - ZTX_LOG(DEBUG, "refresh_interval set to %ld seconds", ztx->opts->refresh_interval); - services_refresh(&ztx->refresh_timer); - } - else if (ztx->opts->refresh_interval == 0) { - ZTX_LOG(DEBUG, "refresh_interval not specified"); - uv_timer_stop(&ztx->refresh_timer); - } - - ziti_posture_init(ztx, 20); - - if (!ztx->no_current_edge_routers) { - ziti_ctrl_current_edge_routers(&ztx->controller, edge_routers_cb, ztx); - } + ziti_auth_query_init(ztx); + //check for additional authentication requirements, pickup in session_post_auth_query_cb + ziti_auth_query_process(ztx,session_post_auth_query_cb); } else if (err) { ZTX_LOG(WARN, "failed to get session from ctrl[%s] %s[%d] %s", - ztx->opts->controller, err->code, errCode, err->message); + ztx->opts->controller, err->code, errCode, err->message); if (errCode == ZITI_NOT_AUTHORIZED) { if (ztx->session || !init_req->login) { @@ -815,7 +820,7 @@ static void session_cb(ziti_session *session, ziti_error *err, void *ctx) { // cannot login or re-auth -- identity no longer valid // notify service removal, and state ZTX_LOG(ERROR, "identity[%s] cannot authenticate with ctrl[%s]", ztx->opts->config, - ztx->opts->controller); + ztx->opts->controller); ziti_event_t service_event = { .type = ZitiServiceEvent, .event.service = { @@ -855,7 +860,7 @@ static void session_cb(ziti_session *session, ziti_error *err, void *ctx) { FREE(init_req); } -static void update_ctrl_status(ziti_context ztx, int errCode, const char* errMsg) { +static void update_ctrl_status(ziti_context ztx, int errCode, const char *errMsg) { if (ztx->ctrl_status != errCode) { ziti_event_t ev = { .type = ZitiContextEvent, @@ -872,18 +877,18 @@ static void version_cb(ziti_version *v, ziti_error *err, void *ctx) { ziti_context ztx = ctx; if (err != NULL) { ZTX_LOG(ERROR, "failed to get controller version from %s %s(%s)", - ztx->opts->controller, err->code, err->message); + ztx->opts->controller, err->code, err->message); free_ziti_error(err); FREE(err); } else { ZTX_LOG(INFO, "connected to controller %s version %s(%s %s)", - ztx->opts->controller, v->version, v->revision, v->build_date); + ztx->opts->controller, v->version, v->revision, v->build_date); free_ziti_version(v); FREE(v); } } -void ziti_invalidate_session(ziti_context ztx, ziti_net_session *session, const char *service_id, const char* type) { +void ziti_invalidate_session(ziti_context ztx, ziti_net_session *session, const char *service_id, const char *type) { if (session == NULL) { return; } @@ -894,8 +899,7 @@ void ziti_invalidate_session(ziti_context ztx, ziti_net_session *session, const // already removed or different one // passed reference is no longer valid session = NULL; - } - else if (s == session) { + } else if (s == session) { model_map_remove(&ztx->sessions, session->service_id); } } diff --git a/library/ziti_ctrl.c b/library/ziti_ctrl.c index 6ed97bc2..ca323e9f 100644 --- a/library/ziti_ctrl.c +++ b/library/ziti_ctrl.c @@ -21,6 +21,7 @@ limitations under the License. #include #include + #define DEFAULT_PAGE_SIZE 25 #define ZITI_CTRL_KEEPALIVE 0 #define ZITI_CTRL_TIMEOUT 15000 @@ -68,7 +69,11 @@ XX(INVALID_AUTHENTICATION, ZITI_NOT_AUTHORIZED) \ XX(REQUIRES_CERT_AUTH, ZITI_NOT_AUTHORIZED) \ XX(UNAUTHORIZED, ZITI_NOT_AUTHORIZED) \ XX(INVALID_POSTURE, ZITI_INVALID_POSTURE) \ -XX(INVALID_AUTH, ZITI_NOT_AUTHORIZED) +XX(INVALID_AUTH, ZITI_NOT_AUTHORIZED) \ +XX(MFA_INVALID_TOKEN, ZITI_MFA_INVALID_TOKEN) \ +XX(MFA_EXISTS, ZITI_MFA_EXISTS) \ +XX(MFA_NOT_ENROLLED, ZITI_MFA_NOT_ENROLLED) + #define CODE_MATCH(c, err) if (strcmp(code,#c) == 0) return err; @@ -602,3 +607,95 @@ static void ctrl_paging_req(struct ctrl_resp *resp) { um_http_req(&resp->ctrl->client, "GET", path, ctrl_resp_cb, resp); } + + +void ziti_ctrl_login_mfa(ziti_controller *ctrl, char* body, size_t body_len ,void(*cb)(void *, ziti_error *, void *), void *ctx) { + + struct ctrl_resp *resp = calloc(1, sizeof(struct ctrl_resp)); + resp->body_parse_func = NULL; + resp->resp_cb = (void (*)(void *, ziti_error *, void *)) cb; + resp->ctx = ctx; + resp->ctrl = ctrl; + resp->ctrl_cb = ctrl_default_cb; + + um_http_req_t *req = um_http_req(&ctrl->client, "POST", "/authenticate/mfa", ctrl_resp_cb, resp); + um_http_req_header(req, "Content-Type", "application/json"); + um_http_req_data(req, body, body_len, free_body_cb); +} + +void ziti_ctrl_post_mfa(ziti_controller *ctrl,void(*cb)(void *, ziti_error *, void *), void *ctx){ + struct ctrl_resp *resp = calloc(1, sizeof(struct ctrl_resp)); + resp->body_parse_func = NULL; + resp->resp_cb = (void (*)(void *, ziti_error *, void *)) cb; + resp->ctx = ctx; + resp->ctrl = ctrl; + resp->ctrl_cb = ctrl_default_cb; + + um_http_req_t *req = um_http_req(&ctrl->client, "POST", "/current-identity/mfa", ctrl_resp_cb, resp); + um_http_req_header(req, "Content-Type", "application/json"); + um_http_req_data(req, NULL, 0, free_body_cb); +} + +void ziti_ctrl_get_mfa(ziti_controller *ctrl, void(*cb)(ziti_mfa_enrollment *, ziti_error *, void *), void *ctx) { + struct ctrl_resp *resp = calloc(1, sizeof(struct ctrl_resp)); + resp->body_parse_func = (int (*)(void *, const char *, size_t)) parse_ziti_mfa_enrollment_ptr; + resp->resp_cb = (void (*)(void *, ziti_error *, void *)) cb; + resp->ctx = ctx; + resp->ctrl = ctrl; + resp->ctrl_cb = ctrl_default_cb; + + um_http_req_t *req = um_http_req(&ctrl->client, "GET", "/current-identity/mfa", ctrl_resp_cb, resp); + um_http_req_header(req, "Content-Type", "application/json"); +} + +void ziti_ctrl_delete_mfa(ziti_controller *ctrl, char* code, void(*cb)(void *, ziti_error *, void *), void *ctx) { + struct ctrl_resp *resp = calloc(1, sizeof(struct ctrl_resp)); + resp->body_parse_func = NULL; + resp->resp_cb = (void (*)(void *, ziti_error *, void *)) cb; + resp->ctx = ctx; + resp->ctrl = ctrl; + resp->ctrl_cb = ctrl_default_cb; + + um_http_req_t *req = um_http_req(&ctrl->client, "DELETE", "/current-identity/mfa", ctrl_resp_cb, resp); + um_http_req_header(req, "Content-Type", "application/json"); + um_http_req_header(req, "mfa-validation-code", code); +} + +void ziti_ctrl_post_mfa_verify(ziti_controller *ctrl, char* body, size_t body_len, void(*cb)(void *, ziti_error *, void *), void *ctx){ + struct ctrl_resp *resp = calloc(1, sizeof(struct ctrl_resp)); + resp->body_parse_func = NULL; + resp->resp_cb = (void (*)(void *, ziti_error *, void *)) cb; + resp->ctx = ctx; + resp->ctrl = ctrl; + resp->ctrl_cb = ctrl_default_cb; + + um_http_req_t *req = um_http_req(&ctrl->client, "POST", "/current-identity/mfa/verify", ctrl_resp_cb, resp); + um_http_req_header(req, "Content-Type", "application/json"); + um_http_req_data(req, body, body_len, free_body_cb); +} + +void ziti_ctrl_get_mfa_recovery_codes(ziti_controller *ctrl, char* code, void(*cb)(ziti_mfa_recovery_codes *, ziti_error *, void *), void *ctx){ + struct ctrl_resp *resp = calloc(1, sizeof(struct ctrl_resp)); + resp->body_parse_func = (int (*)(void *, const char *, size_t)) parse_ziti_mfa_recovery_codes_ptr; + resp->resp_cb = (void (*)(void *, ziti_error *, void *)) cb; + resp->ctx = ctx; + resp->ctrl = ctrl; + resp->ctrl_cb = ctrl_default_cb; + + um_http_req_t *req = um_http_req(&ctrl->client, "GET", "/current-identity/mfa/recovery-codes", ctrl_resp_cb, resp); + um_http_req_header(req, "mfa-validation-code", code); + um_http_req_header(req, "Content-Type", "application/json"); +} + +void ziti_ctrl_post_mfa_recovery_codes(ziti_controller *ctrl, char* body, size_t body_len, void(*cb)(void *,ziti_error *, void *), void *ctx) { + struct ctrl_resp *resp = calloc(1, sizeof(struct ctrl_resp)); + resp->body_parse_func = NULL; + resp->resp_cb = (void (*)(void *, ziti_error *, void *)) cb; + resp->ctx = ctx; + resp->ctrl = ctrl; + resp->ctrl_cb = ctrl_default_cb; + + um_http_req_t *req = um_http_req(&ctrl->client, "POST", "/current-identity/mfa/recovery-codes", ctrl_resp_cb, resp); + um_http_req_header(req, "Content-Type", "application/json"); + um_http_req_data(req, body, body_len, free_body_cb); +} \ No newline at end of file From c28b9a73ce84f3407638ca3266c7f5f98165ac7c Mon Sep 17 00:00:00 2001 From: dovholuknf <46322585+dovholuknf@users.noreply.github.com> Date: Wed, 24 Mar 2021 08:14:49 -0400 Subject: [PATCH 2/2] fix mismerged block --- library/ziti.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/ziti.c b/library/ziti.c index e574570b..5d98bb9e 100644 --- a/library/ziti.c +++ b/library/ziti.c @@ -706,6 +706,12 @@ static void check_service_update(ziti_service_update *update, ziti_error *err, v static void services_refresh(uv_timer_t *t) { ziti_context ztx = t->data; + + if (ztx->auth_queries->outstanding_auth_queries) { + ZITI_LOG(DEBUG, "service refresh stopped, outstanding auth queries"); + return; + } + if (ztx->no_service_updates_api) { ziti_ctrl_get_services(&ztx->controller, update_services, ztx); }