diff --git a/include/neuron/utils/http_handler.h b/include/neuron/utils/http_handler.h index 0f34c842..53a3841f 100644 --- a/include/neuron/utils/http_handler.h +++ b/include/neuron/utils/http_handler.h @@ -78,6 +78,24 @@ } \ } +#define NEU_VALIDATE_JWT_WITH_USER(aio, user) \ + { \ + if (!disable_jwt) { \ + char *jwt = \ + (char *) neu_http_get_header(aio, (char *) "Authorization"); \ + \ + NEU_JSON_RESPONSE_ERROR(neu_jwt_validate(jwt), { \ + if (error_code.error != NEU_ERR_SUCCESS) { \ + neu_http_response(aio, error_code.error, result_error); \ + free(result_error); \ + return; \ + } else { \ + neu_jwt_decode_user(jwt, user); \ + } \ + }); \ + } \ + } + enum neu_http_method { NEU_HTTP_METHOD_UNDEFINE = 0x0, NEU_HTTP_METHOD_GET, diff --git a/include/neuron/utils/neu_jwt.h b/include/neuron/utils/neu_jwt.h index 815a9572..2c3deee6 100644 --- a/include/neuron/utils/neu_jwt.h +++ b/include/neuron/utils/neu_jwt.h @@ -26,9 +26,10 @@ extern "C" { #include int neu_jwt_init(const char *dir_path); -int neu_jwt_new(char **token); +int neu_jwt_new(char **token, const char *user); int neu_jwt_validate(char *b_token); void neu_jwt_destroy(); +int neu_jwt_decode_user(char *token, char *user); #ifdef __cplusplus } diff --git a/plugins/restful/normal_handle.c b/plugins/restful/normal_handle.c index 71955b76..2ba15c22 100644 --- a/plugins/restful/normal_handle.c +++ b/plugins/restful/normal_handle.c @@ -73,7 +73,7 @@ void handle_login(nng_aio *aio) char *token = NULL; char *result = NULL; - int ret = neu_jwt_new(&token); + int ret = neu_jwt_new(&token, req->name); if (ret != 0) { NEU_JSON_RESPONSE_ERROR(NEU_ERR_NEED_TOKEN, { neu_http_response(aio, error_code.error, result_error); @@ -101,7 +101,62 @@ void handle_login(nng_aio *aio) void handle_add_user(nng_aio *aio) { - (void) aio; + char current_user[USER_NAME_LEN] = { 0 }; + NEU_VALIDATE_JWT_WITH_USER(aio, current_user); + NEU_PROCESS_HTTP_REQUEST( + aio, neu_json_login_req_t, neu_json_decode_login_req, { + neu_json_login_resp_t login_resp = { 0 }; + neu_user_t * user = neu_load_user(req->name); + int pass_len = strlen(req->pass); + + if (0 == strlen(current_user)) { + nlog_error("check current user failed"); + NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_OR_PASSWORD, { + neu_http_response(aio, error_code.error, result_error); + }); + } + + if (NULL == user) { + nlog_error("could not find user `%s`", req->name); + NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_OR_PASSWORD, { + neu_http_response(aio, error_code.error, result_error); + }); + } else if (pass_len < NEU_USER_PASSWORD_MIN_LEN || + pass_len > NEU_USER_PASSWORD_MAX_LEN) { + nlog_error("user `%s` password too short or too long", + req->name); + NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_PASSWORD_LEN, { + neu_http_response(aio, error_code.error, result_error); + }); + } else if (neu_user_check_password(user, req->pass)) { + + char *token = NULL; + char *result = NULL; + + int ret = neu_jwt_new(&token, req->name); + if (ret != 0) { + NEU_JSON_RESPONSE_ERROR(NEU_ERR_NEED_TOKEN, { + neu_http_response(aio, error_code.error, result_error); + jwt_free_str(token); + }); + } + + login_resp.token = token; + + neu_json_encode_by_fn(&login_resp, neu_json_encode_login_resp, + &result); + neu_http_ok(aio, result); + jwt_free_str(token); + free(result); + } else { + nlog_error("user `%s` password check fail", req->name); + NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_OR_PASSWORD, { + neu_http_response(aio, error_code.error, result_error); + }); + } + + neu_user_free(user); + }) } void handle_delete_user(nng_aio *aio) diff --git a/plugins/restful/user.h b/plugins/restful/user.h index 6d5ce233..529acd3c 100644 --- a/plugins/restful/user.h +++ b/plugins/restful/user.h @@ -28,6 +28,8 @@ extern "C" { #include "persist/persist.h" +#define USER_NAME_LEN 32 + typedef struct { char *name; char *hash; @@ -41,6 +43,10 @@ int neu_user_update_password(neu_user_t *user, const char *new_password); neu_user_t *neu_load_user(const char *name); int neu_save_user(neu_user_t *user); +int neu_user_list(); +int neu_user_add(const char *name, const char *password); +int neu_user_delete(const char *name); + #ifdef __cplusplus } #endif diff --git a/src/parser/neu_json_login.c b/src/parser/neu_json_login.c index e12cd853..a0db84ec 100644 --- a/src/parser/neu_json_login.c +++ b/src/parser/neu_json_login.c @@ -129,3 +129,66 @@ int neu_json_encode_login_resp(void *json_object, void *param) return ret; } + +int neu_json_decode_add_user_req(char *buf, neu_json_password_req_t **result) +{ + int ret = 0; + + neu_json_password_req_t *req = calloc(1, sizeof(neu_json_password_req_t)); + neu_json_elem_t req_elems[] = { + { + .name = "name", + .t = NEU_JSON_STR, + }, + { + .name = "old_pass", + .t = NEU_JSON_STR, + }, + { + .name = "new_pass", + .t = NEU_JSON_STR, + }, + }; + ret = neu_json_decode(buf, NEU_JSON_ELEM_SIZE(req_elems), req_elems); + if (ret != 0) { + goto decode_fail; + } + + req->name = req_elems[0].v.val_str; + req->old_pass = req_elems[1].v.val_str; + req->new_pass = req_elems[2].v.val_str; + + *result = req; + return ret; + +decode_fail: + free(req); + return -1; +} + +void neu_json_decode_add_user_req_free(neu_json_password_req_t *req) +{ + if (req) { + free(req->name); + free(req->old_pass); + free(req->new_pass); + + free(req); + } +} + +int neu_json_encode_add_user_resp(void *json_object, void *param) +{ + int ret = 0; + neu_json_login_resp_t *resp = (neu_json_login_resp_t *) param; + + neu_json_elem_t resp_elems[] = { { + .name = "token", + .t = NEU_JSON_STR, + .v.val_str = resp->token, + } }; + ret = neu_json_encode_field(json_object, resp_elems, + NEU_JSON_ELEM_SIZE(resp_elems)); + + return ret; +} diff --git a/src/parser/neu_json_login.h b/src/parser/neu_json_login.h index 4982f4a5..138a85d8 100644 --- a/src/parser/neu_json_login.h +++ b/src/parser/neu_json_login.h @@ -54,6 +54,9 @@ typedef struct { int neu_json_encode_login_resp(void *json_object, void *param); +int neu_json_decode_add_user_req(char *buf, neu_json_password_req_t **result); +void neu_json_decode_add_user_req_free(neu_json_password_req_t *req); + #ifdef __cplusplus } #endif diff --git a/src/utils/neu_jwt.c b/src/utils/neu_jwt.c index d489c8ea..26ba6590 100644 --- a/src/utils/neu_jwt.c +++ b/src/utils/neu_jwt.c @@ -145,7 +145,7 @@ int neu_jwt_init(const char *dir_path) return 0; } -int neu_jwt_new(char **token) +int neu_jwt_new(char **token, const char *user) { struct timeval tv = { 0 }; jwt_alg_t opt_alg = JWT_ALG_RS256; @@ -185,6 +185,14 @@ int neu_jwt_new(char **token) goto err_out; } + // only normal user need to add user grant + // do not change the original logic + if (0 != strcmp(user, "admin")) { + if (0 != jwt_add_grant(jwt, "user", user)) { + goto err_out; + } + } + ret = jwt_set_alg(jwt, opt_alg, (const unsigned char *) neuron_private_key, strlen(neuron_private_key)); if (ret != 0) { @@ -214,6 +222,30 @@ err_out: return -1; } +int neu_jwt_decode_user(char *token, char *user) +{ + jwt_t *jwt = NULL; + int ret = -1; + + ret = jwt_decode(&jwt, token, NULL, 0); + if (ret != 0) { + zlog_error(neuron, "jwt decode error: %d", ret); + return -1; + } + + const char *user_grant = jwt_get_grant(jwt, "user"); + + if (NULL == user_grant) { + zlog_error(neuron, "jwt get user grant error, the token is: %s", token); + jwt_free(jwt); + return -1; + } + + strncpy(user, user_grant, strlen(user_grant)); + jwt_free(jwt); + return 0; +} + static void *neu_jwt_decode(char *token) { jwt_t * jwt = NULL; diff --git a/tests/ut/jwt_test.cc b/tests/ut/jwt_test.cc index 1015acbf..53d08679 100644 --- a/tests/ut/jwt_test.cc +++ b/tests/ut/jwt_test.cc @@ -14,7 +14,7 @@ TEST(JwtTest, SetJwt) EXPECT_EQ(0, neu_jwt_init((char *) "./config")); - EXPECT_EQ(0, neu_jwt_new(&token)); + EXPECT_EQ(0, neu_jwt_new(&token, "admin")); EXPECT_GE(strlen(token), 400); jwt_free_str(token); @@ -26,7 +26,7 @@ TEST(JwtTest, JwtValidate) char b_token[1024] = { 0 }; EXPECT_EQ(0, neu_jwt_init((char *) "./config")); - EXPECT_EQ(0, neu_jwt_new(&token)); + EXPECT_EQ(0, neu_jwt_new(&token, "admin")); snprintf(b_token, sizeof(b_token), "Bearer %s", token);