mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-02-20 09:46:13 +00:00
plumbing full flow from controller -> client network
This commit is contained in:
parent
f8bf91426b
commit
8d39c9a861
@ -40,6 +40,30 @@
|
||||
namespace ZeroTier
|
||||
{
|
||||
|
||||
struct AuthInfo
|
||||
{
|
||||
public:
|
||||
AuthInfo()
|
||||
: enabled(false)
|
||||
, version(0)
|
||||
, authenticationURL()
|
||||
, authenticationExpiryTime(0)
|
||||
, centralAuthURL()
|
||||
, ssoNonce()
|
||||
, ssoState()
|
||||
, ssoClientID()
|
||||
{}
|
||||
|
||||
bool enabled;
|
||||
uint64_t version;
|
||||
std::string authenticationURL;
|
||||
uint64_t authenticationExpiryTime;
|
||||
std::string centralAuthURL;
|
||||
std::string ssoNonce;
|
||||
std::string ssoState;
|
||||
std::string ssoClientID;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class with common infrastructure for all controller DB implementations
|
||||
*/
|
||||
@ -108,7 +132,7 @@ public:
|
||||
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId) = 0;
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0;
|
||||
|
||||
virtual std::string getSSOAuthURL(const nlohmann::json &member, const std::string &redirectURL) { return ""; }
|
||||
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) { return AuthInfo(); }
|
||||
virtual void networkMemberSSOHasExpired(uint64_t nwid, int64_t ts);
|
||||
|
||||
inline void addListener(DB::ChangeListener *const listener)
|
||||
|
@ -125,16 +125,16 @@ bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,std::vect
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string DBMirrorSet::getSSOAuthURL(const nlohmann::json &member, const std::string &redirectURL)
|
||||
AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_dbs_l);
|
||||
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
|
||||
std::string url = (*d)->getSSOAuthURL(member, redirectURL);
|
||||
if (!url.empty()) {
|
||||
return url;
|
||||
AuthInfo info = (*d)->getSSOAuthInfo(member, redirectURL);
|
||||
if (info.enabled) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
return AuthInfo();
|
||||
}
|
||||
|
||||
void DBMirrorSet::networkMemberSSOHasExpired(uint64_t nwid, int64_t ts)
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member);
|
||||
virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId);
|
||||
|
||||
std::string getSSOAuthURL(const nlohmann::json &member, const std::string &redirectURL);
|
||||
AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
|
||||
void networkMemberSSOHasExpired(uint64_t nwid, int64_t ts);
|
||||
|
||||
inline void addDB(const std::shared_ptr<DB> &db)
|
||||
|
@ -1360,27 +1360,53 @@ void EmbeddedNetworkController::_request(
|
||||
// Otherwise no, we use standard auth logic.
|
||||
bool networkSSOEnabled = OSUtils::jsonBool(network["ssoEnabled"], false);
|
||||
bool memberSSOExempt = OSUtils::jsonBool(member["ssoExempt"], false);
|
||||
std::string authenticationURL;
|
||||
if (networkSSOEnabled && !memberSSOExempt) {
|
||||
authenticationURL = _db.getSSOAuthURL(member, _ssoRedirectURL);
|
||||
AuthInfo info;
|
||||
if (networkSSOEnabled && ! memberSSOExempt) {
|
||||
info = _db.getSSOAuthInfo(member, _ssoRedirectURL);
|
||||
assert(info.enabled == networkSSOEnabled);
|
||||
|
||||
std::string memberId = member["id"];
|
||||
//fprintf(stderr, "ssoEnabled && !ssoExempt %s-%s\n", nwids, memberId.c_str());
|
||||
uint64_t authenticationExpiryTime = (int64_t)OSUtils::jsonInt(member["authenticationExpiryTime"], 0);
|
||||
//fprintf(stderr, "authExpiryTime: %lld\n", authenticationExpiryTime);
|
||||
if (authenticationExpiryTime < now) {
|
||||
if (!authenticationURL.empty()) {
|
||||
_db.networkMemberSSOHasExpired(nwid, now);
|
||||
onNetworkMemberDeauthorize(&_db, nwid, identity.address().toInt());
|
||||
if (info.version == 0) {
|
||||
if (!info.authenticationURL.empty()) {
|
||||
_db.networkMemberSSOHasExpired(nwid, now);
|
||||
onNetworkMemberDeauthorize(&_db, nwid, identity.address().toInt());
|
||||
|
||||
Dictionary<3072> authInfo;
|
||||
authInfo.add("aU", authenticationURL.c_str());
|
||||
//fprintf(stderr, "sending auth URL: %s\n", authenticationURL.c_str());
|
||||
Dictionary<4096> authInfo;
|
||||
authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, 0ULL);
|
||||
authInfo.add(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, info.authenticationURL.c_str());
|
||||
//fprintf(stderr, "sending auth URL: %s\n", authenticationURL.c_str());
|
||||
|
||||
DB::cleanMember(member);
|
||||
_db.save(member,true);
|
||||
DB::cleanMember(member);
|
||||
_db.save(member,true);
|
||||
|
||||
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes());
|
||||
return;
|
||||
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes());
|
||||
return;
|
||||
}
|
||||
} else if (info.version == 1) {
|
||||
if (!info.authenticationURL.empty()) {
|
||||
_db.networkMemberSSOHasExpired(nwid, now);
|
||||
onNetworkMemberDeauthorize(&_db, nwid, identity.address().toInt());
|
||||
|
||||
Dictionary<8192> authInfo;
|
||||
authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, info.version);
|
||||
authInfo.add(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, info.authenticationURL.c_str());
|
||||
authInfo.add(ZT_AUTHINFO_DICT_KEY_CENTRAL_ENDPOINT_URL, info.centralAuthURL.c_str());
|
||||
authInfo.add(ZT_AUTHINFO_DICT_KEY_NONCE, info.ssoNonce.c_str());
|
||||
authInfo.add(ZT_AUTHINFO_DICT_KEY_STATE, info.ssoState.c_str());
|
||||
authInfo.add(ZT_AUTHINFO_DICT_KEY_CLIENT_ID, info.ssoClientID.c_str());
|
||||
|
||||
DB::cleanMember(member);
|
||||
_db.save(member, true);
|
||||
|
||||
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "invalid sso info.version %llu\n", info.version);
|
||||
}
|
||||
} else if (authorized) {
|
||||
_db.memberWillExpire(authenticationExpiryTime, nwid, identity.address().toInt());
|
||||
@ -1452,9 +1478,32 @@ void EmbeddedNetworkController::_request(
|
||||
nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL);
|
||||
|
||||
nc->ssoEnabled = OSUtils::jsonBool(network["ssoEnabled"], false);
|
||||
nc->authenticationExpiryTime = OSUtils::jsonInt(member["authenticationExpiryTime"], 0LL);
|
||||
if (!authenticationURL.empty())
|
||||
Utils::scopy(nc->authenticationURL, sizeof(nc->authenticationURL), authenticationURL.c_str());
|
||||
nc->ssoVersion = info.version;
|
||||
|
||||
if (info.version == 0) {
|
||||
nc->authenticationExpiryTime = OSUtils::jsonInt(member["authenticationExpiryTime"], 0LL);
|
||||
if (!info.authenticationURL.empty()) {
|
||||
Utils::scopy(nc->authenticationURL, sizeof(nc->authenticationURL), info.authenticationURL.c_str());
|
||||
}
|
||||
}
|
||||
else if (info.version == 1) {
|
||||
nc->authenticationExpiryTime = OSUtils::jsonInt(member["authenticationExpiryTime"], 0LL);
|
||||
if (!info.authenticationURL.empty()) {
|
||||
Utils::scopy(nc->authenticationURL, sizeof(nc->authenticationURL), info.authenticationURL.c_str());
|
||||
}
|
||||
if (!info.centralAuthURL.empty()) {
|
||||
Utils::scopy(nc->centralAuthURL, sizeof(nc->centralAuthURL), info.centralAuthURL.c_str());
|
||||
}
|
||||
if (!info.ssoNonce.empty()) {
|
||||
Utils::scopy(nc->ssoNonce, sizeof(nc->ssoNonce), info.ssoNonce.c_str());
|
||||
}
|
||||
if (!info.ssoState.empty()) {
|
||||
Utils::scopy(nc->ssoState, sizeof(nc->ssoState), info.ssoState.c_str());
|
||||
}
|
||||
if (!info.ssoClientID.empty()) {
|
||||
Utils::scopy(nc->ssoClientID, sizeof(nc->ssoClientID), info.ssoClientID.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string rtt(OSUtils::jsonString(member["remoteTraceTarget"],""));
|
||||
if (rtt.length() == 10) {
|
||||
|
@ -336,7 +336,7 @@ void PostgreSQL::nodeIsOnline(const uint64_t networkId, const uint64_t memberId,
|
||||
}
|
||||
}
|
||||
|
||||
std::string PostgreSQL::getSSOAuthURL(const nlohmann::json &member, const std::string &redirectURL)
|
||||
AuthInfo PostgreSQL::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL)
|
||||
{
|
||||
// NONCE is just a random character string. no semantic meaning
|
||||
// state = HMAC SHA384 of Nonce based on shared sso key
|
||||
@ -347,10 +347,12 @@ std::string PostgreSQL::getSSOAuthURL(const nlohmann::json &member, const std::s
|
||||
// how do we tell when a nonce is used? if auth_expiration_time is set
|
||||
std::string networkId = member["nwid"];
|
||||
std::string memberId = member["id"];
|
||||
char authenticationURL[4096] = {0};
|
||||
|
||||
//fprintf(stderr, "PostgreSQL::updateMemberOnLoad: %s-%s\n", networkId.c_str(), memberId.c_str());
|
||||
bool have_auth = false;
|
||||
|
||||
char authenticationURL[4096] = {0};
|
||||
AuthInfo info;
|
||||
info.enabled = true;
|
||||
// fprintf(stderr, "PostgreSQL::updateMemberOnLoad: %s-%s\n", networkId.c_str(), memberId.c_str());
|
||||
try {
|
||||
auto c = _pool->borrow();
|
||||
pqxx::work w(*c->c);
|
||||
@ -390,38 +392,51 @@ std::string PostgreSQL::getSSOAuthURL(const nlohmann::json &member, const std::s
|
||||
exit(6);
|
||||
}
|
||||
|
||||
r = w.exec_params("SELECT org.client_id, org.authorization_endpoint "
|
||||
r = w.exec_params("SELECT org.client_id, org.authorization_endpoint, org.sso_version "
|
||||
"FROM ztc_network AS nw, ztc_org AS org "
|
||||
"WHERE nw.id = $1 AND nw.sso_enabled = true AND org.owner_id = nw.owner_id", networkId);
|
||||
|
||||
std::string client_id = "";
|
||||
std::string authorization_endpoint = "";
|
||||
uint64_t sso_version = 0;
|
||||
|
||||
if (r.size() == 1) {
|
||||
client_id = r.at(0)[0].as<std::string>();
|
||||
authorization_endpoint = r.at(0)[1].as<std::string>();
|
||||
sso_version = r.at(0)[2].as<uint64_t>();
|
||||
} else if (r.size() > 1) {
|
||||
fprintf(stderr, "ERROR: More than one auth endpoint for an organization?!?!? NetworkID: %s\n", networkId.c_str());
|
||||
} else {
|
||||
fprintf(stderr, "No client or auth endpoint?!?\n");
|
||||
}
|
||||
|
||||
|
||||
info.version = sso_version;
|
||||
|
||||
// no catch all else because we don't actually care if no records exist here. just continue as normal.
|
||||
if ((!client_id.empty())&&(!authorization_endpoint.empty())) {
|
||||
have_auth = true;
|
||||
|
||||
|
||||
uint8_t state[48];
|
||||
HMACSHA384(_ssoPsk, nonceBytes, sizeof(nonceBytes), state);
|
||||
char state_hex[256];
|
||||
Utils::hex(state, 48, state_hex);
|
||||
|
||||
OSUtils::ztsnprintf(authenticationURL, sizeof(authenticationURL),
|
||||
"%s?response_type=id_token&response_mode=form_post&scope=openid+email+profile&redirect_uri=%s&nonce=%s&state=%s&client_id=%s",
|
||||
authorization_endpoint.c_str(),
|
||||
redirectURL.c_str(),
|
||||
nonce.c_str(),
|
||||
state_hex,
|
||||
client_id.c_str());
|
||||
if (info.version == 0) {
|
||||
char url[2048] = {0};
|
||||
OSUtils::ztsnprintf(url, sizeof(authenticationURL),
|
||||
"%s?response_type=id_token&response_mode=form_post&scope=openid+email+profile&redirect_uri=%s&nonce=%s&state=%s&client_id=%s",
|
||||
authorization_endpoint.c_str(),
|
||||
redirectURL.c_str(),
|
||||
nonce.c_str(),
|
||||
state_hex,
|
||||
client_id.c_str());
|
||||
info.authenticationURL = std::string(url);
|
||||
} else if (info.version == 1) {
|
||||
info.ssoClientID = client_id;
|
||||
info.authenticationURL = authorization_endpoint;
|
||||
info.ssoNonce = nonce;
|
||||
info.ssoState = std::string(state_hex);
|
||||
info.centralAuthURL = redirectURL;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "client_id: %s\nauthorization_endpoint: %s\n", client_id.c_str(), authorization_endpoint.c_str());
|
||||
}
|
||||
@ -432,7 +447,7 @@ std::string PostgreSQL::getSSOAuthURL(const nlohmann::json &member, const std::s
|
||||
fprintf(stderr, "ERROR: Error updating member on load: %s\n", e.what());
|
||||
}
|
||||
|
||||
return std::string(authenticationURL);
|
||||
return info; //std::string(authenticationURL);
|
||||
}
|
||||
|
||||
void PostgreSQL::initializeNetworks()
|
||||
|
@ -107,7 +107,7 @@ public:
|
||||
virtual void eraseNetwork(const uint64_t networkId);
|
||||
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
|
||||
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress);
|
||||
virtual std::string getSSOAuthURL(const nlohmann::json &member, const std::string &redirectURL);
|
||||
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
|
||||
|
||||
protected:
|
||||
struct _PairHasher
|
||||
|
@ -1194,11 +1194,18 @@ typedef struct
|
||||
*/
|
||||
ZT_VirtualNetworkDNS dns;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sso enabled
|
||||
*/
|
||||
bool ssoEnabled;
|
||||
|
||||
/**
|
||||
* SSO verison
|
||||
*/
|
||||
uint64_t ssoVersion;
|
||||
|
||||
/**
|
||||
* If the status us AUTHENTICATION_REQUIRED, this may contain a URL for authentication.
|
||||
*/
|
||||
@ -1208,6 +1215,26 @@ typedef struct
|
||||
* Time that current authentication expires. only valid if ssoEnabled is true
|
||||
*/
|
||||
uint64_t authenticationExpiryTime;
|
||||
|
||||
/**
|
||||
* central base URL.
|
||||
*/
|
||||
char centralAuthURL[2048];
|
||||
|
||||
/**
|
||||
* sso nonce
|
||||
*/
|
||||
char ssoNonce[64];
|
||||
|
||||
/**
|
||||
* sso state
|
||||
*/
|
||||
char ssoState[128];
|
||||
|
||||
/**
|
||||
* oidc client id
|
||||
*/
|
||||
char ssoClientID[256];
|
||||
} ZT_VirtualNetworkConfig;
|
||||
|
||||
/**
|
||||
|
14
make-mac.mk
14
make-mac.mk
@ -1,6 +1,8 @@
|
||||
CC=clang
|
||||
CXX=clang++
|
||||
INCLUDES=
|
||||
TOPDIR=$(shell PWD)
|
||||
|
||||
INCLUDES=-I$(shell PWD)/zeroidc/target
|
||||
DEFS=
|
||||
LIBS=
|
||||
ARCH_FLAGS=-arch x86_64 -arch arm64
|
||||
@ -26,7 +28,7 @@ DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUIL
|
||||
|
||||
include objects.mk
|
||||
ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o osdep/MacDNSHelper.o ext/http-parser/http_parser.o
|
||||
LIBS+=-framework CoreServices -framework SystemConfiguration -framework CoreFoundation
|
||||
LIBS+=-framework CoreServices -framework SystemConfiguration -framework CoreFoundation -framework Security
|
||||
|
||||
# Official releases are signed with our Apple cert and apply software updates by default
|
||||
ifeq ($(ZT_OFFICIAL_RELEASE),1)
|
||||
@ -103,7 +105,7 @@ mac-agent: FORCE
|
||||
osdep/MacDNSHelper.o: osdep/MacDNSHelper.mm
|
||||
$(CXX) $(CXXFLAGS) -c osdep/MacDNSHelper.mm -o osdep/MacDNSHelper.o
|
||||
|
||||
one: $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent zeroidc
|
||||
one: zeroidc $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent
|
||||
$(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS) zeroidc/target/libzeroidc.a
|
||||
# $(STRIP) zerotier-one
|
||||
ln -sf zerotier-one zerotier-idtool
|
||||
@ -115,8 +117,8 @@ zerotier-one: one
|
||||
zeroidc: zeroidc/target/libzeroidc.a
|
||||
|
||||
zeroidc/target/libzeroidc.a:
|
||||
cd zeroidc && cargo build --target=x86_64-apple-darwin --release
|
||||
cd zeroidc && cargo build --target=aarch64-apple-darwin --release
|
||||
cd zeroidc && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build --target=x86_64-apple-darwin --release
|
||||
cd zeroidc && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build --target=aarch64-apple-darwin --release
|
||||
cd zeroidc && lipo -create target/x86_64-apple-darwin/release/libzeroidc.a target/aarch64-apple-darwin/release/libzeroidc.a -output target/libzeroidc.a
|
||||
|
||||
central-controller:
|
||||
@ -126,6 +128,8 @@ zerotier-idtool: one
|
||||
|
||||
zerotier-cli: one
|
||||
|
||||
$(CORE_OBJS): zeroidc
|
||||
|
||||
libzerotiercore.a: $(CORE_OBJS)
|
||||
ar rcs libzerotiercore.a $(CORE_OBJS)
|
||||
ranlib libzerotiercore.a
|
||||
|
@ -199,17 +199,62 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
|
||||
const uint16_t errorDataSize = at<uint16_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8);
|
||||
s -= 2;
|
||||
if (s >= (int)errorDataSize) {
|
||||
Dictionary<3072> authInfo(((const char *)this->data()) + (ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 10), errorDataSize);
|
||||
char authenticationURL[2048];
|
||||
if (authInfo.get("aU", authenticationURL, sizeof(authenticationURL)) > 0) {
|
||||
authenticationURL[sizeof(authenticationURL) - 1] = 0; // ensure always zero terminated
|
||||
network->setAuthenticationRequired(authenticationURL);
|
||||
noUrl = false;
|
||||
Dictionary<8192> authInfo(((const char *)this->data()) + (ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 10), errorDataSize);
|
||||
|
||||
uint64_t authVer = authInfo.getUI(ZT_AUTHINFO_DICT_KEY_VERSION, 0ULL);
|
||||
|
||||
if (authVer == 0) {
|
||||
char authenticationURL[2048];
|
||||
|
||||
if (authInfo.get(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, authenticationURL, sizeof(authenticationURL)) > 0) {
|
||||
authenticationURL[sizeof(authenticationURL) - 1] = 0; // ensure always zero terminated
|
||||
network->setAuthenticationRequired(authenticationURL);
|
||||
noUrl = false;
|
||||
}
|
||||
} else if (authVer == 1) {
|
||||
bool haveAuthURL = false;
|
||||
char authenticationURL[2048] = { 0 };
|
||||
bool haveCentralURL = false;
|
||||
char centralAuthURL[2048] = { 0 };
|
||||
bool haveNonce = false;
|
||||
char ssoNonce[64] = { 0 };
|
||||
bool haveState = false;
|
||||
char ssoState[128] = {0};
|
||||
bool haveClientID = false;
|
||||
char ssoClientID[256] = { 0 };
|
||||
|
||||
if (authInfo.get(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, authenticationURL, sizeof(authenticationURL)) > 0) {
|
||||
authenticationURL[sizeof(authenticationURL) - 1] = 0;
|
||||
haveAuthURL = true;
|
||||
}
|
||||
if (authInfo.get(ZT_AUTHINFO_DICT_KEY_CENTRAL_ENDPOINT_URL, centralAuthURL, sizeof(centralAuthURL))>0) {
|
||||
centralAuthURL[sizeof(centralAuthURL) - 1] = 0;
|
||||
haveCentralURL = true;
|
||||
}
|
||||
if (authInfo.get(ZT_AUTHINFO_DICT_KEY_NONCE, ssoNonce, sizeof(ssoNonce)) > 0) {
|
||||
ssoNonce[sizeof(ssoNonce) - 1] = 0;
|
||||
haveNonce = true;
|
||||
}
|
||||
if (authInfo.get(ZT_AUTHINFO_DICT_KEY_STATE, ssoState, sizeof(ssoState)) > 0) {
|
||||
ssoState[sizeof(ssoState) - 1] = 0;
|
||||
haveState = true;
|
||||
}
|
||||
if (authInfo.get(ZT_AUTHINFO_DICT_KEY_CLIENT_ID, ssoClientID, sizeof(ssoClientID)) > 0) {
|
||||
ssoClientID[sizeof(ssoClientID) - 1] = 0;
|
||||
haveClientID = true;
|
||||
}
|
||||
|
||||
noUrl = ! (haveAuthURL && haveCentralURL && haveNonce && haveState && haveClientID);
|
||||
|
||||
if (!noUrl) {
|
||||
network->setAuthenticationRequired(authenticationURL, centralAuthURL, ssoClientID, ssoNonce, ssoState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (noUrl)
|
||||
if (noUrl) {
|
||||
network->setAuthenticationRequired("");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "Node.hpp"
|
||||
#include "Peer.hpp"
|
||||
#include "Trace.hpp"
|
||||
#include "zeroidc.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
@ -550,7 +551,8 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u
|
||||
_lastConfigUpdate(0),
|
||||
_destroyed(false),
|
||||
_netconfFailure(NETCONF_FAILURE_NONE),
|
||||
_portError(0)
|
||||
_portError(0),
|
||||
_idc(nullptr)
|
||||
{
|
||||
for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i)
|
||||
_incomingConfigChunks[i].ts = 0;
|
||||
@ -591,6 +593,12 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u
|
||||
_portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
|
||||
_portInitialized = true;
|
||||
}
|
||||
|
||||
if (nconf->ssoEnabled) {
|
||||
if (_config.ssoVersion == 1) {
|
||||
// start sso handling for network
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Network::~Network()
|
||||
@ -598,6 +606,12 @@ Network::~Network()
|
||||
ZT_VirtualNetworkConfig ctmp;
|
||||
_externalConfig(&ctmp);
|
||||
|
||||
if (_idc) {
|
||||
zeroidc::zeroidc_stop(_idc);
|
||||
zeroidc::zeroidc_delete(_idc);
|
||||
_idc = nullptr;
|
||||
}
|
||||
|
||||
if (_destroyed) {
|
||||
// This is done in Node::leave() so we can pass tPtr properly
|
||||
//RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
|
||||
@ -1434,8 +1448,13 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
|
||||
memcpy(&ec->dns, &_config.dns, sizeof(ZT_VirtualNetworkDNS));
|
||||
|
||||
Utils::scopy(ec->authenticationURL, sizeof(ec->authenticationURL), _authenticationURL.c_str());
|
||||
ec->ssoVersion = _config.ssoVersion;
|
||||
ec->authenticationExpiryTime = _config.authenticationExpiryTime;
|
||||
ec->ssoEnabled = _config.ssoEnabled;
|
||||
Utils::scopy(ec->centralAuthURL, sizeof(ec->centralAuthURL), _config.centralAuthURL);
|
||||
Utils::scopy(ec->ssoNonce, sizeof(ec->ssoNonce), _config.ssoNonce);
|
||||
Utils::scopy(ec->ssoState, sizeof(ec->ssoState), _config.ssoState);
|
||||
Utils::scopy(ec->ssoClientID, sizeof(ec->ssoClientID), _config.ssoClientID);
|
||||
}
|
||||
|
||||
void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup)
|
||||
@ -1542,4 +1561,30 @@ Membership &Network::_membership(const Address &a)
|
||||
return _memberships[a];
|
||||
}
|
||||
|
||||
void Network::setAuthenticationRequired(const char* authEndpoint, const char* centralEndpoint, const char* clientID, const char* nonce, const char* state)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
_netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED;
|
||||
_config.ssoEnabled = true;
|
||||
_config.ssoVersion = 1;
|
||||
|
||||
Utils::scopy(_config.authenticationURL, sizeof(_config.authenticationURL), authEndpoint);
|
||||
Utils::scopy(_config.centralAuthURL, sizeof(_config.centralAuthURL), centralEndpoint);
|
||||
Utils::scopy(_config.ssoClientID, sizeof(_config.ssoClientID), clientID);
|
||||
Utils::scopy(_config.ssoNonce, sizeof(_config.ssoNonce), nonce);
|
||||
Utils::scopy(_config.ssoState, sizeof(_config.ssoState), state);
|
||||
|
||||
// TODO: propaagte to full flow module
|
||||
if (!this->_idc) {
|
||||
this->_idc = zeroidc::zeroidc_new(_config.authenticationURL, _config.ssoClientID, _config.centralAuthURL, 9993);
|
||||
zeroidc::zeroidc_start(this->_idc);
|
||||
}
|
||||
|
||||
zeroidc::AuthInfo *info = zeroidc::zeroidc_get_auth_info(this->_idc, _config.ssoState, _config.ssoNonce);
|
||||
const char* url = zeroidc::zeroidc_get_auth_url(info);
|
||||
if (url != NULL) {
|
||||
fprintf(stderr, "full auth URL: %s\n", url);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -41,6 +41,10 @@
|
||||
#define ZT_NETWORK_MAX_INCOMING_UPDATES 3
|
||||
#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1)
|
||||
|
||||
namespace zeroidc {
|
||||
typedef struct ZeroIDC ZeroIDC;
|
||||
}
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
@ -229,7 +233,14 @@ public:
|
||||
_netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED;
|
||||
_authenticationURL = (url) ? url : "";
|
||||
_config.ssoEnabled = true;
|
||||
}
|
||||
_config.ssoVersion = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* set netconf failure to 'authentication required' along with info needed
|
||||
* for sso full flow authentication.
|
||||
*/
|
||||
void setAuthenticationRequired(const char* authEndpoint, const char* centralEndpoint, const char* clientID, const char* nonce, const char* state);
|
||||
|
||||
/**
|
||||
* Causes this network to request an updated configuration from its master node now
|
||||
@ -457,8 +468,10 @@ private:
|
||||
Mutex _lock;
|
||||
|
||||
AtomicCounter __refCount;
|
||||
|
||||
zeroidc::ZeroIDC *_idc;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
|
@ -182,12 +182,24 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) return false;
|
||||
}
|
||||
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) return false;
|
||||
if (this->ssoEnabled) {
|
||||
if (this->authenticationURL[0]) {
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false;
|
||||
if (this->ssoVersion == 0) {
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) return false;
|
||||
|
||||
if (this->ssoEnabled) {
|
||||
if (this->authenticationURL[0]) {
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false;
|
||||
}
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) return false;
|
||||
}
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) return false;
|
||||
} else if(this->ssoVersion == 1) {
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) return false;
|
||||
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) return false;
|
||||
}
|
||||
|
||||
delete tmp;
|
||||
@ -374,18 +386,48 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
|
||||
DNS::deserializeDNS(*tmp, p, &dns);
|
||||
}
|
||||
|
||||
|
||||
this->ssoVersion = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, 0ULL);
|
||||
this->ssoEnabled = d.getB(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, false);
|
||||
if (this->ssoEnabled) {
|
||||
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) {
|
||||
this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated
|
||||
|
||||
if (this->ssoVersion == 0) {
|
||||
// implicit flow
|
||||
if (this->ssoEnabled) {
|
||||
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) {
|
||||
this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated
|
||||
} else {
|
||||
this->authenticationURL[0] = 0;
|
||||
}
|
||||
this->authenticationExpiryTime = d.getI(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, 0);
|
||||
} else {
|
||||
this->authenticationURL[0] = 0;
|
||||
this->authenticationExpiryTime = 0;
|
||||
}
|
||||
} else if (this->ssoVersion == 1) {
|
||||
// full flow
|
||||
if (this->ssoEnabled) {
|
||||
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) {
|
||||
this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0;
|
||||
}
|
||||
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL, (unsigned int)sizeof(this->centralAuthURL)) > 0) {
|
||||
this->centralAuthURL[sizeof(this->centralAuthURL) - 1] = 0;
|
||||
}
|
||||
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce, (unsigned int)sizeof(this->ssoNonce)) > 0) {
|
||||
this->ssoNonce[sizeof(this->ssoNonce) - 1] = 0;
|
||||
}
|
||||
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState, (unsigned int)sizeof(this->ssoState)) > 0) {
|
||||
this->ssoState[sizeof(this->ssoState) - 1] = 0;
|
||||
}
|
||||
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID, (unsigned int)sizeof(this->ssoClientID)) > 0) {
|
||||
this->ssoClientID[sizeof(this->ssoClientID) - 1] = 0;
|
||||
}
|
||||
} else {
|
||||
this->authenticationURL[0] = 0;
|
||||
this->authenticationExpiryTime = 0;
|
||||
this->centralAuthURL[0] = 0;
|
||||
this->ssoNonce[0] = 0;
|
||||
this->ssoState[0] = 0;
|
||||
this->ssoClientID[0] = 0;
|
||||
}
|
||||
this->authenticationExpiryTime = d.getI(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, 0);
|
||||
} else {
|
||||
this->authenticationURL[0] = 0;
|
||||
this->authenticationExpiryTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,10 +180,35 @@ namespace ZeroTier {
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_DNS "DNS"
|
||||
// sso enabld
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED "ssoe"
|
||||
// so version
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION "ssov"
|
||||
// authentication URL
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL "aurl"
|
||||
// authentication expiry
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME "aexpt"
|
||||
// central endpoint
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL "ssoce"
|
||||
// nonce
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_NONCE "sson"
|
||||
// state
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_STATE "ssos"
|
||||
// client ID
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID "ssocid"
|
||||
|
||||
// AuthInfo fields -- used by ncSendError for sso
|
||||
|
||||
// AuthInfo Version
|
||||
#define ZT_AUTHINFO_DICT_KEY_VERSION "aV"
|
||||
// authenticaiton URL
|
||||
#define ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL "aU"
|
||||
// Central endpoint URL
|
||||
#define ZT_AUTHINFO_DICT_KEY_CENTRAL_ENDPOINT_URL "aCU"
|
||||
// Nonce
|
||||
#define ZT_AUTHINFO_DICT_KEY_NONCE "aN"
|
||||
// State
|
||||
#define ZT_AUTHINFO_DICT_KEY_STATE "aS"
|
||||
// Client ID
|
||||
#define ZT_AUTHINFO_DICT_KEY_CLIENT_ID "aCID"
|
||||
|
||||
// Legacy fields -- these are obsoleted but are included when older clients query
|
||||
|
||||
@ -242,7 +267,11 @@ public:
|
||||
dnsCount(0),
|
||||
ssoEnabled(false),
|
||||
authenticationURL(),
|
||||
authenticationExpiryTime(0)
|
||||
authenticationExpiryTime(0),
|
||||
centralAuthURL(),
|
||||
ssoNonce(),
|
||||
ssoState(),
|
||||
ssoClientID()
|
||||
{
|
||||
name[0] = 0;
|
||||
memset(specialists, 0, sizeof(uint64_t)*ZT_MAX_NETWORK_SPECIALISTS);
|
||||
@ -250,6 +279,11 @@ public:
|
||||
memset(staticIps, 0, sizeof(InetAddress)*ZT_MAX_ZT_ASSIGNED_ADDRESSES);
|
||||
memset(rules, 0, sizeof(ZT_VirtualNetworkRule)*ZT_MAX_NETWORK_RULES);
|
||||
memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS));
|
||||
memset(authenticationURL, 0, sizeof(authenticationURL));
|
||||
memset(centralAuthURL, 0, sizeof(centralAuthURL));
|
||||
memset(ssoNonce, 0, sizeof(ssoNonce));
|
||||
memset(ssoState, 0, sizeof(ssoState));
|
||||
memset(ssoClientID, 0, sizeof(ssoClientID));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -619,15 +653,42 @@ public:
|
||||
*/
|
||||
bool ssoEnabled;
|
||||
|
||||
/**
|
||||
* SSO verison
|
||||
*/
|
||||
uint64_t ssoVersion;
|
||||
|
||||
/**
|
||||
* Authentication URL if authentication is required
|
||||
*/
|
||||
char authenticationURL[2048];
|
||||
|
||||
/**
|
||||
/**
|
||||
* Time current authentication expires or 0 if external authentication is disabled
|
||||
*
|
||||
* Not used if authVersion >= 1
|
||||
*/
|
||||
uint64_t authenticationExpiryTime;
|
||||
|
||||
/**
|
||||
* central base URL.
|
||||
*/
|
||||
char centralAuthURL[2048];
|
||||
|
||||
/**
|
||||
* sso nonce
|
||||
*/
|
||||
char ssoNonce[64];
|
||||
|
||||
/**
|
||||
* sso state
|
||||
*/
|
||||
char ssoState[128];
|
||||
|
||||
/**
|
||||
* oidc client id
|
||||
*/
|
||||
char ssoClientID[256];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
5
zeroidc/.cargo/config.toml
Normal file
5
zeroidc/.cargo/config.toml
Normal file
@ -0,0 +1,5 @@
|
||||
[target.x86_64-apple-darwin]
|
||||
rustflags=["-C", "link-arg=-mmacosx-version-min=10.13"]
|
||||
|
||||
[target.aarch64-apple-darwin]
|
||||
rustflags=["-C", "link-arg=-mmacosx-version-min=10.13"]
|
Loading…
x
Reference in New Issue
Block a user