ports/misc/open62541/patches/patch-plugins_ua_accesscontrol_default_c

73 lines
3.2 KiB
Text

https://github.com/open62541/open62541/pull/5935
https://github.com/open62541/open62541/commit/f4b481276a9144da2a3bd9f67026751885fd803e
feat(plugin): allow custom password validation
Username password validation in access control plugin allows only
passwords stored in plaintext. Add a callback to implement custom
validation. This allows salted password hashes and timing safe
comparison in the server. Furthermore remote validation could be
implemented. The new function UA_AccessControl_defaultWithLoginCallback()
calls existing UA_AccessControl_default() and after that installs
the given UA_UsernamePasswordLoginCallback with context.
Index: plugins/ua_accesscontrol_default.c
--- plugins/ua_accesscontrol_default.c.orig
+++ plugins/ua_accesscontrol_default.c
@@ -21,6 +21,8 @@ typedef struct {
UA_Boolean allowAnonymous;
size_t usernamePasswordLoginSize;
UA_UsernamePasswordLogin *usernamePasswordLogin;
+ UA_UsernamePasswordLoginCallback loginCallback;
+ void *loginContext;
UA_CertificateVerification verifyX509;
} AccessControlContext;
@@ -95,11 +97,18 @@ activateSession_default(UA_Server *server, UA_AccessCo
/* Try to match username/pw */
UA_Boolean match = false;
- for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
- if(UA_String_equal(&userToken->userName, &context->usernamePasswordLogin[i].username) &&
- UA_String_equal(&userToken->password, &context->usernamePasswordLogin[i].password)) {
+ if(context->loginCallback) {
+ if(context->loginCallback(&userToken->userName, &userToken->password,
+ context->usernamePasswordLoginSize, context->usernamePasswordLogin,
+ sessionContext, context->loginContext) == UA_STATUSCODE_GOOD)
match = true;
- break;
+ } else {
+ for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
+ if(UA_String_equal(&userToken->userName, &context->usernamePasswordLogin[i].username) &&
+ UA_String_equal(&userToken->password, &context->usernamePasswordLogin[i].password)) {
+ match = true;
+ break;
+ }
}
}
if(!match)
@@ -399,3 +408,24 @@ UA_AccessControl_default(UA_ServerConfig *config,
return UA_STATUSCODE_GOOD;
}
+UA_StatusCode
+UA_AccessControl_defaultWithLoginCallback(UA_ServerConfig *config,
+ UA_Boolean allowAnonymous, UA_CertificateVerification *verifyX509,
+ const UA_ByteString *userTokenPolicyUri, size_t usernamePasswordLoginSize,
+ const UA_UsernamePasswordLogin *usernamePasswordLogin,
+ UA_UsernamePasswordLoginCallback loginCallback, void *loginContext)
+{
+ AccessControlContext *context;
+ UA_StatusCode sc;
+
+ sc = UA_AccessControl_default(config, allowAnonymous, verifyX509,
+ userTokenPolicyUri, usernamePasswordLoginSize, usernamePasswordLogin);
+ if (sc != UA_STATUSCODE_GOOD)
+ return sc;
+
+ context = (AccessControlContext *)config->accessControl.context;
+ context->loginCallback = loginCallback;
+ context->loginContext = loginContext;
+
+ return UA_STATUSCODE_GOOD;
+}