Procházet zdrojové kódy

username/pass logins work, did not looked into CTT yet

Stasik0 před 10 roky
rodič
revize
ec9af23975

+ 5 - 0
include/ua_server.h

@@ -34,7 +34,12 @@ extern "C" {
 
 typedef struct UA_ServerConfig {
     UA_Boolean  Login_enableAnonymous;
+
     UA_Boolean  Login_enableUsernamePassword;
+    char**      Login_usernames;
+    char**      Login_passwords;
+    UA_UInt32   Login_loginsCount;
+
     char*       Application_applicationURI;
 } UA_ServerConfig;
 

+ 3 - 0
include/ua_types.h

@@ -341,6 +341,9 @@ UA_StatusCode UA_EXPORT UA_String_copyprintf(char const *fmt, UA_String *dst, ..
 /** Compares two strings */
 UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
 
+/** Compares an UA String with a char array */
+UA_Boolean UA_EXPORT UA_String_equalchars(const UA_String *string1, const char *charString);
+
 /* DateTime */
 /** Returns the current time */
 UA_DateTime UA_EXPORT UA_DateTime_now(void);

+ 14 - 6
src/server/ua_server.c

@@ -8,7 +8,16 @@
 
 const char *UA_LoggerCategoryNames[3] = {"communication", "server", "userland"};
 
-const UA_ServerConfig UA_ServerConfig_standard = { UA_TRUE, UA_TRUE, "urn:unconfigured:open62541:open62541Server"};
+const UA_ServerConfig UA_ServerConfig_standard = {
+        UA_TRUE,
+
+        UA_TRUE,
+        (char *[]){"user"},
+        (char *[]){"password"},
+        1,
+
+        "urn:unconfigured:open62541:open62541Server"
+};
 
 /**********************/
 /* Namespace Handling */
@@ -245,7 +254,6 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 
     UA_ByteString_init(&server->serverCertificate);
 
-#define PRODUCT_URI "http://open62541.org"
     // mockup application description
     UA_ApplicationDescription_init(&server->description);
     server->description.productUri = UA_STRING_ALLOC(PRODUCT_URI);
@@ -284,14 +292,14 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
         if(server->config.Login_enableAnonymous){
             UA_UserTokenPolicy_init(&endpoint->userIdentityTokens[currentIndex]);
             endpoint->userIdentityTokens[currentIndex].tokenType = UA_USERTOKENTYPE_ANONYMOUS;
-            endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC("open62541-anonymous-policy"); // defined per server
+            endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY); // defined per server
             currentIndex++;
         }
 
         if(server->config.Login_enableUsernamePassword){
-            UA_UserTokenPolicy_init(&endpoint->userIdentityTokens[1]);
-            endpoint->userIdentityTokens[1].tokenType = UA_USERTOKENTYPE_USERNAME;
-            endpoint->userIdentityTokens[1].policyId = UA_STRING_ALLOC("open62541-username-policy"); // defined per server
+            UA_UserTokenPolicy_init(&endpoint->userIdentityTokens[currentIndex]);
+            endpoint->userIdentityTokens[currentIndex].tokenType = UA_USERTOKENTYPE_USERNAME;
+            endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(USERNAME_POLICY); // defined per server
             currentIndex++;
         }
 

+ 4 - 0
src/server/ua_server_internal.h

@@ -7,6 +7,10 @@
 #include "ua_securechannel_manager.h"
 #include "ua_nodestore.h"
 
+#define PRODUCT_URI "http://open62541.org"
+#define ANONYMOUS_POLICY "open62541-anonymous-policy"
+#define USERNAME_POLICY "open62541-username-policy"
+
 /** Mapping of namespace-id and url to an external nodestore. For namespaces
     that have no mapping defined, the internal nodestore is used by default. */
 typedef struct UA_ExternalNamespace {

+ 72 - 3
src/server/ua_services_session.c

@@ -38,6 +38,11 @@ void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
     }
 }
 
+#ifdef RETURN
+#undef RETURN
+#endif
+#define RETURN  UA_UserIdentityToken_deleteMembers(&token); \
+                UA_UserNameIdentityToken_deleteMembers(&username_token)
 void Service_ActivateSession(UA_Server *server,UA_SecureChannel *channel,
                              const UA_ActivateSessionRequest *request,
                              UA_ActivateSessionResponse *response) {
@@ -47,11 +52,75 @@ void Service_ActivateSession(UA_Server *server,UA_SecureChannel *channel,
                                         (const UA_NodeId*)&request->requestHeader.authenticationToken,
                                         &foundSession);
 
-	if(foundSession == UA_NULL)
+	if(foundSession == UA_NULL){
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+        return;
+	}
+
+
+
+    UA_UserIdentityToken token;
+    UA_UserIdentityToken_init(&token);
+    size_t offset = 0;
+    UA_UserIdentityToken_decodeBinary(&request->userIdentityToken.body, &offset, &token);
+
+    UA_UserNameIdentityToken username_token;
+    UA_UserNameIdentityToken_init(&username_token);
+
+    //check policies
+
+    if(token.policyId.data == UA_NULL){ //user identity token is NULL
         response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
-    else
-        channel->session = foundSession;
+        //todo cleanup session
+        RETURN;
+    }
+
+    //anonymous logins
+    if(!server->config.Login_enableAnonymous && UA_String_equalchars(&token.policyId, ANONYMOUS_POLICY)){
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+        UA_UserIdentityToken_deleteMembers(&token);
+        //todo cleanup session
+        RETURN;
+    }
+
+    //username logins
+    if(UA_String_equalchars(&token.policyId, USERNAME_POLICY)){
+        if(!server->config.Login_enableUsernamePassword){
+            response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+            //todo cleanup session
+            RETURN;
+        }
+        offset = 0;
+        UA_UserNameIdentityToken_decodeBinary(&request->userIdentityToken.body, &offset, &username_token);
+        if(username_token.encryptionAlgorithm.data != UA_NULL){
+            //we only support encryption
+            response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+            //todo cleanup session
+            RETURN;
+        }
+        UA_Boolean matched = UA_FALSE;
+        for(UA_UInt32 i=0;i<server->config.Login_loginsCount;++i){
+            if(UA_String_equalchars(&username_token.userName, server->config.Login_usernames[i])
+            && UA_String_equalchars(&username_token.password, server->config.Login_passwords[i])){
+                matched = UA_TRUE;
+                break;
+            }
+        }
+        if(!matched){
+            //no username/pass matched
+            response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+            //todo cleanup session
+            RETURN;
+        }
+   }
+
+   //success - bind session to the channel
+   channel->session = foundSession;
+
+   RETURN;
+
 }
+#undef RETURN
 
 void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_CloseSessionRequest *request,
                           UA_CloseSessionResponse *response) {

+ 9 - 0
src/ua_types.c

@@ -159,6 +159,15 @@ UA_Boolean UA_String_equal(const UA_String *string1, const UA_String *string2) {
     return (is == 0) ? UA_TRUE : UA_FALSE;
 }
 
+UA_Boolean UA_String_equalchars(const UA_String *string1, const char *charString) {
+    UA_String string2 = UA_String_fromChars(charString);
+    UA_Boolean result = UA_FALSE;
+    result = UA_String_equal(string1, &string2);
+    UA_String_deleteMembers(&string2);
+    return result;
+
+}
+
 /* DateTime */
 #define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
 #define HUNDRED_NANOSEC_PER_USEC 10LL

+ 1 - 1
tools/generate_datatypes.py

@@ -57,7 +57,7 @@ minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "Applicati
                  "NodeAttributes","ReferenceTypeAttributes", "ViewAttributes", "ObjectTypeAttributes",
                  "NodeAttributesMask","DeleteNodesItem", "DeleteNodesRequest", "DeleteNodesResponse",
                  "DeleteReferencesItem", "DeleteReferencesRequest", "DeleteReferencesResponse",
-                 "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse"]
+                 "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse", "UserIdentityToken", "UserNameIdentityToken"]
 
 class TypeDescription(object):
     def __init__(self, name, nodeid, namespaceid):