Coverage Report

Created: 2026-05-16 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/plugins/ua_accesscontrol_default.c
Line
Count
Source
1
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
2
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
3
 *
4
 *    Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
5
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
6
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
7
 */
8
9
#include <open62541/plugin/accesscontrol_default.h>
10
11
/* Example access control management. Anonymous and username / password login.
12
 * The access rights are maximally permissive.
13
 *
14
 * FOR PRODUCTION USE, THIS EXAMPLE PLUGIN SHOULD BE REPLACED WITH LESS
15
 * PERMISSIVE ACCESS CONTROL.
16
 *
17
 * For TransferSubscriptions, we check whether the transfer happens between
18
 * Sessions for the same user. */
19
20
typedef struct {
21
    UA_Boolean allowAnonymous;
22
    size_t usernamePasswordLoginSize;
23
    UA_UsernamePasswordLogin *usernamePasswordLogin;
24
    UA_UsernamePasswordLoginCallback loginCallback;
25
    void *loginContext;
26
    UA_CertificateGroup verifyX509;
27
} AccessControlContext;
28
29
#define ANONYMOUS_POLICY "open62541-anonymous-policy"
30
#define CERTIFICATE_POLICY "open62541-certificate-policy"
31
#define USERNAME_POLICY "open62541-username-policy"
32
33
/************************/
34
/* Access Control Logic */
35
/************************/
36
37
static UA_StatusCode
38
activateSession_default(UA_Server *server, UA_AccessControl *ac,
39
                        const UA_EndpointDescription *endpointDescription,
40
                        const UA_ByteString *secureChannelRemoteCertificate,
41
                        const UA_NodeId *sessionId,
42
                        const UA_ExtensionObject *userIdentityToken,
43
0
                        void **sessionContext) {
44
0
    AccessControlContext *context = (AccessControlContext*)ac->context;
45
46
    /* The empty token is interpreted as anonymous */
47
0
    UA_AnonymousIdentityToken anonToken;
48
0
    UA_ExtensionObject tmpIdentity;
49
0
    if(userIdentityToken->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
50
0
        UA_AnonymousIdentityToken_init(&anonToken);
51
0
        UA_ExtensionObject_init(&tmpIdentity);
52
0
        UA_ExtensionObject_setValueNoDelete(&tmpIdentity,
53
0
                                            &anonToken,
54
0
                                            &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]);
55
0
        userIdentityToken = &tmpIdentity;
56
0
    }
57
58
    /* Could the token be decoded? */
59
0
    if(userIdentityToken->encoding < UA_EXTENSIONOBJECT_DECODED)
60
0
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
61
62
0
    const UA_DataType *tokenType = userIdentityToken->content.decoded.type;
63
0
    if(tokenType == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
64
        /* Anonymous login */
65
0
        if(!context->allowAnonymous)
66
0
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
67
0
    } else if(tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
68
        /* Username and password */
69
0
        const UA_UserNameIdentityToken *userToken = (UA_UserNameIdentityToken*)
70
0
            userIdentityToken->content.decoded.data;
71
72
        /* Empty username and password */
73
0
        if(userToken->userName.length == 0 && userToken->password.length == 0)
74
0
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
75
76
        /* Try to match username/pw */
77
0
        if(context->loginCallback) {
78
            /* Configured callback */
79
0
            UA_StatusCode res =
80
0
                context->loginCallback(&userToken->userName, &userToken->password,
81
0
                                       context->usernamePasswordLoginSize,
82
0
                                       context->usernamePasswordLogin,
83
0
                                       sessionContext, context->loginContext);
84
0
            if(res != UA_STATUSCODE_GOOD)
85
0
                return UA_STATUSCODE_BADUSERACCESSDENIED;
86
0
        } else {
87
            /* Compare against the configured list  */
88
0
            UA_Boolean match = false;
89
0
            for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
90
0
                UA_UsernamePasswordLogin *upl = &context->usernamePasswordLogin[i];
91
0
                if(!UA_String_equal(&userToken->userName, &upl->username))
92
0
                   continue;
93
0
                if(userToken->password.length != upl->password.length)
94
0
                    continue;
95
0
                if(!UA_constantTimeEqual(userToken->password.data,
96
0
                                         upl->password.data,
97
0
                                         upl->password.length))
98
0
                    continue;
99
0
                match = true;
100
0
                break;
101
0
            }
102
0
            if(!match)
103
0
                return UA_STATUSCODE_BADUSERACCESSDENIED;
104
0
        }
105
0
    } else if(tokenType == &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) {
106
        /* x509 certificate was already validated against the sessionPKI in the
107
         * server */
108
0
    } else {
109
        /* Unsupported token type */
110
0
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
111
0
    }
112
113
    /* Store the endpoint's SecurityPolicyUri as a custom session attribute.
114
     * This is needed later in allowTransferSubscription_default to determine
115
     * whether the session was established over a secure channel. */
116
0
    if(endpointDescription) {
117
0
        UA_Variant spUri;
118
0
        UA_Variant_setScalar(&spUri, (void*)(uintptr_t)&endpointDescription->securityPolicyUri,
119
0
                             &UA_TYPES[UA_TYPES_STRING]);
120
0
        UA_Server_setSessionAttribute(server, sessionId,
121
0
                                      UA_QUALIFIEDNAME(0, "channelSecurityPolicyUri"),
122
0
                                      &spUri);
123
0
    }
124
125
0
    return UA_STATUSCODE_GOOD;
126
0
}
127
128
static void
129
closeSession_default(UA_Server *server, UA_AccessControl *ac,
130
0
                     const UA_NodeId *sessionId, void *sessionContext) {
131
0
}
132
133
static UA_UInt32
134
getUserRightsMask_default(UA_Server *server, UA_AccessControl *ac,
135
                          const UA_NodeId *sessionId, void *sessionContext,
136
0
                          const UA_NodeId *nodeId, void *nodeContext) {
137
0
    return 0xFFFFFFFF;
138
0
}
139
140
static UA_Byte
141
getUserAccessLevel_default(UA_Server *server, UA_AccessControl *ac,
142
                           const UA_NodeId *sessionId, void *sessionContext,
143
0
                           const UA_NodeId *nodeId, void *nodeContext) {
144
0
    return 0xFF;
145
0
}
146
147
static UA_Boolean
148
getUserExecutable_default(UA_Server *server, UA_AccessControl *ac,
149
                          const UA_NodeId *sessionId, void *sessionContext,
150
0
                          const UA_NodeId *methodId, void *methodContext) {
151
0
    return true;
152
0
}
153
154
static UA_Boolean
155
getUserExecutableOnObject_default(UA_Server *server, UA_AccessControl *ac,
156
                                  const UA_NodeId *sessionId, void *sessionContext,
157
                                  const UA_NodeId *methodId, void *methodContext,
158
0
                                  const UA_NodeId *objectId, void *objectContext) {
159
0
    return true;
160
0
}
161
162
static UA_Boolean
163
allowAddNode_default(UA_Server *server, UA_AccessControl *ac,
164
                     const UA_NodeId *sessionId, void *sessionContext,
165
0
                     const UA_AddNodesItem *item) {
166
0
    return true;
167
0
}
168
169
static UA_Boolean
170
allowAddReference_default(UA_Server *server, UA_AccessControl *ac,
171
                          const UA_NodeId *sessionId, void *sessionContext,
172
0
                          const UA_AddReferencesItem *item) {
173
0
    return true;
174
0
}
175
176
static UA_Boolean
177
allowDeleteNode_default(UA_Server *server, UA_AccessControl *ac,
178
                        const UA_NodeId *sessionId, void *sessionContext,
179
0
                        const UA_DeleteNodesItem *item) {
180
0
    return true;
181
0
}
182
183
static UA_Boolean
184
allowDeleteReference_default(UA_Server *server, UA_AccessControl *ac,
185
                             const UA_NodeId *sessionId, void *sessionContext,
186
0
                             const UA_DeleteReferencesItem *item) {
187
0
    return true;
188
0
}
189
190
static UA_Boolean
191
allowBrowseNode_default(UA_Server *server, UA_AccessControl *ac,
192
                        const UA_NodeId *sessionId, void *sessionContext,
193
0
                        const UA_NodeId *nodeId, void *nodeContext) {
194
0
    return true;
195
0
}
196
197
#ifdef UA_ENABLE_SUBSCRIPTIONS
198
static UA_Boolean
199
allowTransferSubscription_default(UA_Server *server, UA_AccessControl *ac,
200
                                  const UA_NodeId *oldSessionId, void *oldSessionContext,
201
0
                                  const UA_NodeId *newSessionId, void *newSessionContext) {
202
0
    if(!oldSessionId)
203
0
        return true;
204
    
205
    /* Get clientUserId for both sessions */
206
0
    UA_Variant session1UserId;
207
0
    UA_Variant_init(&session1UserId);
208
0
    UA_Server_getSessionAttribute(server, oldSessionId,
209
0
                                  UA_QUALIFIEDNAME(0, "clientUserId"),
210
0
                                  &session1UserId);
211
0
    UA_Variant session2UserId;
212
0
    UA_Variant_init(&session2UserId);
213
0
    UA_Server_getSessionAttribute(server, newSessionId,
214
0
                                  UA_QUALIFIEDNAME(0, "clientUserId"),
215
0
                                  &session2UserId);
216
217
    /* clientUserId is always a String type */
218
0
    UA_Boolean result = false;
219
0
    if(session1UserId.type == &UA_TYPES[UA_TYPES_STRING] &&
220
0
       session2UserId.type == &UA_TYPES[UA_TYPES_STRING]) {
221
0
        UA_String *userId1 = (UA_String*)session1UserId.data;
222
0
        UA_String *userId2 = (UA_String*)session2UserId.data;
223
        
224
0
        if(userId1->length == 0 && userId2->length == 0) {
225
            /* Both users are anonymous.
226
             * For anonymous users, the OPC UA specification requires
227
             * checking the ApplicationUri from the clientDescription
228
             * to verify that the same application is transferring the
229
             * subscription (e.g. after a network interruption or client
230
             * crash with reconnect on a different SecureChannel).
231
             *
232
             * Additionally, on unsecure connections (SecurityPolicy#None)
233
             * the ApplicationUri is not verified against a certificate,
234
             * so the transfer must be rejected. */
235
236
            /* First check: Both sessions must use a secure channel
237
             * (not SecurityPolicy#None). The securityPolicyUri was
238
             * stored as a session attribute during ActivateSession. */
239
0
            UA_Variant session1SpUri;
240
0
            UA_Variant_init(&session1SpUri);
241
0
            UA_Server_getSessionAttribute(server, oldSessionId,
242
0
                                          UA_QUALIFIEDNAME(0, "channelSecurityPolicyUri"),
243
0
                                          &session1SpUri);
244
0
            UA_Variant session2SpUri;
245
0
            UA_Variant_init(&session2SpUri);
246
0
            UA_Server_getSessionAttribute(server, newSessionId,
247
0
                                          UA_QUALIFIEDNAME(0, "channelSecurityPolicyUri"),
248
0
                                          &session2SpUri);
249
250
0
            UA_Boolean bothSecure = false;
251
0
            if(session1SpUri.type == &UA_TYPES[UA_TYPES_STRING] &&
252
0
               session2SpUri.type == &UA_TYPES[UA_TYPES_STRING]) {
253
0
                UA_String *spUri1 = (UA_String*)session1SpUri.data;
254
0
                UA_String *spUri2 = (UA_String*)session2SpUri.data;
255
                /* Reject if either session uses SecurityPolicy#None */
256
0
                if(!UA_String_equal(spUri1, &UA_SECURITY_POLICY_NONE_URI) &&
257
0
                   !UA_String_equal(spUri2, &UA_SECURITY_POLICY_NONE_URI)) {
258
0
                    bothSecure = true;
259
0
                }
260
0
            }
261
262
0
            UA_Variant_clear(&session1SpUri);
263
0
            UA_Variant_clear(&session2SpUri);
264
265
            /* Second check: If both channels are secure, compare the
266
             * ApplicationUri from the clientDescription. On secure
267
             * connections the ApplicationUri is validated against
268
             * the client certificate during CreateSession. */
269
0
            if(bothSecure) {
270
0
                UA_Variant session1Desc;
271
0
                UA_Variant_init(&session1Desc);
272
0
                UA_Server_getSessionAttribute(server, oldSessionId,
273
0
                                              UA_QUALIFIEDNAME(0, "clientDescription"),
274
0
                                              &session1Desc);
275
0
                UA_Variant session2Desc;
276
0
                UA_Variant_init(&session2Desc);
277
0
                UA_Server_getSessionAttribute(server, newSessionId,
278
0
                                              UA_QUALIFIEDNAME(0, "clientDescription"),
279
0
                                              &session2Desc);
280
281
0
                if(session1Desc.type == &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION] &&
282
0
                   session2Desc.type == &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]) {
283
0
                    UA_ApplicationDescription *desc1 =
284
0
                        (UA_ApplicationDescription*)session1Desc.data;
285
0
                    UA_ApplicationDescription *desc2 =
286
0
                        (UA_ApplicationDescription*)session2Desc.data;
287
0
                    if(desc1->applicationUri.length > 0 &&
288
0
                       desc2->applicationUri.length > 0 &&
289
0
                       UA_String_equal(&desc1->applicationUri,
290
0
                                       &desc2->applicationUri)) {
291
0
                        result = true;
292
0
                    }
293
0
                }
294
295
0
                UA_Variant_clear(&session1Desc);
296
0
                UA_Variant_clear(&session2Desc);
297
0
            }
298
0
        } else if(UA_String_equal(userId1, userId2)) {
299
            /* Same authenticated user - allow transfer */
300
0
            result = true;
301
0
        }
302
0
    }
303
    
304
0
    UA_Variant_clear(&session1UserId);
305
0
    UA_Variant_clear(&session2UserId);
306
    
307
0
    return result;
308
0
}
309
#endif
310
311
#ifdef UA_ENABLE_HISTORIZING
312
static UA_Boolean
313
allowHistoryUpdateUpdateData_default(UA_Server *server, UA_AccessControl *ac,
314
                                     const UA_NodeId *sessionId, void *sessionContext,
315
                                     const UA_NodeId *nodeId,
316
                                     UA_PerformUpdateType performInsertReplace,
317
0
                                     const UA_DataValue *value) {
318
0
    return true;
319
0
}
320
321
static UA_Boolean
322
allowHistoryUpdateDeleteRawModified_default(UA_Server *server, UA_AccessControl *ac,
323
                                            const UA_NodeId *sessionId, void *sessionContext,
324
                                            const UA_NodeId *nodeId,
325
                                            UA_DateTime startTimestamp,
326
                                            UA_DateTime endTimestamp,
327
0
                                            bool isDeleteModified) {
328
0
    return true;
329
0
}
330
#endif
331
332
/***************************************/
333
/* Create Delete Access Control Plugin */
334
/***************************************/
335
336
8.00k
static void clear_default(UA_AccessControl *ac) {
337
8.00k
    UA_Array_delete((void*)(uintptr_t)ac->userTokenPolicies,
338
8.00k
                    ac->userTokenPoliciesSize,
339
8.00k
                    &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
340
8.00k
    ac->userTokenPolicies = NULL;
341
8.00k
    ac->userTokenPoliciesSize = 0;
342
343
8.00k
    AccessControlContext *context = (AccessControlContext*)ac->context;
344
345
8.00k
    if (context) {
346
8.00k
        for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
347
0
            UA_String_clear(&context->usernamePasswordLogin[i].username);
348
0
            UA_ByteString_clear(&context->usernamePasswordLogin[i].password);
349
0
        }
350
8.00k
        if(context->usernamePasswordLoginSize > 0)
351
0
            UA_free(context->usernamePasswordLogin);
352
353
8.00k
        UA_free(ac->context);
354
8.00k
        ac->context = NULL;
355
8.00k
    }
356
8.00k
}
357
358
UA_StatusCode
359
UA_AccessControl_default(UA_ServerConfig *config,
360
                         UA_Boolean allowAnonymous,
361
                         const UA_String *userTokenPolicyUri,
362
                         size_t usernamePasswordLoginSize,
363
8.00k
                         const UA_UsernamePasswordLogin *usernamePasswordLogin) {
364
8.00k
    UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
365
8.00k
                   "AccessControl: Unconfigured AccessControl. Users have all permissions.");
366
8.00k
    UA_AccessControl *ac = &config->accessControl;
367
368
8.00k
    if(ac->clear)
369
0
        ac->clear(ac);
370
371
8.00k
    ac->clear = clear_default;
372
8.00k
    ac->activateSession = activateSession_default;
373
8.00k
    ac->closeSession = closeSession_default;
374
8.00k
    ac->getUserRightsMask = getUserRightsMask_default;
375
8.00k
    ac->getUserAccessLevel = getUserAccessLevel_default;
376
8.00k
    ac->getUserExecutable = getUserExecutable_default;
377
8.00k
    ac->getUserExecutableOnObject = getUserExecutableOnObject_default;
378
8.00k
    ac->allowAddNode = allowAddNode_default;
379
8.00k
    ac->allowAddReference = allowAddReference_default;
380
8.00k
    ac->allowBrowseNode = allowBrowseNode_default;
381
382
8.00k
#ifdef UA_ENABLE_SUBSCRIPTIONS
383
8.00k
    ac->allowTransferSubscription = allowTransferSubscription_default;
384
8.00k
#endif
385
386
8.00k
#ifdef UA_ENABLE_HISTORIZING
387
8.00k
    ac->allowHistoryUpdateUpdateData = allowHistoryUpdateUpdateData_default;
388
8.00k
    ac->allowHistoryUpdateDeleteRawModified = allowHistoryUpdateDeleteRawModified_default;
389
8.00k
#endif
390
391
8.00k
    ac->allowDeleteNode = allowDeleteNode_default;
392
8.00k
    ac->allowDeleteReference = allowDeleteReference_default;
393
394
8.00k
    AccessControlContext *context = (AccessControlContext*)
395
8.00k
            UA_malloc(sizeof(AccessControlContext));
396
8.00k
    if(!context)
397
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
398
8.00k
    memset(context, 0, sizeof(AccessControlContext));
399
8.00k
    ac->context = context;
400
401
    /* Allow anonymous? */
402
8.00k
    context->allowAnonymous = allowAnonymous;
403
8.00k
    if(allowAnonymous) {
404
8.00k
        UA_LOG_INFO(config->logging, UA_LOGCATEGORY_SERVER,
405
8.00k
                    "AccessControl: Anonymous login is enabled");
406
8.00k
    }
407
408
    /* Copy username/password to the access control plugin */
409
8.00k
    if(usernamePasswordLoginSize > 0) {
410
0
        context->usernamePasswordLogin = (UA_UsernamePasswordLogin*)
411
0
            UA_malloc(usernamePasswordLoginSize * sizeof(UA_UsernamePasswordLogin));
412
0
        if(!context->usernamePasswordLogin)
413
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
414
0
        context->usernamePasswordLoginSize = usernamePasswordLoginSize;
415
0
        for(size_t i = 0; i < usernamePasswordLoginSize; i++) {
416
0
            UA_String_copy(&usernamePasswordLogin[i].username,
417
0
                           &context->usernamePasswordLogin[i].username);
418
0
            UA_ByteString_copy(&usernamePasswordLogin[i].password,
419
0
                           &context->usernamePasswordLogin[i].password);
420
0
        }
421
0
    }
422
423
8.00k
    size_t numOfPolcies = 1;
424
8.00k
    if(!userTokenPolicyUri) {
425
8.00k
        if(config->securityPoliciesSize > 0)
426
8.00k
            numOfPolcies = config->securityPoliciesSize;
427
0
        else {
428
0
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
429
0
                           "No security policies defined for the secure channel.");
430
0
            return UA_STATUSCODE_BADINTERNALERROR;
431
0
        }
432
8.00k
    }
433
434
    /* Set the allowed policies */
435
8.00k
    size_t policies = 0;
436
8.00k
    if(allowAnonymous)
437
8.00k
        policies++;
438
8.00k
    if(usernamePasswordLoginSize > 0)
439
0
        policies++;
440
8.00k
    if(config->sessionPKI.verifyCertificate)
441
8.00k
        policies++;
442
8.00k
    ac->userTokenPoliciesSize = 0;
443
8.00k
    ac->userTokenPolicies = (UA_UserTokenPolicy *)
444
8.00k
        UA_Array_new(policies * numOfPolcies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
445
8.00k
    if(!ac->userTokenPolicies)
446
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
447
8.00k
    ac->userTokenPoliciesSize = policies * numOfPolcies;
448
449
8.00k
    if(policies == 0) {
450
0
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
451
0
                       "No allowed policies set.");
452
0
        return UA_STATUSCODE_GOOD;
453
0
    }
454
455
8.00k
    const UA_String *utpUri = NULL;
456
8.00k
    policies = 0;
457
16.0k
    for(size_t i = 0; i < numOfPolcies; i++) {
458
8.00k
        if(userTokenPolicyUri) {
459
0
            utpUri = userTokenPolicyUri;
460
8.00k
        } else {
461
8.00k
            utpUri = &config->securityPolicies[i].policyUri;
462
8.00k
        }
463
8.00k
        if(allowAnonymous) {
464
8.00k
            ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_ANONYMOUS;
465
8.00k
            ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY);
466
8.00k
            UA_String_copy(utpUri,
467
8.00k
                               &ac->userTokenPolicies[policies].securityPolicyUri);
468
8.00k
            policies++;
469
8.00k
        }
470
471
8.00k
        if(config->sessionPKI.verifyCertificate) {
472
8.00k
            ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_CERTIFICATE;
473
8.00k
            ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(CERTIFICATE_POLICY);
474
#if UA_LOGLEVEL <= 400
475
            if(UA_String_equal(utpUri, &UA_SECURITY_POLICY_NONE_URI)) {
476
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
477
                               "x509 Certificate Authentication configured, "
478
                               "but no encrypting SecurityPolicy. "
479
                               "This can leak credentials on the network.");
480
            }
481
#endif
482
8.00k
            UA_String_copy(utpUri,
483
8.00k
                               &ac->userTokenPolicies[policies].securityPolicyUri);
484
8.00k
            policies++;
485
8.00k
        }
486
487
8.00k
        if(usernamePasswordLoginSize > 0) {
488
0
            ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_USERNAME;
489
0
            ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(USERNAME_POLICY);
490
#if UA_LOGLEVEL <= 400
491
            if(UA_String_equal(utpUri, &UA_SECURITY_POLICY_NONE_URI)) {
492
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
493
                               "Username/Password Authentication configured, "
494
                               "but no encrypting SecurityPolicy. "
495
                               "This can leak credentials on the network.");
496
            }
497
#endif
498
0
            UA_String_copy(utpUri,
499
0
                               &ac->userTokenPolicies[policies].securityPolicyUri);
500
0
            policies++;
501
0
        }
502
8.00k
    }
503
8.00k
    return UA_STATUSCODE_GOOD;
504
8.00k
}
505
506
UA_StatusCode
507
UA_AccessControl_defaultWithLoginCallback(UA_ServerConfig *config,
508
                                          UA_Boolean allowAnonymous,
509
                                          const UA_String *userTokenPolicyUri,
510
                                          size_t usernamePasswordLoginSize,
511
                                          const UA_UsernamePasswordLogin *usernamePasswordLogin,
512
                                          UA_UsernamePasswordLoginCallback loginCallback,
513
0
                                          void *loginContext) {
514
0
    AccessControlContext *context;
515
0
    UA_StatusCode sc =
516
0
        UA_AccessControl_default(config, allowAnonymous, userTokenPolicyUri,
517
0
                                 usernamePasswordLoginSize, usernamePasswordLogin);
518
0
    if(sc != UA_STATUSCODE_GOOD)
519
0
        return sc;
520
521
0
    context = (AccessControlContext *)config->accessControl.context;
522
0
    context->loginCallback = loginCallback;
523
0
    context->loginContext = loginContext;
524
525
0
    return UA_STATUSCODE_GOOD;
526
0
}
527