ua_accesscontrol_default.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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. */
  7. #include <open62541/plugin/accesscontrol_default.h>
  8. #include <open62541/server_config.h>
  9. /* Example access control management. Anonymous and username / password login.
  10. * The access rights are maximally permissive. */
  11. typedef struct {
  12. UA_Boolean allowAnonymous;
  13. size_t usernamePasswordLoginSize;
  14. UA_UsernamePasswordLogin *usernamePasswordLogin;
  15. } AccessControlContext;
  16. #define ANONYMOUS_POLICY "open62541-anonymous-policy"
  17. #define USERNAME_POLICY "open62541-username-policy"
  18. const UA_String anonymous_policy = UA_STRING_STATIC(ANONYMOUS_POLICY);
  19. const UA_String username_policy = UA_STRING_STATIC(USERNAME_POLICY);
  20. /************************/
  21. /* Access Control Logic */
  22. /************************/
  23. static UA_StatusCode
  24. activateSession_default(UA_Server *server, UA_AccessControl *ac,
  25. const UA_EndpointDescription *endpointDescription,
  26. const UA_ByteString *secureChannelRemoteCertificate,
  27. const UA_NodeId *sessionId,
  28. const UA_ExtensionObject *userIdentityToken,
  29. void **sessionContext) {
  30. AccessControlContext *context = (AccessControlContext*)ac->context;
  31. /* The empty token is interpreted as anonymous */
  32. if(userIdentityToken->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
  33. if(!context->allowAnonymous)
  34. return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
  35. /* No userdata atm */
  36. *sessionContext = NULL;
  37. return UA_STATUSCODE_GOOD;
  38. }
  39. /* Could the token be decoded? */
  40. if(userIdentityToken->encoding < UA_EXTENSIONOBJECT_DECODED)
  41. return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
  42. /* Anonymous login */
  43. if(userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
  44. if(!context->allowAnonymous)
  45. return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
  46. const UA_AnonymousIdentityToken *token = (UA_AnonymousIdentityToken*)
  47. userIdentityToken->content.decoded.data;
  48. /* Compatibility notice: Siemens OPC Scout v10 provides an empty
  49. * policyId. This is not compliant. For compatibility, assume that empty
  50. * policyId == ANONYMOUS_POLICY */
  51. if(token->policyId.data && !UA_String_equal(&token->policyId, &anonymous_policy))
  52. return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
  53. /* No userdata atm */
  54. *sessionContext = NULL;
  55. return UA_STATUSCODE_GOOD;
  56. }
  57. /* Username and password */
  58. if(userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
  59. const UA_UserNameIdentityToken *userToken =
  60. (UA_UserNameIdentityToken*)userIdentityToken->content.decoded.data;
  61. if(!UA_String_equal(&userToken->policyId, &username_policy))
  62. return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
  63. /* The userToken has been decrypted by the server before forwarding
  64. * it to the plugin. This information can be used here. */
  65. /* if(userToken->encryptionAlgorithm.length > 0) {} */
  66. /* Empty username and password */
  67. if(userToken->userName.length == 0 && userToken->password.length == 0)
  68. return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
  69. /* Try to match username/pw */
  70. UA_Boolean match = false;
  71. for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
  72. if(UA_String_equal(&userToken->userName, &context->usernamePasswordLogin[i].username) &&
  73. UA_String_equal(&userToken->password, &context->usernamePasswordLogin[i].password)) {
  74. match = true;
  75. break;
  76. }
  77. }
  78. if(!match)
  79. return UA_STATUSCODE_BADUSERACCESSDENIED;
  80. /* No userdata atm */
  81. *sessionContext = NULL;
  82. return UA_STATUSCODE_GOOD;
  83. }
  84. /* Unsupported token type */
  85. return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
  86. }
  87. static void
  88. closeSession_default(UA_Server *server, UA_AccessControl *ac,
  89. const UA_NodeId *sessionId, void *sessionContext) {
  90. /* no context to clean up */
  91. }
  92. static UA_UInt32
  93. getUserRightsMask_default(UA_Server *server, UA_AccessControl *ac,
  94. const UA_NodeId *sessionId, void *sessionContext,
  95. const UA_NodeId *nodeId, void *nodeContext) {
  96. return 0xFFFFFFFF;
  97. }
  98. static UA_Byte
  99. getUserAccessLevel_default(UA_Server *server, UA_AccessControl *ac,
  100. const UA_NodeId *sessionId, void *sessionContext,
  101. const UA_NodeId *nodeId, void *nodeContext) {
  102. return 0xFF;
  103. }
  104. static UA_Boolean
  105. getUserExecutable_default(UA_Server *server, UA_AccessControl *ac,
  106. const UA_NodeId *sessionId, void *sessionContext,
  107. const UA_NodeId *methodId, void *methodContext) {
  108. return true;
  109. }
  110. static UA_Boolean
  111. getUserExecutableOnObject_default(UA_Server *server, UA_AccessControl *ac,
  112. const UA_NodeId *sessionId, void *sessionContext,
  113. const UA_NodeId *methodId, void *methodContext,
  114. const UA_NodeId *objectId, void *objectContext) {
  115. return true;
  116. }
  117. static UA_Boolean
  118. allowAddNode_default(UA_Server *server, UA_AccessControl *ac,
  119. const UA_NodeId *sessionId, void *sessionContext,
  120. const UA_AddNodesItem *item) {
  121. return true;
  122. }
  123. static UA_Boolean
  124. allowAddReference_default(UA_Server *server, UA_AccessControl *ac,
  125. const UA_NodeId *sessionId, void *sessionContext,
  126. const UA_AddReferencesItem *item) {
  127. return true;
  128. }
  129. static UA_Boolean
  130. allowDeleteNode_default(UA_Server *server, UA_AccessControl *ac,
  131. const UA_NodeId *sessionId, void *sessionContext,
  132. const UA_DeleteNodesItem *item) {
  133. return true;
  134. }
  135. static UA_Boolean
  136. allowDeleteReference_default(UA_Server *server, UA_AccessControl *ac,
  137. const UA_NodeId *sessionId, void *sessionContext,
  138. const UA_DeleteReferencesItem *item) {
  139. return true;
  140. }
  141. #ifdef UA_ENABLE_HISTORIZING
  142. static UA_Boolean
  143. allowHistoryUpdateUpdateData_default(UA_Server *server, UA_AccessControl *ac,
  144. const UA_NodeId *sessionId, void *sessionContext,
  145. const UA_NodeId *nodeId,
  146. UA_PerformUpdateType performInsertReplace,
  147. const UA_DataValue *value) {
  148. return true;
  149. }
  150. static UA_Boolean
  151. allowHistoryUpdateDeleteRawModified_default(UA_Server *server, UA_AccessControl *ac,
  152. const UA_NodeId *sessionId, void *sessionContext,
  153. const UA_NodeId *nodeId,
  154. UA_DateTime startTimestamp,
  155. UA_DateTime endTimestamp,
  156. bool isDeleteModified) {
  157. return true;
  158. }
  159. #endif
  160. /***************************************/
  161. /* Create Delete Access Control Plugin */
  162. /***************************************/
  163. static void deleteMembers_default(UA_AccessControl *ac) {
  164. UA_Array_delete((void*)(uintptr_t)ac->userTokenPolicies,
  165. ac->userTokenPoliciesSize,
  166. &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
  167. ac->userTokenPolicies = NULL;
  168. ac->userTokenPoliciesSize = 0;
  169. AccessControlContext *context = (AccessControlContext*)ac->context;
  170. if (context) {
  171. for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
  172. UA_String_deleteMembers(&context->usernamePasswordLogin[i].username);
  173. UA_String_deleteMembers(&context->usernamePasswordLogin[i].password);
  174. }
  175. if(context->usernamePasswordLoginSize > 0)
  176. UA_free(context->usernamePasswordLogin);
  177. UA_free(ac->context);
  178. }
  179. }
  180. UA_StatusCode
  181. UA_AccessControl_default(UA_ServerConfig *config, UA_Boolean allowAnonymous,
  182. const UA_ByteString *userTokenPolicyUri,
  183. size_t usernamePasswordLoginSize,
  184. const UA_UsernamePasswordLogin *usernamePasswordLogin) {
  185. UA_AccessControl *ac = &config->accessControl;
  186. ac->deleteMembers = deleteMembers_default;
  187. ac->activateSession = activateSession_default;
  188. ac->closeSession = closeSession_default;
  189. ac->getUserRightsMask = getUserRightsMask_default;
  190. ac->getUserAccessLevel = getUserAccessLevel_default;
  191. ac->getUserExecutable = getUserExecutable_default;
  192. ac->getUserExecutableOnObject = getUserExecutableOnObject_default;
  193. ac->allowAddNode = allowAddNode_default;
  194. ac->allowAddReference = allowAddReference_default;
  195. #ifdef UA_ENABLE_HISTORIZING
  196. ac->allowHistoryUpdateUpdateData = allowHistoryUpdateUpdateData_default;
  197. ac->allowHistoryUpdateDeleteRawModified = allowHistoryUpdateDeleteRawModified_default;
  198. #endif
  199. ac->allowDeleteNode = allowDeleteNode_default;
  200. ac->allowDeleteReference = allowDeleteReference_default;
  201. AccessControlContext *context = (AccessControlContext*)
  202. UA_malloc(sizeof(AccessControlContext));
  203. if (!context)
  204. return UA_STATUSCODE_BADOUTOFMEMORY;
  205. memset(context, 0, sizeof(AccessControlContext));
  206. ac->context = context;
  207. /* Allow anonymous? */
  208. context->allowAnonymous = allowAnonymous;
  209. /* Copy username/password to the access control plugin */
  210. if(usernamePasswordLoginSize > 0) {
  211. context->usernamePasswordLogin = (UA_UsernamePasswordLogin*)
  212. UA_malloc(usernamePasswordLoginSize * sizeof(UA_UsernamePasswordLogin));
  213. if(!context->usernamePasswordLogin)
  214. return UA_STATUSCODE_BADOUTOFMEMORY;
  215. context->usernamePasswordLoginSize = usernamePasswordLoginSize;
  216. for(size_t i = 0; i < usernamePasswordLoginSize; i++) {
  217. UA_String_copy(&usernamePasswordLogin[i].username, &context->usernamePasswordLogin[i].username);
  218. UA_String_copy(&usernamePasswordLogin[i].password, &context->usernamePasswordLogin[i].password);
  219. }
  220. }
  221. /* Set the allowed policies */
  222. size_t policies = 0;
  223. if(allowAnonymous)
  224. policies++;
  225. if(usernamePasswordLoginSize > 0)
  226. policies++;
  227. ac->userTokenPoliciesSize = 0;
  228. ac->userTokenPolicies = (UA_UserTokenPolicy *)
  229. UA_Array_new(policies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
  230. if(!ac->userTokenPolicies)
  231. return UA_STATUSCODE_BADOUTOFMEMORY;
  232. ac->userTokenPoliciesSize = policies;
  233. policies = 0;
  234. if(allowAnonymous) {
  235. ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_ANONYMOUS;
  236. ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY);
  237. if (!ac->userTokenPolicies[policies].policyId.data)
  238. return UA_STATUSCODE_BADOUTOFMEMORY;
  239. policies++;
  240. }
  241. if(usernamePasswordLoginSize > 0) {
  242. ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_USERNAME;
  243. ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(USERNAME_POLICY);
  244. if(!ac->userTokenPolicies[policies].policyId.data)
  245. return UA_STATUSCODE_BADOUTOFMEMORY;
  246. #if UA_LOGLEVEL <= 400
  247. const UA_String noneUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
  248. if(UA_ByteString_equal(userTokenPolicyUri, &noneUri)) {
  249. UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_SERVER,
  250. "Username/Password configured, but no encrypting SecurityPolicy. "
  251. "This can leak credentials on the network.");
  252. }
  253. #endif
  254. return UA_ByteString_copy(userTokenPolicyUri,
  255. &ac->userTokenPolicies[policies].securityPolicyUri);
  256. }
  257. return UA_STATUSCODE_GOOD;
  258. }