SUPPORT-8821. Генерация client_secret, в ответе возвращается подпись и state
This commit is contained in:
parent
919fd8cd7a
commit
de5afea941
1 changed files with 131 additions and 21 deletions
|
|
@ -3,6 +3,8 @@
|
||||||
#include "fcgisrv/fcgi_utils.h"
|
#include "fcgisrv/fcgi_utils.h"
|
||||||
|
|
||||||
#include "utils/cryptopro.h"
|
#include "utils/cryptopro.h"
|
||||||
|
#include "utils/json_writer.h"
|
||||||
|
#include "utils/uuid.h"
|
||||||
|
|
||||||
#define SIGN_CONF_SECTION "sign"
|
#define SIGN_CONF_SECTION "sign"
|
||||||
#define SIGN_CONF_KEY_LOCATION "location"
|
#define SIGN_CONF_KEY_LOCATION "location"
|
||||||
|
|
@ -10,9 +12,9 @@
|
||||||
#define SIGN_CONF_KEY_SIGN_CERT_PASSWORD "sign_cert_password"
|
#define SIGN_CONF_KEY_SIGN_CERT_PASSWORD "sign_cert_password"
|
||||||
|
|
||||||
#define FCGI_OK_RESPONSE_FORMAT \
|
#define FCGI_OK_RESPONSE_FORMAT \
|
||||||
"Content-type: text/plain" CRLF\
|
"Content-type: application/json" CRLF\
|
||||||
CRLF\
|
CRLF\
|
||||||
"%.*s" CRLF
|
"%s" CRLF
|
||||||
|
|
||||||
static const str_t SIGN_CONF_DEFAULT_LOCATION = str_t_const("/sign");
|
static const str_t SIGN_CONF_DEFAULT_LOCATION = str_t_const("/sign");
|
||||||
|
|
||||||
|
|
@ -30,7 +32,7 @@ typedef struct fcgi_sign_request_s {
|
||||||
char *content;
|
char *content;
|
||||||
int content_length;
|
int content_length;
|
||||||
|
|
||||||
str_t signed_content;
|
char *response;
|
||||||
|
|
||||||
} fcgi_sign_request_t;
|
} fcgi_sign_request_t;
|
||||||
|
|
||||||
|
|
@ -38,7 +40,7 @@ static void fcgi_sign_request_clear(fcgi_sign_request_t *req_info);
|
||||||
|
|
||||||
static fcgi_request_handler_pt fcgi_request_finalize_handler(fcgi_handler_status_t status);
|
static fcgi_request_handler_pt fcgi_request_finalize_handler(fcgi_handler_status_t status);
|
||||||
|
|
||||||
static int sign_content(const sign_service_t *hsign, fcgi_sign_request_t *req_info);
|
static int sign_client_secret(const sign_service_t *hsign, fcgi_sign_request_t *req_info);
|
||||||
|
|
||||||
int
|
int
|
||||||
sign_conf_load(sign_conf_t *conf, const conf_file_context_t conf_file)
|
sign_conf_load(sign_conf_t *conf, const conf_file_context_t conf_file)
|
||||||
|
|
@ -182,7 +184,7 @@ fcgi_sign_handler(FCGX_Request* request, void* ctx)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sign_content(hsign, &req_info)) {
|
if (sign_client_secret(hsign, &req_info)) {
|
||||||
status = HANDLER_ERROR;
|
status = HANDLER_ERROR;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +206,9 @@ fcgi_sign_request_clear(fcgi_sign_request_t *req_info)
|
||||||
LOG_TRACE("fcgi_sign_request_clear");
|
LOG_TRACE("fcgi_sign_request_clear");
|
||||||
|
|
||||||
free(req_info->content);
|
free(req_info->content);
|
||||||
str_t_clear(&(req_info->signed_content));
|
free(req_info->response);
|
||||||
|
|
||||||
|
memset(req_info, 0, sizeof(fcgi_sign_request_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
static fcgi_handler_status_t
|
static fcgi_handler_status_t
|
||||||
|
|
@ -214,11 +218,9 @@ fcgi_ok_handler(const FCGX_Request* request, void *ctx)
|
||||||
|
|
||||||
const fcgi_sign_request_t *req_info = (fcgi_sign_request_t*) ctx;
|
const fcgi_sign_request_t *req_info = (fcgi_sign_request_t*) ctx;
|
||||||
|
|
||||||
LOG_DEBUG("response status: " FCGI_OK_RESPONSE_FORMAT,
|
LOG_DEBUG("response status: " FCGI_OK_RESPONSE_FORMAT, req_info->response);
|
||||||
(int) req_info->signed_content.len, req_info->signed_content.data);
|
|
||||||
|
if (FCGX_FPrintF(request->out, FCGI_OK_RESPONSE_FORMAT, req_info->response) < 0) {
|
||||||
if (FCGX_FPrintF(request->out, FCGI_OK_RESPONSE_FORMAT,
|
|
||||||
(int) req_info->signed_content.len, req_info->signed_content.data) < 0) {
|
|
||||||
LOG_ERROR("FCGX_FPrintF() failed");
|
LOG_ERROR("FCGX_FPrintF() failed");
|
||||||
return HANDLER_ERROR;
|
return HANDLER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
@ -233,10 +235,13 @@ fcgi_request_finalize_handler(fcgi_handler_status_t status)
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case HANDLER_SUCCESS:
|
case HANDLER_SUCCESS:
|
||||||
case HANDLER_HTTP_OK:
|
|
||||||
handler = fcgi_ok_handler;
|
handler = fcgi_ok_handler;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HANDLER_HTTP_OK:
|
||||||
|
handler = fcgi_200_ok_handler;
|
||||||
|
break;
|
||||||
|
|
||||||
case HANDLER_HTTP_BAD_REQUEST:
|
case HANDLER_HTTP_BAD_REQUEST:
|
||||||
handler = fcgi_400_bad_request_handler;
|
handler = fcgi_400_bad_request_handler;
|
||||||
break;
|
break;
|
||||||
|
|
@ -259,23 +264,128 @@ fcgi_request_finalize_handler(fcgi_handler_status_t status)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sign_content(const sign_service_t *hsign, fcgi_sign_request_t *req_info)
|
generate_client_secret(const fcgi_sign_request_t *req_info, const char *state,
|
||||||
|
/*out*/ str_t *secret)
|
||||||
{
|
{
|
||||||
LOG_TRACE("sign_content enter");
|
LOG_TRACE("generate_client_secret enter");
|
||||||
|
|
||||||
str_t content = {
|
size_t secret_size = req_info->content_length + strlen(state);
|
||||||
.data = req_info->content,
|
|
||||||
.len = req_info->content_length
|
|
||||||
};
|
|
||||||
|
|
||||||
if (cryptopro_sign(&hsign->cryptopro_ctx, &content, &req_info->signed_content)) {
|
secret->data = malloc(secret_size);
|
||||||
|
if (secret->data == NULL) {
|
||||||
|
LOG_ERROR("Could not allocate memory for client_secret (%zd bytes)", secret_size);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_TRACE("sign_content exit");
|
int len = snprintf(secret->data, secret_size, req_info->content, state);
|
||||||
|
if (len < 0 || (size_t)len >= secret_size) {
|
||||||
|
LOG_ERROR("Could not concatenate client_secret");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
secret->len = len;
|
||||||
|
|
||||||
|
LOG_TRACE("generate_client_secret exit");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
LOG_ERROR("sign_content exit with error");
|
str_t_clear(secret);
|
||||||
|
LOG_ERROR("generate_client_secret exit with error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
generate_response(const char *signature, const char *state)
|
||||||
|
{
|
||||||
|
JsonBuilder *jbuilder;
|
||||||
|
char *response;
|
||||||
|
|
||||||
|
LOG_TRACE("generate_response enter");
|
||||||
|
|
||||||
|
jbuilder = json_builder_new();
|
||||||
|
if (jbuilder == NULL) {
|
||||||
|
LOG_ERROR("json_builder_new failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_builder_begin_object(jbuilder) == NULL) {
|
||||||
|
LOG_ERROR("json_builder_begin_object failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_write_member_string(jbuilder, "signature", signature)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_write_member_string(jbuilder, "state", state)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_builder_end_object(jbuilder) == NULL) {
|
||||||
|
LOG_ERROR("json_builder_end_object failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
response = json_write_to_str(jbuilder);
|
||||||
|
|
||||||
|
g_object_unref(jbuilder);
|
||||||
|
|
||||||
|
LOG_TRACE("generate_response exit");
|
||||||
|
return response;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (jbuilder != NULL) {
|
||||||
|
g_object_unref(jbuilder);
|
||||||
|
}
|
||||||
|
LOG_ERROR("generate_response exit with error");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sign_client_secret(const sign_service_t *hsign, fcgi_sign_request_t *req_info)
|
||||||
|
{
|
||||||
|
str_t secret = str_t_null;
|
||||||
|
char *state = NULL;
|
||||||
|
str_t signature = str_t_null;
|
||||||
|
|
||||||
|
LOG_TRACE("sign_client_secret enter");
|
||||||
|
|
||||||
|
state = generate_uuid4();
|
||||||
|
if (state == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generate_client_secret(req_info, state, &secret)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cryptopro_sign(&hsign->cryptopro_ctx, &secret, &signature)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(str_t_is_null_terminated(signature));
|
||||||
|
|
||||||
|
req_info->response = generate_response(signature.data, state);
|
||||||
|
|
||||||
|
if (req_info->response == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("state: '%s'", state);
|
||||||
|
LOG_DEBUG("client secret: '%.*s'", (int) secret.len, secret.data);
|
||||||
|
LOG_DEBUG("response: '%s'", req_info->response);
|
||||||
|
|
||||||
|
str_t_clear(&secret);
|
||||||
|
free(state);
|
||||||
|
str_t_clear(&signature);
|
||||||
|
|
||||||
|
LOG_TRACE("sign_client_secret exit");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
str_t_clear(&secret);
|
||||||
|
free(state);
|
||||||
|
str_t_clear(&signature);
|
||||||
|
LOG_ERROR("sign_client_secret exit with error");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue