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 f3ce866e..5d98bb9e 100644 --- a/library/ziti.c +++ b/library/ziti.c @@ -24,6 +24,7 @@ limitations under the License. #include "zt_internal.h" #include #include +#include #if _WIN32 @@ -332,7 +333,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); @@ -361,8 +362,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"); } @@ -390,8 +390,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); } } @@ -506,6 +505,9 @@ 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; + bool login = ztx->session == NULL; if (ztx->session) { @@ -704,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); } @@ -753,6 +761,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; @@ -769,38 +812,10 @@ 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); @@ -856,7 +871,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, @@ -884,7 +899,7 @@ static void version_cb(ziti_version *v, ziti_error *err, void *ctx) { } } -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; } @@ -944,4 +959,4 @@ void ziti_on_channel_event(ziti_channel_t *ch, ziti_router_status status, ziti_c }; ziti_send_event(ztx, &ev); -} \ No newline at end of file +} 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