From b72847d50404f4d751184d9977e7bba23050a797 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 17 Aug 2016 13:41:45 -0700 Subject: [PATCH] Finally implement network join auth tokens, at least at the protocol level. --- controller/EmbeddedNetworkController.cpp | 53 +++++++++++++++++++++++- node/NetworkConfig.hpp | 3 ++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index d3f44fb4d..dfb93b012 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -658,11 +658,39 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( // Stop if network is private and member is not authorized if ( (network.value("private",true)) && (!member.value("authorized",false)) ) { - _writeJson(memberJP,member); - return NetworkController::NETCONF_QUERY_ACCESS_DENIED; + bool authenticatedViaToken = false; + char atok[256]; + if (metaData.get(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH_TOKEN,atok,sizeof(atok)) > 0) { + atok[255] = (char)0; // not necessary but YDIFLO + if (strlen(atok) > 0) { // extra sanity check + auto authTokens = network["authTokens"]; + if (authTokens.is_array()) { + for(unsigned long i=0;i now)) && (tok.length() > 0) && (tok == atok) ) { + authenticatedViaToken = true; + break; + } + } + } + } + } + } + + if (!authenticatedViaToken) { + _writeJson(memberJP,member); + return NetworkController::NETCONF_QUERY_ACCESS_DENIED; + } } // Else compose and send network config + // If we made it here for some reason other than authorized being true, such as this + // being a public network or via a bearer token, then we set this in the member config. + member["authorized"] = true; + nc.networkId = nwid; nc.type = network.value("private",true) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; nc.timestamp = now; @@ -1308,6 +1336,26 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( network["rules"] = nrules; } } + + if (b.count("authTokens")) { + auto authTokens = b["authTokens"]; + if (authTokens.is_array()) { + json nat = json::array(); + for(unsigned long i=0;i 0) { + json t = json::object(); + t["token"] = tstr; + t["expires"] = token.value("expires",0ULL); + nat.push_back(t); + } + } + } + network["authTokens"] = nat; + } + } } catch ( ... ) { return 400; } @@ -1319,6 +1367,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (!network.count("v4AssignMode")) network["v4AssignMode"] = "{\"zt\":false}"_json; if (!network.count("v6AssignMode")) network["v6AssignMode"] = "{\"rfc4193\":false,\"zt\":false,\"6plane\":false}"_json; if (!network.count("activeBridges")) network["activeBridges"] = json::array(); + if (!network.count("authTokens")) network["authTokens"] = json::array(); if (!network.count("rules")) { // If unspecified, rules are set to allow anything and behave like a flat L2 segment diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 18244ec90..25e0ccafc 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -101,6 +101,9 @@ namespace ZeroTier { // Maximum number of tags this node can accept #define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS "mt" +// Network join authorization token (if any) +#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH_TOKEN "atok" + // These dictionary keys are short so they don't take up much room. // By convention we use upper case for binary blobs, but it doesn't really matter.