From 3425cddd75fa105b940c8c0afe4a63065c446515 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Tue, 17 Feb 2026 03:31:40 +0100 Subject: Make authentication mode and credentials configurable via CLI Replace hardcoded user/password credentials with a new parameter that accepts "anonymous" or "user". When "user" is chosen, two additional arguments are required. ServerRegister accepts two independent auth modes: one for its own server-side access control and one for authenticating to the LDS when registering. ClientFindServers passes credentials to readServerTime, which selects UA_Client_connectUsername or UA_Client_connect accordingly. Update CLAUDE.md running examples and add an auth modes table. --- src/client_find_servers.c | 52 ++++++++++++++++--- src/server_lds.c | 64 +++++++++++++++++++----- src/server_register.c | 124 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 197 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/client_find_servers.c b/src/client_find_servers.c index 4789b38..21d48ca 100644 --- a/src/client_find_servers.c +++ b/src/client_find_servers.c @@ -129,11 +129,14 @@ getServersEndpoints (UA_Client *client, * @param applicationDescriptionArray Array of server descriptions from * FindServers. * @param applicationDescriptionArraySize Number of servers in the array. + * @param username Username for session auth, or NULL for anonymous. + * @param password Password for session auth (ignored when username is NULL). */ static void readServerTime (UA_Client *client, UA_ApplicationDescription *applicationDescriptionArray, - size_t applicationDescriptionArraySize) + size_t applicationDescriptionArraySize, const char *username, + const char *password) { for (size_t i = 0; i < applicationDescriptionArraySize; i++) { @@ -160,8 +163,11 @@ readServerTime (UA_Client *client, UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "Connecting to %s to read current time...", url); - UA_StatusCode retval - = UA_Client_connectUsername (client, url, "user", "password"); + UA_StatusCode retval; + if (username) + retval = UA_Client_connectUsername (client, url, username, password); + else + retval = UA_Client_connect (client, url); UA_free (url); if (retval != UA_STATUSCODE_GOOD) { @@ -204,19 +210,21 @@ readServerTime (UA_Client *client, int main (int argc, char **argv) { - if (argc < 7) + if (argc < 8) { UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Usage: %s \n" " \n" " \n" " \n" + " [ ]\n" " [, ...]\n" "\n" "Security modes : None, Sign, SignAndEncrypt\n" "Security policies: None, Basic256Sha256, " "Aes256_Sha256_RsaPss,\n" - " Aes128_Sha256_RsaOaep, ECC_nistP256", + " Aes128_Sha256_RsaOaep, ECC_nistP256\n" + "Auth modes : anonymous, user", argv[0]); return EXIT_FAILURE; } @@ -242,8 +250,36 @@ main (int argc, char **argv) return EXIT_FAILURE; } - char **trustPaths = argv + 7; - size_t trustSize = (argc > 7) ? (size_t)argc - 7 : 0; + int idx = 7; + const char *authMode = argv[idx++]; + const char *username = NULL, *password = NULL; + + if (strcmp (authMode, "anonymous") == 0) + { + /* No extra args needed */ + } + else if (strcmp (authMode, "user") == 0) + { + if (idx + 2 > argc) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Auth mode 'user' requires "); + return EXIT_FAILURE; + } + username = argv[idx++]; + password = argv[idx++]; + } + else + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Unknown auth mode: %s " + "(expected 'anonymous' or 'user')", + authMode); + return EXIT_FAILURE; + } + + char **trustPaths = argv + idx; + size_t trustSize = (idx < argc) ? (size_t)(argc - idx) : 0; UA_Client *client = UA_Client_new (); UA_StatusCode retval = createSecureClientConfig ( @@ -271,7 +307,7 @@ main (int argc, char **argv) applicationDescriptionArraySize); readServerTime (client, applicationDescriptionArray, - applicationDescriptionArraySize); + applicationDescriptionArraySize, username, password); UA_Client_delete (client); UA_Array_delete (applicationDescriptionArray, diff --git a/src/server_lds.c b/src/server_lds.c index 12dfe59..fc51596 100644 --- a/src/server_lds.c +++ b/src/server_lds.c @@ -33,14 +33,17 @@ main (int argc, char *argv[]) signal (SIGINT, stopHandler); signal (SIGTERM, stopHandler); - if (argc < 6) + if (argc < 7) { UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Usage: %s\n" " \n" " \n" " \n" - " [, ...]", + " [ ]\n" + " [, ...]\n" + "\n" + "Auth modes: anonymous, user", argv[0]); return EXIT_FAILURE; } @@ -57,27 +60,62 @@ main (int argc, char *argv[]) cleanupTimeout); return EXIT_FAILURE; } - size_t trustSize = (argc > 6) ? (size_t)argc - 6 : 0; + + int idx = 6; + const char *authMode = argv[idx++]; + UA_Boolean allowAnonymous; + char *username = NULL, *password = NULL; + + if (strcmp (authMode, "anonymous") == 0) + { + allowAnonymous = true; + } + else if (strcmp (authMode, "user") == 0) + { + if (idx + 2 > argc) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Auth mode 'user' requires "); + return EXIT_FAILURE; + } + allowAnonymous = false; + username = argv[idx++]; + password = argv[idx++]; + } + else + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Unknown auth mode: %s " + "(expected 'anonymous' or 'user')", + authMode); + return EXIT_FAILURE; + } + + size_t trustSize = (idx < argc) ? (size_t)(argc - idx) : 0; UA_StatusCode retval; UA_Server *server = createSecureServer (port, argv[2], argv[3], argv[4], - argv + 6, trustSize, &retval); + argv + idx, trustSize, &retval); if (!server) return EXIT_FAILURE; UA_ServerConfig *serverConfig = UA_Server_getConfig (server); - /* Disallow anonymous sessions. + /* Configure access control after server creation because UA_ServerConfig_setDefaultWithSecurityPolicies (called by - createSecureServer) resets access control, so this must come after server - creation. The static credential list is deep-copied. */ - UA_UsernamePasswordLogin logins[] - = { { UA_STRING_STATIC ("user"), UA_STRING_STATIC ("password") } }; - retval = UA_AccessControl_default (serverConfig, false, NULL, 1, logins); - if (retval != UA_STATUSCODE_GOOD) + createSecureServer) resets the access control plugin. The credential + list is deep-copied by UA_AccessControl_default. */ + if (!allowAnonymous) { - UA_Server_delete (server); - return EXIT_FAILURE; + UA_UsernamePasswordLogin logins[1]; + logins[0].username = UA_STRING (username); + logins[0].password = UA_STRING (password); + retval = UA_AccessControl_default (serverConfig, false, NULL, 1, logins); + if (retval != UA_STATUSCODE_GOOD) + { + UA_Server_delete (server); + return EXIT_FAILURE; + } } /* Mark this server as a Discovery Server so clients can identify it. */ diff --git a/src/server_register.c b/src/server_register.c index 8b750fe..c90fc31 100644 --- a/src/server_register.c +++ b/src/server_register.c @@ -41,7 +41,7 @@ main (int argc, char **argv) signal (SIGINT, stopHandler); signal (SIGTERM, stopHandler); - if (argc < 11) + if (argc < 13) { UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Usage: %s\n" @@ -51,12 +51,15 @@ main (int argc, char **argv) " \n" " \n" " \n" + " [ ]\n" + " [ ]\n" " [, ...]\n" "\n" "Security modes : None, Sign, SignAndEncrypt\n" "Security policies: None, Basic256Sha256, " "Aes256_Sha256_RsaPss,\n" - " Aes128_Sha256_RsaOaep, ECC_nistP256", + " Aes128_Sha256_RsaOaep, ECC_nistP256\n" + "Auth modes : anonymous, user", argv[0]); return EXIT_FAILURE; } @@ -84,27 +87,101 @@ main (int argc, char **argv) return EXIT_FAILURE; } - size_t trustSize = (argc > 11) ? (size_t)argc - 11 : 0; + /* Parse server-side auth mode (what clients connecting to this server + need). "anonymous" allows unauthenticated sessions; "user" requires + a username/password pair. */ + int idx = 11; + const char *serverAuthMode = argv[idx++]; + UA_Boolean serverAllowAnonymous; + char *serverUsername = NULL, *serverPassword = NULL; + + if (strcmp (serverAuthMode, "anonymous") == 0) + { + serverAllowAnonymous = true; + } + else if (strcmp (serverAuthMode, "user") == 0) + { + if (idx + 2 > argc) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Server auth mode 'user' requires " + " "); + return EXIT_FAILURE; + } + serverAllowAnonymous = false; + serverUsername = argv[idx++]; + serverPassword = argv[idx++]; + } + else + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Unknown server auth mode: %s " + "(expected 'anonymous' or 'user')", + serverAuthMode); + return EXIT_FAILURE; + } + + /* Parse client-side auth mode (how this server authenticates to the + LDS when registering). */ + if (idx >= argc) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Missing client auth mode"); + return EXIT_FAILURE; + } + const char *clientAuthMode = argv[idx++]; + char *clientUsername = NULL, *clientPassword = NULL; + + if (strcmp (clientAuthMode, "anonymous") == 0) + { + /* No extra args needed */ + } + else if (strcmp (clientAuthMode, "user") == 0) + { + if (idx + 2 > argc) + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Client auth mode 'user' requires " + " "); + return EXIT_FAILURE; + } + clientUsername = argv[idx++]; + clientPassword = argv[idx++]; + } + else + { + UA_LOG_FATAL (UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "Unknown client auth mode: %s " + "(expected 'anonymous' or 'user')", + clientAuthMode); + return EXIT_FAILURE; + } + + size_t trustSize = (idx < argc) ? (size_t)(argc - idx) : 0; UA_StatusCode retval; UA_Server *server = createSecureServer ( - port, applicationUri, argv[3], argv[4], argv + 11, trustSize, &retval); + port, applicationUri, argv[3], argv[4], argv + idx, trustSize, &retval); if (!server) return EXIT_FAILURE; UA_ServerConfig *serverConfig = UA_Server_getConfig (server); - /* Disallow anonymous sessions. + /* Configure access control after server creation because UA_ServerConfig_setDefaultWithSecurityPolicies (called by - createSecureServer) resets access control, so this must come after server - creation. The static credential list is deep-copied. */ - UA_UsernamePasswordLogin logins[] - = { { UA_STRING_STATIC ("user"), UA_STRING_STATIC ("password") } }; - retval = UA_AccessControl_default (serverConfig, false, NULL, 1, logins); - if (retval != UA_STATUSCODE_GOOD) + createSecureServer) resets the access control plugin. The credential + list is deep-copied by UA_AccessControl_default. */ + if (!serverAllowAnonymous) { - UA_Server_delete (server); - return EXIT_FAILURE; + UA_UsernamePasswordLogin logins[1]; + logins[0].username = UA_STRING (serverUsername); + logins[0].password = UA_STRING (serverPassword); + retval = UA_AccessControl_default (serverConfig, false, NULL, 1, logins); + if (retval != UA_STATUSCODE_GOOD) + { + UA_Server_delete (server); + return EXIT_FAILURE; + } } serverConfig->applicationDescription.applicationType @@ -117,7 +194,7 @@ main (int argc, char **argv) UA_ClientConfig clientConfig; memset (&clientConfig, 0, sizeof (UA_ClientConfig)); retval = createSecureClientConfig ( - &clientConfig, applicationUri, clientCertPath, clientKeyPath, argv + 11, + &clientConfig, applicationUri, clientCertPath, clientKeyPath, argv + idx, trustSize, securityMode, securityPolicyUri); if (retval != UA_STATUSCODE_GOOD) { @@ -125,8 +202,9 @@ main (int argc, char **argv) UA_Server_delete (server); return EXIT_FAILURE; } - UA_ClientConfig_setAuthenticationUsername (&clientConfig, "user", - "password"); + if (clientUsername) + UA_ClientConfig_setAuthenticationUsername (&clientConfig, clientUsername, + clientPassword); UA_String discoveryUrl = UA_STRING_ALLOC (discoveryEndpoint); retval = UA_Server_registerDiscovery (server, &clientConfig, discoveryUrl, @@ -149,11 +227,12 @@ main (int argc, char **argv) memset (&clientConfig, 0, sizeof (UA_ClientConfig)); retval = createSecureClientConfig ( &clientConfig, applicationUri, clientCertPath, clientKeyPath, - argv + 11, trustSize, securityMode, securityPolicyUri); + argv + idx, trustSize, securityMode, securityPolicyUri); if (retval == UA_STATUSCODE_GOOD) { - UA_ClientConfig_setAuthenticationUsername (&clientConfig, "user", - "password"); + if (clientUsername) + UA_ClientConfig_setAuthenticationUsername ( + &clientConfig, clientUsername, clientPassword); UA_String reregUrl = UA_STRING_ALLOC (discoveryEndpoint); retval = UA_Server_registerDiscovery (server, &clientConfig, reregUrl, UA_STRING_NULL); @@ -169,12 +248,13 @@ main (int argc, char **argv) memset (&clientConfig, 0, sizeof (UA_ClientConfig)); retval = createSecureClientConfig ( - &clientConfig, applicationUri, clientCertPath, clientKeyPath, argv + 11, + &clientConfig, applicationUri, clientCertPath, clientKeyPath, argv + idx, trustSize, securityMode, securityPolicyUri); if (retval == UA_STATUSCODE_GOOD) { - UA_ClientConfig_setAuthenticationUsername (&clientConfig, "user", - "password"); + if (clientUsername) + UA_ClientConfig_setAuthenticationUsername ( + &clientConfig, clientUsername, clientPassword); UA_String deregUrl = UA_STRING_ALLOC (discoveryEndpoint); retval = UA_Server_deregisterDiscovery (server, &clientConfig, deregUrl); UA_String_clear (&deregUrl); -- cgit v1.2.3