Skip to content

Commit

Permalink
Merge pull request #824 from openziti/refresh-oidc-on-re-auth
Browse files Browse the repository at this point in the history
refresh ext OIDC token when re-authentication is required
  • Loading branch information
ekoby authored Feb 7, 2025
2 parents 5d0181b + cf7f04a commit ef057dc
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 28 deletions.
13 changes: 8 additions & 5 deletions inc_internal/oidc.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@
extern "C" {
#endif

#define OIDC_TOKEN_OK (0)
#define OIDC_TOTP_NEEDED (1)
#define OIDC_TOTP_FAILED (2)
#define OIDC_TOKEN_FAILED (3)
enum oidc_status {
OIDC_TOKEN_OK = 0,
OIDC_TOTP_NEEDED = 1,
OIDC_TOTP_FAILED = 2,
OIDC_TOKEN_FAILED = 3,
OIDC_RESTART = 4,
};

typedef struct oidc_client_s oidc_client_t;
typedef void (*oidc_config_cb)(oidc_client_t *, int, const char *);
typedef void (*oidc_token_cb)(oidc_client_t *, int, const char *access_token);
typedef void (*oidc_token_cb)(oidc_client_t *, enum oidc_status, const char *access_token);
typedef void (*oidc_close_cb)(oidc_client_t *);
typedef void (*oidc_ext_link_cb)(oidc_client_t *, const char *link, void *ctx);

Expand Down
2 changes: 2 additions & 0 deletions inc_internal/ziti_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ void ziti_ctrl_list_controllers(ziti_controller *ctrl,

void ziti_ctrl_current_api_session(ziti_controller *ctrl, void(*cb)(ziti_api_session *, const ziti_error *, void *), void *ctx);

void ziti_ctrl_mfa_jwt(ziti_controller *ctrl, const char *token, void(*cb)(ziti_api_session *, const ziti_error *, void *), void *ctx);

void ziti_ctrl_create_api_certificate(ziti_controller *ctrl, const char *csr_pem, void(*cb)(ziti_create_api_cert_resp *, const ziti_error *, void *), void *ctx);

void ziti_ctrl_current_identity(ziti_controller *ctrl, void(*cb)(ziti_identity_data *, const ziti_error *, void *), void *ctx);
Expand Down
47 changes: 31 additions & 16 deletions library/external_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,38 @@ static void internal_link_cb(oidc_client_t *oidc, const char *url, void *ctx) {
ztx->ext_launch_ctx = NULL;
}

static void ext_token_cb(oidc_client_t *oidc, int status, const char *data) {
static void ext_token_cb(oidc_client_t *oidc, enum oidc_status status, const char *data) {
ziti_context ztx = oidc->data;
if (status == ZITI_OK) {
const char *token = data;
ZITI_LOG(DEBUG, "received access token: %.*s...", 20, token);
ztx->auth_method->set_ext_jwt(ztx->auth_method, token);
ztx->auth_method->start(ztx->auth_method, ztx_auth_state_cb, ztx);
} else {
const char *message = data;
ZITI_LOG(WARN, "failed to get external authentication token: %d/%s",
status, ziti_errorstr(status));
char err[256];
snprintf(err, sizeof(err), "failed to get external auth token: %s", message);
ztx_auth_state_cb(ztx, ZitiAuthImpossibleToAuthenticate, &(ziti_error){
.err = status,
.message = message,
});
switch (status) {
case OIDC_TOKEN_OK: {
const char *token = data;
ZITI_LOG(DEBUG, "received access token: %.*s...", 20, token);
ztx->auth_method->set_ext_jwt(ztx->auth_method, token);
ztx->auth_method->start(ztx->auth_method, ztx_auth_state_cb, ztx);
break;
}
case OIDC_RESTART: {
ziti_event_t ev = {
.type = ZitiAuthEvent,
.auth = {
.type = ziti_auth_query_types.name(ziti_auth_query_type_EXT_JWT),
.action = ziti_auth_login_external,
.detail = ztx->ext_auth->signer_cfg.name,
}
};
ziti_send_event(ztx, &ev);
break;
}
default: {
const char *message = data;
ZTX_LOG(WARN, "failed to get external authentication token: %d", status);
char err[256];
snprintf(err, sizeof(err), "failed to get external auth token: %s", message);
ztx_auth_state_cb(ztx, ZitiAuthImpossibleToAuthenticate, &(ziti_error) {
.err = status,
.message = message,
});
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion library/ha_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ static void ha_auth_free(ziti_auth_method_t *self) {
oidc_client_close(&auth->oidc, close_cb);
}

static void token_cb(oidc_client_t *oidc, int status, const char *token) {
static void token_cb(oidc_client_t *oidc, enum oidc_status status, const char *token) {
struct ha_auth_s *auth = HA_AUTH_FROM_OIDC(oidc);
char err[128];

Expand Down
3 changes: 1 addition & 2 deletions library/legacy_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,8 @@ static int legacy_auth_jwt_token(ziti_auth_method_t *self, const char *token) {
struct legacy_auth_s *auth = container_of(self, struct legacy_auth_s, api);
free(auth->jwt);
auth->jwt = strdup(token);
ziti_ctrl_set_token(auth->ctrl, token);
if (auth->session) {
ziti_ctrl_current_api_session(auth->ctrl, login_cb, auth);
ziti_ctrl_mfa_jwt(auth->ctrl, auth->jwt, login_cb, auth);
}
return 0;
}
Expand Down
9 changes: 7 additions & 2 deletions library/oidc.c
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ static void refresh_cb(oidc_req *req, int status, json_object *resp) {
uv_timer_start(clt->timer, refresh_time_cb, 5 * 1000, 0);
} else {
ZITI_LOG(WARN, "OIDC token refresh failed: %d[%s]", status, json_object_to_json_string(resp));
oidc_client_start(clt, clt->token_cb);
clt->token_cb(clt, OIDC_RESTART, NULL);
if (resp) {
json_object_put(resp);
}
Expand All @@ -947,10 +947,15 @@ static void refresh_time_cb(uv_timer_t *t) {
uv_unref((uv_handle_t *) t);
oidc_client_t *clt = t->data;
ZITI_LOG(DEBUG, "refreshing OIDC token");
struct json_object *tok = json_object_object_get(clt->tokens, "refresh_token");
if (tok == NULL) {
ZITI_LOG(DEBUG, "must restart authentication flow: no refresh_token");
clt->token_cb(clt, OIDC_RESTART, NULL);
return;
}

struct json_object *token_ep = json_object_object_get(clt->config, TOKEN_EP);
const char *token_url = json_object_get_string(token_ep);
struct json_object *tok = json_object_object_get(clt->tokens, "refresh_token");
oidc_req *refresh_req = new_oidc_req(clt, refresh_cb, clt);

tlsuv_http_set_url(&clt->http, token_url);
Expand Down
4 changes: 4 additions & 0 deletions library/ziti.c
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,10 @@ int ziti_listen_with_options(ziti_connection serv_conn, const char *service, zit
* @param ztx
*/
static void ziti_re_auth(ziti_context ztx) {
if (ztx->ext_auth) {
oidc_client_refresh(ztx->ext_auth);
}

// always get controller version to get the right auth method
ziti_ctrl_get_version(ztx_get_controller(ztx), version_pre_auth_cb, ztx);

Expand Down
16 changes: 16 additions & 0 deletions library/ziti_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,22 @@ void ziti_ctrl_current_api_session(ziti_controller *ctrl, void(*cb)(ziti_api_ses
start_request(ctrl->client, "GET", "/current-api-session", ctrl_resp_cb, resp);
}

void ziti_ctrl_mfa_jwt(ziti_controller *ctrl, const char *token, void(*cb)(ziti_api_session *, const ziti_error *, void *), void *ctx) {
if(!verify_api_session(ctrl, (void (*)(void *, const ziti_error *, void *)) cb, ctx)) return;

struct ctrl_resp *resp = MAKE_RESP(ctrl, cb, ziti_api_session_ptr_from_json, ctx);
resp->ctrl_cb = (ctrl_cb_t) ctrl_login_cb;

string_buf_t *b = new_string_buf();
string_buf_fmt(b, "Bearer %s", token);
char *header = string_buf_to_string(b, NULL);


tlsuv_http_req_t *req = start_request(ctrl->client, "GET", "/current-api-session", ctrl_resp_cb, resp);
tlsuv_http_req_header(req, "Authorization", header);
}


void ziti_ctrl_list_controllers(ziti_controller *ctrl,
void (*cb)(ziti_controller_detail_array, const ziti_error*, void *ctx), void *ctx) {
if(!verify_api_session(ctrl, (void (*)(void *, const ziti_error *, void *)) cb, ctx)) return;
Expand Down
4 changes: 2 additions & 2 deletions tests/integ/oidc-tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ TEST_CASE_METHOD(LoopTestCase, "ha-oidc", "[integ]") {

std::string token;
oidcClient.data = &token;
oidc_client_start(&oidcClient, [](oidc_client_t *clt, int status, const char *token) {
oidc_client_start(&oidcClient, [](oidc_client_t *clt, enum oidc_status status, const char *token) {
auto out = (std::string *) clt->data;
REQUIRE(status == 0);
REQUIRE(status == OIDC_TOKEN_OK);
*out = token;
});

Expand Down

0 comments on commit ef057dc

Please sign in to comment.