Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 35 additions & 9 deletions src/wh_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ int wh_Server_Init(whServerContext* server, whServerConfig* config)
server->nvm = config->nvm;
#ifdef WOLFHSM_CFG_ENABLE_AUTHENTICATION
server->auth = config->auth;
/* auth context is externally owned; clear any stale session left over from
* a prior connection (Logout first so backend callback runs). */
if (server->auth != NULL &&
server->auth->user.user_id != WH_USER_ID_INVALID) {
whUserId stale_id = server->auth->user.user_id;
int logout_rc = wh_Auth_Logout(server->auth, stale_id);
if (logout_rc != WH_ERROR_OK ||
server->auth->user.user_id != WH_USER_ID_INVALID) {
memset(&server->auth->user, 0, sizeof(server->auth->user));
}
}
#endif /* WOLFHSM_CFG_ENABLE_AUTHENTICATION */

#ifndef WOLFHSM_CFG_NO_CRYPTO
Expand Down Expand Up @@ -177,6 +188,27 @@ int wh_Server_SetConnected(whServerContext *server, whCommConnected connected)
return WH_ERROR_BADARGS;
}

#ifdef WOLFHSM_CFG_ENABLE_AUTHENTICATION
/* Log out any active user on disconnect, including abrupt drops where
* COMM_CLOSE never arrives. */
if (connected == WH_COMM_DISCONNECTED &&
server->connected != WH_COMM_DISCONNECTED &&
server->auth != NULL &&
server->auth->user.user_id != WH_USER_ID_INVALID) {
whUserId user_id = server->auth->user.user_id;
int logout_rc = wh_Auth_Logout(server->auth, user_id);

/* wh_Auth_Logout only clears the session when the backend callback
* returns WH_ERROR_OK. Force-clear if it failed or left the user set,
* so a stale identity can never carry over to the next connection
* (mirrors the defensive clear in wh_Server_Init). */
if (logout_rc != WH_ERROR_OK ||
server->auth->user.user_id != WH_USER_ID_INVALID) {
memset(&server->auth->user, 0, sizeof(server->auth->user));
}
}
#endif /* WOLFHSM_CFG_ENABLE_AUTHENTICATION */

server->connected = connected;
return WH_ERROR_OK;
}
Expand Down Expand Up @@ -285,15 +317,9 @@ static int _wh_Server_HandleCommRequest(whServerContext* server,
/* No message */
/* Process the close action */

#ifdef WOLFHSM_CFG_ENABLE_AUTHENTICATION
/* Log out the current user when communication channel closes */
if (server->auth != NULL &&
server->auth->user.user_id != WH_USER_ID_INVALID) {
whUserId user_id = server->auth->user.user_id;
(void)wh_Auth_Logout(server->auth, user_id);
}
#endif /* WOLFHSM_CFG_ENABLE_AUTHENTICATION */

/* wh_Server_SetConnected logs out any active user on the transition to
* the disconnected state, so the graceful-close and abrupt-disconnect
* paths share a single authoritative logout. */
wh_Server_SetConnected(server, WH_COMM_DISCONNECTED);
*out_resp_size = 0;

Expand Down
51 changes: 50 additions & 1 deletion test/wh_test_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ static whNvmContext nvm[1] = {{0}};
/* Test-specific authorization override callbacks to verify they are invoked */
static int test_checkRequestAuthorizationCalled = 0;
static int test_checkKeyAuthorizationCalled = 0;
static int test_logoutCallCount = 0;

static int test_CheckRequestAuthorization(void* context, int err,
uint16_t user_id, uint16_t group,
Expand All @@ -115,12 +116,20 @@ static int test_CheckKeyAuthorization(void* context, int err, uint16_t user_id,
return err;
}

/* Counts Logout calls for the abrupt-disconnect test. */
static int test_Logout(void* context, uint16_t current_user_id,
uint16_t user_id)
{
test_logoutCallCount++;
return wh_Auth_BaseLogout(context, current_user_id, user_id);
}

/* Auth setup following wh_posix_server pattern */
static whAuthCb default_auth_cb = {
.Init = wh_Auth_BaseInit,
.Cleanup = wh_Auth_BaseCleanup,
.Login = wh_Auth_BaseLogin,
.Logout = wh_Auth_BaseLogout,
.Logout = test_Logout,
.CheckRequestAuthorization = test_CheckRequestAuthorization,
.CheckKeyAuthorization = test_CheckKeyAuthorization,
.UserAdd = wh_Auth_BaseUserAdd,
Expand All @@ -142,6 +151,10 @@ static int _whTest_Auth_SetupMemory(whClientContext** out_client)
uint16_t out_user_id;
int i;

/* Reset so logout-count assertions are self-contained across repeated
* invocations of the suite in a single process. */
test_logoutCallCount = 0;

/* Initialize transport memory config - avoid compound literals for C90 */
tmcf->req = (whTransportMemCsr*)req_buffer;
tmcf->req_size = sizeof(req_buffer);
Expand Down Expand Up @@ -1415,6 +1428,41 @@ int whTest_AuthTCP(whClientConfig* clientCfg)
}


#if !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP) && \
defined(WOLFHSM_CFG_ENABLE_SERVER)
static int _whTest_Auth_AbruptDisconnect(whClientContext* client_ctx)
{
int32_t server_rc = 0;
whUserId user_id = WH_USER_ID_INVALID;
int logouts_before = 0;

WH_TEST_PRINT(" Test: Abrupt disconnect calls wh_Auth_Logout\n");

WH_TEST_RETURN_ON_FAIL(_whTest_Auth_LoginOp(
client_ctx, WH_AUTH_METHOD_PIN, TEST_ADMIN_USERNAME, TEST_ADMIN_PIN,
strlen(TEST_ADMIN_PIN), &server_rc, &user_id));
WH_TEST_ASSERT_RETURN(server_rc == WH_ERROR_OK);
WH_TEST_ASSERT_RETURN(user_id != WH_USER_ID_INVALID);
WH_TEST_ASSERT_RETURN(auth_ctx.user.user_id == user_id);
WH_TEST_ASSERT_RETURN(auth_ctx.user.is_active);

logouts_before = test_logoutCallCount;
WH_TEST_RETURN_ON_FAIL(
wh_Server_SetConnected(server, WH_COMM_DISCONNECTED));
WH_TEST_ASSERT_RETURN(test_logoutCallCount == logouts_before + 1);
WH_TEST_ASSERT_RETURN(auth_ctx.user.user_id == WH_USER_ID_INVALID);
WH_TEST_ASSERT_RETURN(!auth_ctx.user.is_active);

/* Repeat disconnect is a no-op. */
logouts_before = test_logoutCallCount;
WH_TEST_RETURN_ON_FAIL(
wh_Server_SetConnected(server, WH_COMM_DISCONNECTED));
WH_TEST_ASSERT_RETURN(test_logoutCallCount == logouts_before);

return WH_TEST_SUCCESS;
}
#endif /* memory transport */

int whTest_AuthMEM(void)
{
#if !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP) && \
Expand All @@ -1424,6 +1472,7 @@ int whTest_AuthMEM(void)
/* Memory transport mode */
WH_TEST_RETURN_ON_FAIL(_whTest_Auth_SetupMemory(&client_ctx));
WH_TEST_RETURN_ON_FAIL(whTest_AuthTest(client_ctx));
WH_TEST_RETURN_ON_FAIL(_whTest_Auth_AbruptDisconnect(client_ctx));

/* Verify that authorization callbacks were invoked during tests */
WH_TEST_PRINT(
Expand Down
Loading