Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/1.4' into merge_14_master_23
Browse files Browse the repository at this point in the history
  • Loading branch information
jpfr committed Nov 6, 2024
2 parents 2b445ae + 1626459 commit c5b39c9
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 55 deletions.
3 changes: 3 additions & 0 deletions src/server/ua_server_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,9 @@ UA_ServerComponent * UA_BinaryProtocolManager_new(UA_Server *server);
UA_ServerComponent * UA_PubSubManager_new(UA_Server *server);
#endif

UA_String
securityPolicyUriPostfix(const UA_String uri);

/***********/
/* RefTree */
/***********/
Expand Down
68 changes: 41 additions & 27 deletions src/server/ua_services_discovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,18 +294,17 @@ getDefaultEncryptedSecurityPolicy(UA_Server *server) {
if(!UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &sp->policyUri))
return sp;
}
return server->config.securityPoliciesSize > 0 ?
&server->config.securityPolicies[0] : NULL;
return NULL; /* No encrypted policy found */
}

const char *securityModeStrs[4] = {"-invalid", "-none", "-sign", "-sign+encrypt"};

static UA_String
UA_String
securityPolicyUriPostfix(const UA_String uri) {
for(size_t i = 0; i < uri.length; i++) {
if(uri.data[i] != '#')
for(UA_Byte *b = uri.data + uri.length - 1; b >= uri.data; b--) {
if(*b != '#')
continue;
UA_String postfix = {uri.length - i, &uri.data[i]};
UA_String postfix = {uri.length - (size_t)(b - uri.data), b};
return postfix;
}
return uri;
Expand All @@ -321,30 +320,45 @@ updateEndpointUserIdentityToken(UA_Server *server, UA_EndpointDescription *ed) {
/* Copy the UserTokenPolicies from the AccessControl plugin, but only the matching ones to the securityPolicyUri.
* TODO: Different instances of the AccessControl plugin per Endpoint */
UA_StatusCode res = UA_STATUSCODE_GOOD;
for(size_t i = 0; i < server->config.accessControl.userTokenPoliciesSize; i++) {
UA_UserTokenPolicy *utp = &server->config.accessControl.userTokenPolicies[i];
if(UA_String_equal(&ed->securityPolicyUri, &utp->securityPolicyUri)) {
res = UA_Array_appendCopy((void**)&ed->userIdentityTokens,
&ed->userIdentityTokensSize,
utp,
&UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
if(res != UA_STATUSCODE_GOOD)
return res;
}
}

for(size_t i = 0; i < ed->userIdentityTokensSize; i++) {
/* Use the securityPolicy of the SecureChannel. But not if the
* SecureChannel is unencrypted and there is a non-anonymous token. */
UA_UserTokenPolicy *utp = &ed->userIdentityTokens[i];
UA_ServerConfig *sc = &server->config;
for(size_t i = 0; i < sc->accessControl.userTokenPoliciesSize; i++) {
UA_UserTokenPolicy *utp = &sc->accessControl.userTokenPolicies[i];
res = UA_Array_appendCopy((void**)&ed->userIdentityTokens,
&ed->userIdentityTokensSize, utp,
&UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
if(res != UA_STATUSCODE_GOOD)
return res;

/* Select the SecurityPolicy for the UserTokenType.
* If not set, the SecurityPolicy of the SecureChannel is used. */
utp = &ed->userIdentityTokens[ed->userIdentityTokensSize - 1];
UA_String_clear(&utp->securityPolicyUri);
if((!server->config.allowNonePolicyPassword || ed->userIdentityTokens[i].tokenType != UA_USERTOKENTYPE_USERNAME) &&
UA_String_equal(&ed->securityPolicyUri, &UA_SECURITY_POLICY_NONE_URI) &&
utp->tokenType != UA_USERTOKENTYPE_ANONYMOUS) {
#ifdef UA_ENABLE_ENCRYPTION
/* Anonymous tokens don't need encryption. All other tokens require
* encryption with the exception of Username/Password if also the
* allowNonePolicyPassword option has been set. The same logic is used
* in selectEndpointAndTokenPolicy (ua_services_session.c). */
if(utp->tokenType != UA_USERTOKENTYPE_ANONYMOUS &&
!(sc->allowNonePolicyPassword && utp->tokenType == UA_USERTOKENTYPE_USERNAME) &&
UA_String_equal(&ed->securityPolicyUri, &UA_SECURITY_POLICY_NONE_URI)) {
UA_SecurityPolicy *encSP = getDefaultEncryptedSecurityPolicy(server);
if(encSP)
res |= UA_String_copy(&encSP->policyUri, &utp->securityPolicyUri);
if(!encSP) {
/* No encrypted SecurityPolicy available */
UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_CLIENT,
"Removing a UserTokenPolicy that would allow the "
"password to be transmitted without encryption "
"(Can be enabled via config->allowNonePolicyPassword)");
UA_StatusCode res2 =
UA_Array_resize((void **)&ed->userIdentityTokens,
&ed->userIdentityTokensSize,
ed->userIdentityTokensSize - 1,
&UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
(void)res2;
continue;
}
res |= UA_String_copy(&encSP->policyUri, &utp->securityPolicyUri);
}
#endif

/* Append the SecurityMode and SecurityPolicy postfix to the PolicyId to
* make it unique */
Expand Down
73 changes: 45 additions & 28 deletions src/server/ua_services_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,9 @@ selectEndpointAndTokenPolicy(UA_Server *server, UA_SecureChannel *channel,
const UA_EndpointDescription **ed,
const UA_UserTokenPolicy **utp,
const UA_SecurityPolicy **tokenSp) {
for(size_t i = 0; i < server->config.endpointsSize; ++i) {
const UA_EndpointDescription *desc = &server->config.endpoints[i];
UA_ServerConfig *sc = &server->config;
for(size_t i = 0; i < sc->endpointsSize; ++i) {
const UA_EndpointDescription *desc = &sc->endpoints[i];

/* Match the Security Mode */
if(desc->securityMode != channel->securityMode)
Expand All @@ -464,8 +465,8 @@ selectEndpointAndTokenPolicy(UA_Server *server, UA_SecureChannel *channel,
size_t identPoliciesSize = desc->userIdentityTokensSize;
const UA_UserTokenPolicy *identPolicies = desc->userIdentityTokens;
if(identPoliciesSize == 0) {
identPoliciesSize = server->config.accessControl.userTokenPoliciesSize;
identPolicies = server->config.accessControl.userTokenPolicies;
identPoliciesSize = sc->accessControl.userTokenPoliciesSize;
identPolicies = sc->accessControl.userTokenPolicies;
}

/* Match the UserTokenType */
Expand Down Expand Up @@ -506,37 +507,53 @@ selectEndpointAndTokenPolicy(UA_Server *server, UA_SecureChannel *channel,
UA_AnonymousIdentityToken *token = (UA_AnonymousIdentityToken*)
identityToken->content.decoded.data;

/* In setCurrentEndPointsArray we prepend the policyId with the
* security mode to make it unique. Remove that here. */
/* Select the SecurityPolicy used to encrypt the token.
* The default is to use the SecurityPolicy of the SecureChannel. */
*tokenSp = channel->securityPolicy;
#ifdef UA_ENABLE_ENCRYPTION
if(identPolicies == sc->accessControl.userTokenPolicies) {
/* If the standard UserTokenPolicies from the AccessControl
* plugin are used, use the same logic as in
* updateEndpointUserIdentityToken (ua_services_discovery.c). */
if(pol->tokenType != UA_USERTOKENTYPE_ANONYMOUS &&
!(sc->allowNonePolicyPassword && pol->tokenType == UA_USERTOKENTYPE_USERNAME) &&
UA_String_equal(&channel->securityPolicy->policyUri, &UA_SECURITY_POLICY_NONE_URI))
*tokenSp = getDefaultEncryptedSecurityPolicy(server);
} else if(pol->securityPolicyUri.length > 0) {
/* Manually defined UserTokenPolicy. Lookup by URI */
*tokenSp = getSecurityPolicyByUri(server, &pol->securityPolicyUri);
}
if(!*tokenSp)
continue;

/* Anonymous tokens don't need encryption. All other tokens require
* encryption with the exception of Username/Password if also the
* allowNonePolicyPassword option has been set. */
if(pol->tokenType != UA_USERTOKENTYPE_ANONYMOUS &&
!(sc->allowNonePolicyPassword && pol->tokenType == UA_USERTOKENTYPE_USERNAME) &&
UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &(*tokenSp)->policyUri))
continue;
#endif

/* In setCurrentEndPointsArray we prepend the PolicyId with the
* SecurityMode of the endpoint and the postfix of the
* SecurityPolicyUri to make it unique. Check the SecurityPolicyUri
* postfix. */
if(pol->policyId.length > token->policyId.length)
continue;
UA_String tmpId = token->policyId;
tmpId.length = pol->policyId.length;
if(!UA_String_equal(&tmpId, &pol->policyId))
UA_String policyPrefix = token->policyId;
policyPrefix.length = pol->policyId.length;
if(!UA_String_equal(&policyPrefix, &pol->policyId))
continue;

UA_String secPolPostfix = securityPolicyUriPostfix((*tokenSp)->policyUri);
UA_String utPolPostfix = securityPolicyUriPostfix(token->policyId);
if(!UA_String_equal(&secPolPostfix, &utPolPostfix))
continue;

/* Match found */
*ed = desc;
*utp = pol;

/* Set the SecurityPolicy used to encrypt the token. If the
* userTokenPolicy doesn't specify a security policy the security
* policy of the secure channel is used. */
*tokenSp = channel->securityPolicy;
if(pol->securityPolicyUri.length > 0)
*tokenSp = getSecurityPolicyByUri(server, &pol->securityPolicyUri);

/* If the server does not allow unencrypted passwords, select the
* default encrypted policy for the UserTokenPolicy */
#ifdef UA_ENABLE_ENCRYPTION
if(!*tokenSp ||
(!server->config.allowNonePolicyPassword &&
((*tokenSp)->localCertificate.length == 0 ||
UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &(*tokenSp)->policyUri))))
*tokenSp = getDefaultEncryptedSecurityPolicy(server);
#endif

/* Found SecurityPolicy and UserTokenPoliy. Stop here. */
return;
}
}
Expand Down
3 changes: 3 additions & 0 deletions tests/client/check_activateSession.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ START_TEST(Client_activateSession) {
END_TEST

START_TEST(Client_activateSession_username) {
UA_ServerConfig *sc = UA_Server_getConfig(server);
sc->allowNonePolicyPassword = true;

UA_Client *client = UA_Client_newForUnitTest();
UA_ClientConfig *config = UA_Client_getConfig(client);
config->sessionLocaleIdsSize = 2;
Expand Down
1 change: 1 addition & 0 deletions tests/client/check_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static void setup(void) {
UA_SecurityPolicy *sp = &config->securityPolicies[config->securityPoliciesSize-1];
UA_AccessControl_default(config, true, &sp->policyUri,
usernamePasswordsSize, usernamePasswords);
config->allowNonePolicyPassword = true;

UA_Server_run_startup(server);
addVariable(VARLENGTH);
Expand Down
3 changes: 3 additions & 0 deletions tests/server/check_accesscontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ static void setup(void) {
server = UA_Server_newForUnitTest();
ck_assert(server != NULL);

UA_ServerConfig *sc = UA_Server_getConfig(server);
sc->allowNonePolicyPassword = true;

/* Instatiate a new AccessControl plugin that knows username/pw */
UA_ServerConfig *config = UA_Server_getConfig(server);
UA_SecurityPolicy *sp = &config->securityPolicies[config->securityPoliciesSize-1];
Expand Down
1 change: 1 addition & 0 deletions tests/server/check_server_password.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ static void setup(void) {
server = UA_Server_newForUnitTest();
ck_assert_msg(server, "UA_Server_new");
UA_ServerConfig *config = UA_Server_getConfig(server);
config->allowNonePolicyPassword = true;
UA_String policy = UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#None");
UA_UsernamePasswordLogin login[] = {
{ UA_STRING_STATIC("user"),
Expand Down

0 comments on commit c5b39c9

Please sign in to comment.