Browse Source

AccessControl: Forward endpoint information and the remote certificate
for the SecureChannel to the AccessControl plugin for session
authentication

Julius Pfrommer 6 years ago
parent
commit
0afd439a21

+ 6 - 2
include/ua_plugin_access_control.h

@@ -34,9 +34,13 @@ struct UA_AccessControl {
     size_t userTokenPoliciesSize;
     UA_UserTokenPolicy *userTokenPolicies;
     
-    /* Authenticate a session. The session context is attached to the session and
-     * later passed into the node-based access control callbacks. */
+    /* Authenticate a session. The session context is attached to the session
+     * and later passed into the node-based access control callbacks. The new
+     * session is rejected if a StatusCode other than UA_STATUSCODE_GOOD is
+     * returned. */
     UA_StatusCode (*activateSession)(UA_Server *server, UA_AccessControl *ac,
+                                     const UA_EndpointDescription *endpointDescription,
+                                     const UA_ByteString *secureChannelRemoteCertificate,
                                      const UA_NodeId *sessionId,
                                      const UA_ExtensionObject *userIdentityToken,
                                      void **sessionContext);

+ 2 - 0
plugins/ua_accesscontrol_default.c

@@ -27,6 +27,8 @@ const UA_String username_policy = UA_STRING_STATIC(USERNAME_POLICY);
 
 static UA_StatusCode
 activateSession_default(UA_Server *server, UA_AccessControl *ac,
+                        const UA_EndpointDescription *endpointDescription,
+                        const UA_ByteString *secureChannelRemoteCertificate,
                         const UA_NodeId *sessionId,
                         const UA_ExtensionObject *userIdentityToken,
                         void **sessionContext) {

+ 50 - 1
src/server/ua_services_session.c

@@ -242,10 +242,59 @@ Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
         return;
     }
 
+    /* Find the matching endpoint */
+    const UA_EndpointDescription *ed = NULL;
+    for(size_t i = 0; ed == NULL && i < server->config.endpointsSize; ++i) {
+        const UA_Endpoint *e = &server->config.endpoints[i];
+
+        /* Match the Security Mode */
+        if(e->endpointDescription.securityMode != channel->securityMode)
+            continue;
+
+        /* Match the SecurityPolicy */
+        if(!UA_String_equal(&e->securityPolicy.policyUri,
+                            &channel->securityPolicy->policyUri))
+            continue;
+
+        /* Match the UserTokenType */
+        for(size_t j = 0; j < e->endpointDescription.userIdentityTokensSize; j++) {
+            const UA_UserTokenPolicy *u = &e->endpointDescription.userIdentityTokens[j];
+            if(u->tokenType == UA_USERTOKENTYPE_ANONYMOUS) {
+                if(request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN])
+                    continue;
+            } else if(u->tokenType == UA_USERTOKENTYPE_USERNAME) {
+                if(request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN])
+                    continue;
+            } else if(u->tokenType == UA_USERTOKENTYPE_CERTIFICATE) {
+                if(request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN])
+                    continue;
+            } else if(u->tokenType == UA_USERTOKENTYPE_ISSUEDTOKEN) {
+                if(request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN])
+                    continue;
+            } else {
+                response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+                return;
+            }
+
+            /* Match found */
+            ed = &e->endpointDescription;
+            break;
+        }
+
+    }
+
+    /* No matching endpoint found */
+    if(!ed) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENREJECTED;
+        return;
+    }
+
     /* Callback into userland access control */
     response->responseHeader.serviceResult =
         server->config.accessControl.activateSession(server, &server->config.accessControl,
-                                                     &session->sessionId, &request->userIdentityToken,
+                                                     ed, &channel->remoteCertificate,
+                                                     &session->sessionId,
+                                                     &request->userIdentityToken,
                                                      &session->sessionHandle);
     if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
         UA_LOG_INFO_SESSION(server->config.logger, session,

+ 2 - 0
tools/schema/datatypes_minimal.txt

@@ -45,6 +45,8 @@ ServiceFault
 UserIdentityToken
 UserNameIdentityToken
 AnonymousIdentityToken
+X509IdentityToken
+IssuedIdentityToken
 CreateSessionResponse
 CreateSessionRequest
 EndpointDescription