-
Notifications
You must be signed in to change notification settings - Fork 278
Refresh OAuth2 tokens automatically #8355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
4ee9ca3
b6749f3
a508466
08d5704
3f2a630
b67c661
c3d2e36
3d43309
6234661
3fdefcd
2663e91
b9e9cda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,6 +45,7 @@ const char *oidc_cmd_str[] = { | |
| "get-user-groups", | ||
| "get-group", | ||
| "get-group-members", | ||
| "refresh-access-token", | ||
| NULL | ||
| }; | ||
|
|
||
|
|
@@ -147,6 +148,63 @@ static errno_t read_device_code_from_stdin(struct devicecode_ctx *dc_ctx, | |
| return EOK; | ||
| } | ||
|
|
||
| static errno_t read_refresh_token_from_stdin(struct devicecode_ctx *dc_ctx, | ||
| char **token_out, | ||
| char **secret_out) | ||
| { | ||
| char *str; | ||
| errno_t ret; | ||
| char *sep; | ||
| char *end; | ||
| char *tmp; | ||
|
|
||
| ret = read_from_stdin(dc_ctx, &str); | ||
| if (ret != EOK) { | ||
| DEBUG(SSSDBG_OP_FAILURE, "read_from_stdin failed.\n"); | ||
| return ret; | ||
| } | ||
|
|
||
| if (secret_out != NULL) { | ||
| /* expect the client secret in the first line */ | ||
| sep = strchr(str, '\n'); | ||
| if (sep == NULL) { | ||
| DEBUG(SSSDBG_CRIT_FAILURE, | ||
| "Format error, expecting client secret and refresh token.\n"); | ||
| ret = EINVAL; | ||
| goto fail; | ||
| } | ||
| *sep = '\0'; | ||
| *secret_out = str; | ||
| sep++; | ||
| } else { | ||
| sep = str; | ||
| } | ||
|
|
||
| /* NULL-terminate the token */ | ||
| end = strchr(sep, '\n'); | ||
| if (end != NULL) { | ||
| *end = '\0'; | ||
| } | ||
|
|
||
| tmp = talloc_strdup(dc_ctx, sep); | ||
| if (tmp == NULL) { | ||
| DEBUG(SSSDBG_CRIT_FAILURE, | ||
| "Failed to copy refresh token.\n"); | ||
| ret = ENOMEM; | ||
| goto fail; | ||
| } | ||
| talloc_set_destructor((void *) tmp, sss_erase_talloc_mem_securely); | ||
| *token_out = tmp; | ||
|
|
||
| DEBUG(SSSDBG_TRACE_ALL, "Refresh token read from stdin: [%s].\n", tmp); | ||
|
|
||
| return EOK; | ||
|
|
||
| fail: | ||
| talloc_free(str); | ||
| return ret; | ||
| } | ||
|
|
||
| static errno_t read_client_secret_from_stdin(TALLOC_CTX *mem_ctx, | ||
| char **out) | ||
| { | ||
|
|
@@ -205,9 +263,9 @@ static errno_t set_endpoints(struct devicecode_ctx *dc_ctx, | |
| } | ||
|
|
||
| if (scope != NULL && *scope != '\0') { | ||
| dc_ctx->scope = url_encode_string(dc_ctx, scope); | ||
| dc_ctx->scope = talloc_strdup(dc_ctx, scope); | ||
| if (dc_ctx->scope == NULL) { | ||
| DEBUG(SSSDBG_CRIT_FAILURE, "Failed to encode and copy scopes.\n"); | ||
| DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy scopes.\n"); | ||
| ret = ENOMEM; | ||
| goto done; | ||
| } | ||
|
|
@@ -337,6 +395,8 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts) | |
| _("Lookup a group"), NULL}, | ||
| {"get-group-members", 0, POPT_ARG_VAL, &opts->oidc_cmd, GET_GROUP_MEMBERS, | ||
| _("Lookup members of a group"), NULL}, | ||
| {"refresh-access-token", 0, POPT_ARG_VAL, &opts->oidc_cmd, REFRESH_ACCESS_TOKEN, | ||
| _("Refresh access token"), NULL}, | ||
| {"issuer-url", 0, POPT_ARG_STRING, &opts->issuer_url, 0, | ||
| _("URL of Issuer IdP"), NULL}, | ||
| {"device-auth-endpoint", 0, POPT_ARG_STRING, &opts->device_auth_endpoint, 0, | ||
|
|
@@ -400,7 +460,8 @@ static int parse_cli(int argc, const char *argv[], struct cli_opts *opts) | |
| } | ||
|
|
||
| if (opts->oidc_cmd == GET_ACCESS_TOKEN | ||
| || opts->oidc_cmd == GET_DEVICE_CODE) { | ||
| || opts->oidc_cmd == GET_DEVICE_CODE | ||
| || opts->oidc_cmd == REFRESH_ACCESS_TOKEN) { | ||
| if (!( | ||
| ((opts->issuer_url != NULL) != (opts->device_auth_endpoint != NULL)) | ||
| && ((opts->issuer_url != NULL) != (opts->token_endpoint != NULL)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this require either
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, exactly as you say. This just checks for illegal combinations of options.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, even though |
||
|
|
@@ -489,6 +550,8 @@ void trace_tokens(struct devicecode_ctx *dc_ctx) | |
| DEBUG(SSSDBG_TRACE_ALL, "User Principal: [%s].\n", json_string_value(json_object_get(dc_ctx->td->access_token_payload, "upn"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "User oid: [%s].\n", json_string_value(json_object_get(dc_ctx->td->access_token_payload, "oid"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "User sub: [%s].\n", json_string_value(json_object_get(dc_ctx->td->access_token_payload, "sub"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "Issued at: [%lld].\n", (long long) json_integer_value(json_object_get(dc_ctx->td->access_token_payload, "iat"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "Expires at: [%lld].\n", (long long) json_integer_value(json_object_get(dc_ctx->td->access_token_payload, "exp"))); | ||
| } | ||
|
|
||
| if (dc_ctx->td->id_token_payload != NULL) { | ||
|
|
@@ -499,6 +562,20 @@ void trace_tokens(struct devicecode_ctx *dc_ctx) | |
| DEBUG(SSSDBG_TRACE_ALL, "User Principal: [%s].\n", json_string_value(json_object_get(dc_ctx->td->id_token_payload, "upn"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "User oid: [%s].\n", json_string_value(json_object_get(dc_ctx->td->id_token_payload, "oid"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "User sub: [%s].\n", json_string_value(json_object_get(dc_ctx->td->id_token_payload, "sub"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "Issued at: [%lld].\n", (long long) json_integer_value(json_object_get(dc_ctx->td->id_token_payload, "iat"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "Expires at: [%lld].\n", (long long) json_integer_value(json_object_get(dc_ctx->td->id_token_payload, "exp"))); | ||
| } | ||
|
|
||
| if (dc_ctx->td->refresh_token_payload != NULL) { | ||
| tmp = json_dumps(dc_ctx->td->refresh_token_payload, 0); | ||
| DEBUG(SSSDBG_TRACE_ALL, "refresh_token payload: [%s].\n", tmp); | ||
| free(tmp); | ||
|
|
||
| DEBUG(SSSDBG_TRACE_ALL, "User Principal: [%s].\n", json_string_value(json_object_get(dc_ctx->td->refresh_token_payload, "upn"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "User oid: [%s].\n", json_string_value(json_object_get(dc_ctx->td->refresh_token_payload, "oid"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "User sub: [%s].\n", json_string_value(json_object_get(dc_ctx->td->refresh_token_payload, "sub"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "Issued at: [%lld].\n", (long long) json_integer_value(json_object_get(dc_ctx->td->refresh_token_payload, "iat"))); | ||
| DEBUG(SSSDBG_TRACE_ALL, "Expires at: [%lld].\n", (long long) json_integer_value(json_object_get(dc_ctx->td->refresh_token_payload, "exp"))); | ||
| } | ||
|
|
||
| tmp = json_dumps(dc_ctx->td->userinfo, 0); | ||
|
|
@@ -547,7 +624,8 @@ int main(int argc, const char *argv[]) | |
| } | ||
| talloc_steal(main_ctx, debug_prg_name); | ||
|
|
||
| if (opts.oidc_cmd == GET_DEVICE_CODE || IS_ID_CMD(opts.oidc_cmd)) { | ||
| if (opts.oidc_cmd == GET_DEVICE_CODE | ||
| || IS_ID_CMD(opts.oidc_cmd)) { | ||
| if (opts.client_secret_stdin) { | ||
| ret = read_client_secret_from_stdin(main_ctx, &client_secret_tmp); | ||
| if (ret != EOK || client_secret_tmp == NULL) { | ||
|
|
@@ -584,7 +662,9 @@ int main(int argc, const char *argv[]) | |
| goto success; | ||
| } | ||
|
|
||
| if (opts.oidc_cmd == GET_DEVICE_CODE || opts.oidc_cmd == GET_ACCESS_TOKEN) { | ||
| if (opts.oidc_cmd == GET_DEVICE_CODE | ||
| || opts.oidc_cmd == GET_ACCESS_TOKEN | ||
| || opts.oidc_cmd == REFRESH_ACCESS_TOKEN) { | ||
| dc_ctx = get_dc_ctx(main_ctx, opts.libcurl_debug, opts.ca_db, | ||
| opts.issuer_url, | ||
| opts.device_auth_endpoint, opts.token_endpoint, | ||
|
|
@@ -633,19 +713,54 @@ int main(int argc, const char *argv[]) | |
| } | ||
| } | ||
|
|
||
| ret = parse_result(dc_ctx); | ||
| if (ret != EOK) { | ||
| DEBUG(SSSDBG_OP_FAILURE, "Failed to parse device code reply.\n"); | ||
| goto done; | ||
| if (opts.oidc_cmd == GET_DEVICE_CODE || opts.oidc_cmd == GET_ACCESS_TOKEN) { | ||
| ret = parse_result(dc_ctx); | ||
| if (ret != EOK) { | ||
| DEBUG(SSSDBG_OP_FAILURE, "Failed to parse device code reply.\n"); | ||
| goto done; | ||
| } | ||
|
|
||
| trace_device_code(dc_ctx, (opts.oidc_cmd == GET_DEVICE_CODE)); | ||
|
|
||
| ret = get_token(main_ctx, dc_ctx, opts.client_id, opts.client_secret, | ||
| (opts.oidc_cmd == GET_DEVICE_CODE)); | ||
| if (ret != EOK) { | ||
| DEBUG(SSSDBG_OP_FAILURE, "Failed to get user token.\n"); | ||
| goto done; | ||
| } | ||
| } | ||
|
|
||
| trace_device_code(dc_ctx, (opts.oidc_cmd == GET_DEVICE_CODE)); | ||
| if (opts.oidc_cmd == REFRESH_ACCESS_TOKEN) { | ||
| char *token = NULL; | ||
|
|
||
| ret = get_token(main_ctx, dc_ctx, opts.client_id, opts.client_secret, | ||
| (opts.oidc_cmd == GET_DEVICE_CODE)); | ||
| if (ret != EOK) { | ||
| DEBUG(SSSDBG_OP_FAILURE, "Failed to get user token.\n"); | ||
| goto done; | ||
| ret = read_refresh_token_from_stdin(dc_ctx, &token, | ||
| opts.client_secret_stdin | ||
| ? &client_secret_tmp | ||
| : NULL); | ||
| if (ret != EOK) { | ||
| DEBUG(SSSDBG_OP_FAILURE, | ||
| "Failed to read refresh token from stdin.\n"); | ||
| goto done; | ||
| } | ||
|
|
||
| if (opts.client_secret_stdin) { | ||
| opts.client_secret = strdup(client_secret_tmp); | ||
alexey-tikhonov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| sss_erase_mem_securely(client_secret_tmp, strlen(client_secret_tmp)); | ||
| if (opts.client_secret == NULL) { | ||
| DEBUG(SSSDBG_OP_FAILURE, | ||
| "Failed to copy client secret.\n"); | ||
| ret = ENOMEM; | ||
| goto done; | ||
| } | ||
| } | ||
|
|
||
| ret = refresh_token(main_ctx, dc_ctx, opts.client_id, opts.client_secret, token); | ||
| if (ret != EOK) { | ||
| DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh user token.\n"); | ||
| goto done; | ||
| } | ||
|
|
||
| talloc_free(token); | ||
| } | ||
|
|
||
| if (opts.oidc_cmd == GET_DEVICE_CODE) { | ||
|
|
@@ -666,10 +781,20 @@ int main(int argc, const char *argv[]) | |
| fflush(stdout); | ||
| } | ||
|
|
||
| if (opts.oidc_cmd == GET_ACCESS_TOKEN) { | ||
| if (opts.oidc_cmd == GET_ACCESS_TOKEN | ||
| || opts.oidc_cmd == REFRESH_ACCESS_TOKEN) { | ||
| json_t *tmp; | ||
|
|
||
| DEBUG(SSSDBG_TRACE_ALL, "access_token: [%s].\n", | ||
| dc_ctx->td->access_token_str); | ||
| DEBUG(SSSDBG_TRACE_ALL, "id_token: [%s].\n", dc_ctx->td->id_token_str); | ||
| if (dc_ctx->td->id_token_str != NULL) { | ||
| DEBUG(SSSDBG_TRACE_ALL, "id_token: [%s].\n", | ||
| dc_ctx->td->id_token_str); | ||
| } | ||
| if (dc_ctx->td->refresh_token_str != NULL) { | ||
| DEBUG(SSSDBG_TRACE_ALL, "refresh_token: [%s].\n", | ||
| dc_ctx->td->refresh_token_str); | ||
| } | ||
|
|
||
| if (dc_ctx->jwks_uri != NULL) { | ||
| ret = decode_token(dc_ctx, true); | ||
|
|
@@ -694,6 +819,15 @@ int main(int argc, const char *argv[]) | |
| goto done; | ||
| } | ||
|
|
||
| if (dc_ctx->jwks_uri == NULL) { | ||
| /* Up to here the tokens are only decoded into JSON if | ||
| * verification keys were provided. */ | ||
| ret = decode_token(dc_ctx, false); | ||
| if (ret != EOK) { | ||
| DEBUG(SSSDBG_OP_FAILURE, "Failed to decode tokens, ignored.\n"); | ||
| } | ||
| } | ||
|
|
||
| trace_tokens(dc_ctx); | ||
|
|
||
| user_identifier = get_user_identifier(dc_ctx, dc_ctx->td->userinfo, | ||
|
|
@@ -704,15 +838,6 @@ int main(int argc, const char *argv[]) | |
| "User identifier not found in user info data, " | ||
| "checking id token.\n"); | ||
|
|
||
| if (dc_ctx->jwks_uri == NULL) { | ||
| /* Up to here the tokens are only decoded into JSON if | ||
| * verification keys were provided. */ | ||
| ret = decode_token(dc_ctx, false); | ||
| if (ret != EOK) { | ||
| DEBUG(SSSDBG_OP_FAILURE, "Failed to decode tokens, ignored.\n"); | ||
| } | ||
| } | ||
|
|
||
| if (dc_ctx->td->id_token_payload != NULL) { | ||
| user_identifier = get_user_identifier(dc_ctx, dc_ctx->td->id_token_payload, | ||
| opts.user_identifier_attr, | ||
|
|
@@ -740,12 +865,21 @@ int main(int argc, const char *argv[]) | |
| DEBUG(SSSDBG_CONF_SETTINGS, "User identifier: [%s].\n", | ||
| user_identifier); | ||
|
|
||
| fprintf(stdout,"%s", user_identifier); | ||
| tmp = token_data_to_json(dc_ctx); | ||
| if (tmp == NULL) { | ||
| DEBUG(SSSDBG_OP_FAILURE, "Failed to pack token data into JSON.\n"); | ||
| goto done; | ||
| } | ||
|
|
||
| json_dumpf(tmp, stdout, JSON_COMPACT); | ||
eisenmann-b1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| json_decref(tmp); | ||
|
|
||
| fprintf(stdout, "\n%s", user_identifier); | ||
| fflush(stdout); | ||
| } | ||
|
|
||
| success: | ||
| DEBUG(SSSDBG_IMPORTANT_INFO, "oidc_child finished successful!\n"); | ||
| DEBUG(SSSDBG_IMPORTANT_INFO, "oidc_child finished successfully!\n"); | ||
| exit_status = EXIT_SUCCESS; | ||
|
|
||
| done: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.