/* * send a code/refresh request to the token endpoint and return the parsed contents */ static apr_byte_t oidc_proto_token_endpoint_request(request_rec *r, oidc_cfg *cfg, oidc_provider_t *provider, apr_table_t *params, char **id_token, char **access_token, char **token_type, int *expires_in, char **refresh_token) { const char *response = NULL; /* see if we need to do basic auth or auth-through-post-params (both applied through the HTTP POST method though) */ const char *basic_auth = NULL; if ((provider->token_endpoint_auth == NULL) || (apr_strnatcmp(provider->token_endpoint_auth, "client_secret_basic") == 0)) { basic_auth = apr_psprintf(r->pool, "%s:%s", provider->client_id, provider->client_secret); } else { apr_table_addn(params, "client_id", provider->client_id); apr_table_addn(params, "client_secret", provider->client_secret); } /* add any configured extra static parameters to the token endpoint */ oidc_util_table_add_query_encoded_params(r->pool, params, provider->token_endpoint_params); /* send the refresh request to the token endpoint */ if (oidc_util_http_post_form(r, provider->token_endpoint_url, params, basic_auth, NULL, provider->ssl_validate_server, &response, cfg->http_timeout_long, cfg->outgoing_proxy) == FALSE) { oidc_warn(r, "error when calling the token endpoint (%s)", provider->token_endpoint_url); return FALSE; } /* check for errors, the response itself will have been logged already */ json_t *result = NULL; if (oidc_util_decode_json_and_check_error(r, response, &result) == FALSE) return FALSE; /* get the id_token from the parsed response */ oidc_json_object_get_string(r->pool, result, "id_token", id_token, NULL); /* get the access_token from the parsed response */ oidc_json_object_get_string(r->pool, result, "access_token", access_token, NULL); /* get the token type from the parsed response */ oidc_json_object_get_string(r->pool, result, "token_type", token_type, NULL); /* check the new token type */ if (token_type != NULL) { if (oidc_proto_validate_token_type(r, provider, *token_type) == FALSE) { oidc_warn(r, "access token type did not validate, dropping it"); *access_token = NULL; } } /* get the expires_in value */ oidc_json_object_get_int(r->pool, result, "expires_in", expires_in, -1); /* get the refresh_token from the parsed response */ oidc_json_object_get_string(r->pool, result, "refresh_token", refresh_token, NULL); json_decref(result); return TRUE; }
/* * parse the JSON conf metadata in to a oidc_provider_t struct */ apr_byte_t oidc_metadata_conf_parse(request_rec *r, oidc_cfg *cfg, json_t *j_conf, oidc_provider_t *provider) { oidc_json_object_get_string(r->pool, j_conf, "client_jwks_uri", &provider->client_jwks_uri, cfg->provider.client_jwks_uri); oidc_json_object_get_string(r->pool, j_conf, "id_token_signed_response_alg", &provider->id_token_signed_response_alg, cfg->provider.id_token_signed_response_alg); oidc_json_object_get_string(r->pool, j_conf, "id_token_encrypted_response_alg", &provider->id_token_encrypted_response_alg, cfg->provider.id_token_encrypted_response_alg); oidc_json_object_get_string(r->pool, j_conf, "id_token_encrypted_response_enc", &provider->id_token_encrypted_response_enc, cfg->provider.id_token_encrypted_response_enc); /* get the (optional) signing & encryption settings for the userinfo response */ oidc_json_object_get_string(r->pool, j_conf, "userinfo_signed_response_alg", &provider->userinfo_signed_response_alg, cfg->provider.userinfo_signed_response_alg); oidc_json_object_get_string(r->pool, j_conf, "userinfo_encrypted_response_alg", &provider->userinfo_encrypted_response_alg, cfg->provider.userinfo_encrypted_response_alg); oidc_json_object_get_string(r->pool, j_conf, "userinfo_encrypted_response_enc", &provider->userinfo_encrypted_response_enc, cfg->provider.userinfo_encrypted_response_enc); /* find out if we need to perform SSL server certificate validation on the token_endpoint and user_info_endpoint for this provider */ oidc_json_object_get_int(r->pool, j_conf, "ssl_validate_server", &provider->ssl_validate_server, cfg->provider.ssl_validate_server); /* find out what scopes we should be requesting from this provider */ // TODO: use the provider "scopes_supported" to mix-and-match with what we've configured for the client // TODO: check that "openid" is always included in the configured scopes, right? oidc_json_object_get_string(r->pool, j_conf, "scope", &provider->scope, cfg->provider.scope); /* see if we've got a custom JWKs refresh interval */ oidc_json_object_get_int(r->pool, j_conf, "jwks_refresh_interval", &provider->jwks_refresh_interval, cfg->provider.jwks_refresh_interval); /* see if we've got a custom IAT slack interval */ oidc_json_object_get_int(r->pool, j_conf, "idtoken_iat_slack", &provider->idtoken_iat_slack, cfg->provider.idtoken_iat_slack); /* see if we've got a custom max session duration */ oidc_json_object_get_int(r->pool, j_conf, "session_max_duration", &provider->session_max_duration, cfg->provider.session_max_duration); /* see if we've got custom authentication request parameter values */ oidc_json_object_get_string(r->pool, j_conf, "auth_request_params", &provider->auth_request_params, cfg->provider.auth_request_params); /* see if we've got custom token endpoint parameter values */ oidc_json_object_get_string(r->pool, j_conf, "token_endpoint_params", &provider->token_endpoint_params, cfg->provider.token_endpoint_params); /* get the response mode to use */ oidc_json_object_get_string(r->pool, j_conf, "response_mode", &provider->response_mode, cfg->provider.response_mode); /* get the client name */ oidc_json_object_get_string(r->pool, j_conf, "client_name", &provider->client_name, cfg->provider.client_name); /* get the client contact */ oidc_json_object_get_string(r->pool, j_conf, "client_contact", &provider->client_contact, cfg->provider.client_contact); /* get the dynamic client registration token */ oidc_json_object_get_string(r->pool, j_conf, "registration_token", &provider->registration_token, cfg->provider.registration_token); /* see if we've got custom registration request parameter values */ oidc_json_object_get_string(r->pool, j_conf, "registration_endpoint_json", &provider->registration_endpoint_json, cfg->provider.registration_endpoint_json); /* get the flow to use */ oidc_json_object_get_string(r->pool, j_conf, "response_type", &provider->response_type, NULL); return TRUE; }