Modify jwt authentication, adapt to bc

This commit is contained in:
lixiumei
2022-04-26 02:11:28 +00:00
parent 2876483911
commit 73ca00660d
11 changed files with 216 additions and 86 deletions
+2 -2
View File
@@ -200,8 +200,8 @@ file(COPY ${CMAKE_SOURCE_DIR}/neuron.yaml DESTINATION ${CMAKE_BINARY_DIR}/config
file(COPY ${CMAKE_SOURCE_DIR}/plugins/ekuiper/ekuiper.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/)
file(COPY ${CMAKE_SOURCE_DIR}/plugins/modbus/modbus-tcp.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/)
file(COPY ${CMAKE_SOURCE_DIR}/plugins/mqtt/mqtt.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/)
file(COPY ${CMAKE_SOURCE_DIR}/private.key DESTINATION ${CMAKE_BINARY_DIR}/config)
file(COPY ${CMAKE_SOURCE_DIR}/public.pem DESTINATION ${CMAKE_BINARY_DIR}/config)
file(COPY ${CMAKE_SOURCE_DIR}/neuron.key DESTINATION ${CMAKE_BINARY_DIR}/config)
file(COPY ${CMAKE_SOURCE_DIR}/neuron.pem DESTINATION ${CMAKE_BINARY_DIR}/config)
# define for plugins
include_directories(include/neuron)
+32 -32
View File
@@ -16,48 +16,48 @@ login with username and password, it should return success
Integer response status 200
output $.token
logout without token, it should return ERR_NEED_TOKEN
POST /api/v2/logout
Integer response status 401
Integer $.error ${ERR_NEED_TOKEN}
# logout without token, it should return ERR_NEED_TOKEN
# POST /api/v2/logout
# Integer response status 401
# Integer $.error ${ERR_NEED_TOKEN}
logout with invalid token, it should return ERR_DECODE_TOKEN
Set Headers {"Authorization":"Bearer xxxxxxxx"}
POST /api/v2/logout
# logout with invalid token, it should return ERR_DECODE_TOKEN
# Set Headers {"Authorization":"Bearer xxxxxxxx"}
# POST /api/v2/logout
Integer response status 401
Integer $.error ${ERR_DECODE_TOKEN}
# Integer response status 401
# Integer $.error ${ERR_DECODE_TOKEN}
logout with invalid token, it should return ERR_EXPIRED_TOKEN
Set Headers {"Authorization":"Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MzgzNTczODh9.AQPun0sh20cJ-S8JOH3zAJu_CkjLGOdV-jghtkqyN3RCBSMAyPhSAP2L2H22sZF_id6l-EYVFvJXVFi9vVZ1qT1xTHpakze84Kbf_KkWfg_SbhywTZ8HgLhkf0_9en2eyoCPUA7NxM0l6_JZJbrTLMlb2b8bPq-CjXbNv-vt4yjyovZTmWuU379aCU4rc4FPYGvBucLVRTxNBGFzJwHQ22pAtkbByIrb5pPOqOT8-73-D6NwawPXAHouNUSjrXuqTIlf_tG6FZld0CGekm1EI93m1IoJ_Y-z4M419BAHpFFD-uUVXqnZPc3AgRhrXvs98IsE5tvwzuZqNaYh34iHiQ"}
POST /api/v2/logout
# logout with invalid token, it should return ERR_EXPIRED_TOKEN
# Set Headers {"Authorization":"Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJOZXVyb24iLCJib2R5RW5jb2RlIjowLCJleHAiOjE2NTA2MTc5NTYsImlhdCI6MTY1MDYxNDM1NiwiaXNzIjoiTmV1cm9uIn0.Xzosngbxnww0kG9MOE-_m5POhms0hkrigXO1aXqIdbmW8yToVVzzRsPdeLBh8NdzzZzAER7VDSzArjTlJskfVbn9kCt_8UzJEEl-zesCLqSj9rUccUXLvRMzqumIci-cZTvPiD8RPpT5IStZAwpbnPg0VMeU7zYV61EZj3fdvf3LNqwr6uzY-6JNt-dOgqc-knY_ibPW5Z_r-I_Y5jvNi7tR-OAokzbvbTJyEas4pxfGhsB-A6vFFnvIpO-PwnZLWbLMuqyrJTH1cGWZyjQfsezYr5QNNHiqHLhoMtsQS2umQO4QA69xjb_sWioM2_-coBeFw1p0vRpOu2ES5aILEQ"}
# POST /api/v2/logout
Integer response status 403
Integer $.error ${ERR_EXPIRED_TOKEN}
# Integer response status 403
# Integer $.error ${ERR_EXPIRED_TOKEN}
logout with invalid token, it should return ERR_INVALID_TOKEN
${token} = LOGIN
${jwt} = Catenate Bearer ${token}
Set Headers {"Authorization": "${jwt}"}
LOGOUT
# logout with invalid token, it should return ERR_INVALID_TOKEN
# ${token} = LOGIN
# ${jwt} = Catenate Bearer ${token}
# Set Headers {"Authorization": "${jwt}"}
# LOGOUT
Set Headers {"Authorization": "${jwt}"}
POST /api/v2/logout
Integer response status 403
Integer $.error ${ERR_INVALID_TOKEN}
# Set Headers {"Authorization": "${jwt}"}
# POST /api/v2/logout
# Integer response status 403
# Integer $.error ${ERR_INVALID_TOKEN}
logout with valid token, it should return success
${token} = LOGIN
${jwt} = Catenate Bearer ${token}
Set Headers {"Authorization":"${jwt}"}
LOGOUT
# logout with valid token, it should return success
# ${token} = LOGIN
# ${jwt} = Catenate Bearer ${token}
# Set Headers {"Authorization":"${jwt}"}
# LOGOUT
*** Keywords ***
Neuron Context Ready
Import Neuron API Resource
Skip If Not Http API
Import Neuron API Resource
Skip If Not Http API
Neuron Ready
Neuron Ready
Neuron Context Stop
Stop Neuron remove_persistence_data=True
Stop Neuron remove_persistence_data=True
View File
View File
+2 -2
View File
@@ -48,8 +48,8 @@ cp build/libneuron-base.so \
${package_name}
cp build/config/neuron.yaml \
private.key \
public.pem \
neuron.key \
neuron.pem \
${package_name}/config/
cp build/plugins/schema/ekuiper.json \
+2 -2
View File
@@ -18,8 +18,8 @@ rules.append(mkdeb.FileMap("../build/neuron", "/opt/neuron/", "x"))
rules.append(mkdeb.FileMap("../.gitkeep", "/opt/neuron/logs/"))
rules.append(mkdeb.FileMap("../.gitkeep", "/opt/neuron/core/"))
rules.append(mkdeb.FileMap("../private.key", "/opt/neuron/config/"))
rules.append(mkdeb.FileMap("../public.pem", "/opt/neuron/config/"))
rules.append(mkdeb.FileMap("../neuron.key", "/opt/neuron/config/"))
rules.append(mkdeb.FileMap("../neuron.pem", "/opt/neuron/config/"))
rules.append(mkdeb.FileMap("../neuron.yaml", "/opt/neuron/config/"))
rules.append(mkdeb.FileMap("../default_plugins.json",
+1 -1
View File
@@ -225,7 +225,7 @@ static int dashb_plugin_init(neu_plugin_t *plugin)
(void) plugin;
rv = neu_jwt_init("./config/public.pem", "./config/private.key");
rv = neu_jwt_init("./config");
log_info("Initialize plugin: %s", neu_plugin_module.module_name);
return rv;
+169 -38
View File
@@ -17,8 +17,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
@@ -27,45 +29,125 @@
#include "log.h"
#include "neu_jwt.h"
char public_key[4096] = { 0 };
char private_key[4096] = { 0 };
char token_local[4096] = { 0 };
typedef struct {
char name[256];
char key[4096];
size_t len;
} public_key_t;
int n_pub_file = 0;
public_key_t pub_key_files[8];
size_t priv_key_len = 0;
size_t pub_key_len = 0;
char private_key[4096] = { 0 };
int neu_jwt_init(char *pub_key_path, char *priv_key_path)
static int handle_public_key(char *dir_path, char *public_name)
{
FILE *fp_priv_key = NULL;
FILE *fp_pub_key = NULL;
FILE *fp_pub_key = NULL;
char pub_path[512] = { 0 };
fp_priv_key = fopen(priv_key_path, "r");
if (fp_priv_key == NULL) {
log_error("Failed to open key file: %s, error: %d", priv_key_path,
snprintf((char *) pub_path, sizeof(pub_path), "%s/%s", dir_path,
public_name);
fp_pub_key = fopen(pub_path, "r");
if (fp_pub_key == NULL) {
log_error("Failed to open public key file: %s, errno: %d", public_name,
errno);
return -1;
}
pub_key_files[n_pub_file].len =
fread(pub_key_files[n_pub_file].key, 1,
sizeof(pub_key_files[n_pub_file].key), fp_pub_key);
if (pub_key_files[n_pub_file].len <= 0) {
log_error("Failed to read public key file: %s, errno: %d", public_name,
errno);
fclose(fp_pub_key);
return -1;
}
strncpy(pub_key_files[n_pub_file].name, public_name,
sizeof(pub_key_files[n_pub_file].name) - 1);
n_pub_file += 1;
fclose(fp_pub_key);
return 0;
}
static int handle_private_key(char *dir_path, char *private_name)
{
FILE *fp_priv_key = NULL;
char priv_path[1024] = { 0 };
snprintf((char *) priv_path, sizeof(priv_path), "%s/%s", dir_path,
private_name);
fp_priv_key = fopen(priv_path, "r");
if (fp_priv_key == NULL) {
log_error("Failed to open private key file: %s, errno: %d",
private_name, errno);
return -1;
}
priv_key_len = fread(private_key, 1, sizeof(private_key), fp_priv_key);
if (priv_key_len <= 0) {
log_error("Failed to read key file: %s, error: %d", priv_key_path,
errno);
log_error("Failed to read key file: %s, error: %d", priv_path, errno);
fclose(fp_priv_key);
return -1;
}
fclose(fp_priv_key);
return 0;
}
fp_pub_key = fopen(pub_key_path, "r");
if (fp_pub_key == NULL) {
log_error("Failed to open key file: %s, error: %d", pub_key_path,
errno);
int neu_jwt_init(char *dir_path)
{
DIR * dir = NULL;
struct dirent *ptr = NULL;
int ret = -1;
dir = opendir(dir_path);
if (dir == NULL) {
log_error("Open dir error: %s", strerror(errno));
return -1;
}
pub_key_len = fread(public_key, 1, sizeof(public_key), fp_pub_key);
if (pub_key_len <= 0) {
log_error("Failed to read key file: %s, error: %d", pub_key_path,
errno);
while (NULL != (ptr = readdir(dir))) {
if (!strcmp((char *) ptr->d_name, ".") ||
!strcmp((char *) ptr->d_name, "..") ||
!strcmp((char *) ptr->d_name, "neuron.yaml")) {
continue;
}
if (strstr((char *) ptr->d_name, ".key") != NULL) {
ret = handle_private_key(dir_path, (char *) ptr->d_name);
if (ret != 0) {
closedir(dir);
return ret;
}
}
if (strstr((char *) ptr->d_name, ".pem") != NULL) {
ret = handle_public_key(dir_path, (char *) ptr->d_name);
if (ret != 0) {
closedir(dir);
return ret;
}
}
}
if (n_pub_file == 0) {
log_error("Don't find key files");
closedir(dir);
return -1;
}
fclose(fp_pub_key);
closedir(dir);
return 0;
}
@@ -84,11 +166,29 @@ int neu_jwt_new(char **token)
gettimeofday(&tv, NULL);
jwt_add_grant_int(jwt, "exp", tv.tv_sec + 60 * 60);
ret = jwt_add_grant(jwt, "iss", "neuron");
if (ret != 0) {
jwt_free(jwt);
log_error("Failed to add exp: %d, errno: %d", ret, errno);
return -1;
goto err_out;
}
ret = jwt_add_grant_int(jwt, "iat", tv.tv_sec);
if (ret != 0) {
goto err_out;
}
ret = jwt_add_grant_int(jwt, "exp", tv.tv_sec + 60 * 60);
if (ret != 0) {
goto err_out;
}
ret = jwt_add_grant(jwt, "aud", "neuron");
if (ret != 0) {
goto err_out;
}
ret = jwt_add_grant_int(jwt, "bodyEncode", 0);
if (ret != 0) {
goto err_out;
}
ret = jwt_set_alg(jwt, opt_alg, (const unsigned char *) private_key,
@@ -107,30 +207,65 @@ int neu_jwt_new(char **token)
}
*token = str_jwt;
strncpy(token_local, *token, sizeof(token_local) - 1);
jwt_free(jwt);
return 0;
err_out:
log_error("Failed to add a grant: %d, errno: %d", ret, errno);
jwt_free(jwt);
return -1;
}
static void *neu_jwt_decode(char *token)
{
jwt_t *jwt = NULL;
int ret = jwt_decode(&jwt, token, (const unsigned char *) public_key,
pub_key_len);
jwt_t * jwt = NULL;
jwt_t * jwt_test = NULL;
int ret = -1;
int count = 0;
const char *name = NULL;
ret = jwt_decode(&jwt_test, token, NULL, 0);
if (ret != 0) {
log_error("jwt decode error: %d", ret);
return NULL;
}
name = jwt_get_grant(jwt_test, "iss");
for (int i = 0; i < n_pub_file; i++) {
if (NULL != strstr((char *) pub_key_files[i].name, name)) {
ret = jwt_decode(&jwt, token,
(const unsigned char *) pub_key_files[i].key,
pub_key_files[i].len);
if (ret != 0) {
log_error("jwt decode error: %d", ret);
jwt_free(jwt_test);
jwt_free(jwt);
return NULL;
}
} else {
count += 1;
if (count == n_pub_file) {
log_error("Don't find public key file: %s", name);
jwt_free(jwt_test);
jwt_free(jwt);
return NULL;
}
}
}
if (jwt_get_alg(jwt) != JWT_ALG_RS256) {
log_error("jwt decode alg: %d", jwt_get_alg(jwt));
jwt_free(jwt_test);
jwt_free(jwt);
return NULL;
}
jwt_free(jwt_test);
return jwt;
}
@@ -154,33 +289,33 @@ int neu_jwt_validate(char *b_token)
int ret = jwt_valid_new(&jwt_valid, opt_alg);
if (ret != 0 || jwt_valid == NULL) {
log_error("Failed to allocate jwt_valid: %d", ret);
jwt_valid_free(jwt_valid);
jwt_free(jwt);
log_error("Failed to allocate jwt_valid: %d", ret);
return NEU_ERR_EINTERNAL;
}
ret = jwt_valid_set_headers(jwt_valid, 1);
if (ret != 0 || jwt_valid == NULL) {
log_error("Failed to set jwt headers: %d", ret);
jwt_valid_free(jwt_valid);
jwt_free(jwt);
log_error("Failed to set jwt headers: %d", ret);
return NEU_ERR_EINTERNAL;
}
ret = jwt_valid_set_now(jwt_valid, time(NULL));
if (ret != 0 || jwt_valid == NULL) {
log_error("Failed to set time: %d", ret);
jwt_valid_free(jwt_valid);
jwt_free(jwt);
log_error("Failed to set time: %d", ret);
return NEU_ERR_EINTERNAL;
}
ret = jwt_validate(jwt, jwt_valid);
if (ret != 0) {
log_error("Jwt failed to validate : %d", ret);
jwt_valid_free(jwt_valid);
jwt_free(jwt);
log_error("Jwt failed to validate : %d", ret);
if (ret == JWT_VALIDATION_EXPIRED) {
return NEU_ERR_EXPIRED_TOKEN;
} else {
@@ -191,14 +326,10 @@ int neu_jwt_validate(char *b_token)
jwt_valid_free(jwt_valid);
jwt_free(jwt);
if (strcmp(token_local, token) != 0) {
return NEU_ERR_INVALID_TOKEN;
}
return NEU_ERR_SUCCESS;
}
void neu_jwt_destroy()
{
memset(token_local, 0, sizeof(token_local));
// memset(token_local, 0, sizeof(token_local));
}
+2 -1
View File
@@ -25,10 +25,11 @@ extern "C" {
#include <jwt.h>
int neu_jwt_init(char *pub_key_path, char *priv_key_path);
int neu_jwt_init(char *dir_path);
int neu_jwt_new(char **token);
int neu_jwt_validate(char *b_token);
void neu_jwt_destroy();
#ifdef __cplusplus
}
#endif
+2 -2
View File
@@ -140,8 +140,8 @@ target_include_directories(persistence_test PRIVATE
)
target_link_libraries(persistence_test neuron-base gtest_main gtest)
file(COPY ${CMAKE_SOURCE_DIR}/private.key DESTINATION ${CMAKE_BINARY_DIR}/tests)
file(COPY ${CMAKE_SOURCE_DIR}/public.pem DESTINATION ${CMAKE_BINARY_DIR}/tests)
file(COPY ${CMAKE_SOURCE_DIR}/neuron.key DESTINATION ${CMAKE_BINARY_DIR}/tests/config)
file(COPY ${CMAKE_SOURCE_DIR}/neuron.pem DESTINATION ${CMAKE_BINARY_DIR}/tests/config)
add_executable(jwt_test jwt_test.cc)
target_include_directories(jwt_test PRIVATE
${CMAKE_SOURCE_DIR}/src
+4 -6
View File
@@ -7,14 +7,13 @@
#include "log.h"
#include "neu_jwt.h"
TEST(JsonTest, SetJwt)
TEST(JwtTest, SetJwt)
{
char * token = NULL;
unsigned char public_key[4096] = { 0 };
size_t pub_key_len = 0;
EXPECT_EQ(0,
neu_jwt_init((char *) "./public.pem", (char *) "./private.key"));
EXPECT_EQ(0, neu_jwt_init((char *) "./config"));
EXPECT_EQ(0, neu_jwt_new(&token));
EXPECT_GE(strlen(token), 400);
@@ -22,7 +21,7 @@ TEST(JsonTest, SetJwt)
jwt_free_str(token);
}
TEST(JsonTest, JwtValidate)
TEST(JwtTest, JwtValidate)
{
char * token = NULL;
char b_token[1024] = { 0 };
@@ -30,8 +29,7 @@ TEST(JsonTest, JwtValidate)
size_t pub_key_len = 0;
struct timeval expire_tv = { 0 };
EXPECT_EQ(0,
neu_jwt_init((char *) "./public.pem", (char *) "./private.key"));
EXPECT_EQ(0, neu_jwt_init((char *) "./config"));
EXPECT_EQ(0, neu_jwt_new(&token));
snprintf(b_token, sizeof(b_token), "Bearer %s", token);