From cb086ff97f4f793ef4d62ebf6b15a5d915c9a5f6 Mon Sep 17 00:00:00 2001
From: Adam Ierymenko <adam.ierymenko@zerotier.com>
Date: Mon, 18 Apr 2022 16:32:05 -0400
Subject: [PATCH] Simplify SSO logic. SSO should just normally expire when it
 expires. No full deauth needed. Deauth is for really giving someone the boot.

---
 controller/DB.cpp                        |  8 --------
 controller/DB.hpp                        |  1 -
 controller/DBMirrorSet.cpp               |  8 --------
 controller/DBMirrorSet.hpp               |  1 -
 controller/EmbeddedNetworkController.cpp | 26 +++++++++++++++++++++++-
 5 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/controller/DB.cpp b/controller/DB.cpp
index 27578bf77..2edcadbbe 100644
--- a/controller/DB.cpp
+++ b/controller/DB.cpp
@@ -196,14 +196,6 @@ void DB::networks(std::set<uint64_t> &networks)
 		networks.insert(n->first);
 }
 
-void DB::networkMemberSSOHasExpired(uint64_t nwid, int64_t now) {
-	std::lock_guard<std::mutex> l(_networks_l);
-	auto nw = _networks.find(nwid);
-	if (nw != _networks.end()) {
-		nw->second->mostRecentDeauthTime = now;
-	}
-}
-
 void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners)
 {
 	uint64_t memberId = 0;
diff --git a/controller/DB.hpp b/controller/DB.hpp
index d0641d72e..b792304e5 100644
--- a/controller/DB.hpp
+++ b/controller/DB.hpp
@@ -135,7 +135,6 @@ public:
 	virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0;
 
 	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)
 	{
diff --git a/controller/DBMirrorSet.cpp b/controller/DBMirrorSet.cpp
index 0706fa33a..fd7f32a22 100644
--- a/controller/DBMirrorSet.cpp
+++ b/controller/DBMirrorSet.cpp
@@ -137,14 +137,6 @@ AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::st
 	return AuthInfo();
 }
 
-void DBMirrorSet::networkMemberSSOHasExpired(uint64_t nwid, int64_t ts)
-{
-	std::lock_guard<std::mutex> l(_dbs_l);
-	for(auto d=_dbs.begin();d!=_dbs.end();++d) { 
-		(*d)->networkMemberSSOHasExpired(nwid, ts);
-	}
-}
-
 void DBMirrorSet::networks(std::set<uint64_t> &networks)
 {
 	std::lock_guard<std::mutex> l(_dbs_l);
diff --git a/controller/DBMirrorSet.hpp b/controller/DBMirrorSet.hpp
index 0ff427308..883c98fd7 100644
--- a/controller/DBMirrorSet.hpp
+++ b/controller/DBMirrorSet.hpp
@@ -52,7 +52,6 @@ public:
 	virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId);
 
 	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)
 	{
diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp
index 94e27fa07..9bc21ca59 100644
--- a/controller/EmbeddedNetworkController.cpp
+++ b/controller/EmbeddedNetworkController.cpp
@@ -1340,6 +1340,29 @@ void EmbeddedNetworkController::_request(
 	bool networkSSOEnabled = OSUtils::jsonBool(network["ssoEnabled"], false);
 	bool memberSSOExempt = OSUtils::jsonBool(member["ssoExempt"], false);
 	if (networkSSOEnabled && !memberSSOExempt) {
+		authenticationExpiryTime = (int64_t)OSUtils::jsonInt(member["authenticationExpiryTime"], 0);
+		info = _db.getSSOAuthInfo(member, _ssoRedirectURL);
+		assert(info.enabled == networkSSOEnabled);
+		if (authenticationExpiryTime <= now) {
+			if (info.version == 0) {
+				Dictionary<4096> authInfo;
+				authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, (uint64_t)0ULL);
+				authInfo.add(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, info.authenticationURL.c_str());
+			} else if (info.version == 1) {
+				Dictionary<8192> authInfo;
+				authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, info.version);
+				authInfo.add(ZT_AUTHINFO_DICT_KEY_ISSUER_URL, info.issuerURL.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());
+				_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes());
+			}
+			DB::cleanMember(member);
+			_db.save(member,true);
+			return;
+		}
+#if 0
 		// TODO:  Get expiry time if auth is still valid
 
 		// else get new auth info & stuff
@@ -1395,6 +1418,7 @@ void EmbeddedNetworkController::_request(
 			fprintf(stderr, "Setting member will expire to: %lld\n", authenticationExpiryTime);
 			//_db.memberWillExpire(authenticationExpiryTime, nwid, identity.address().toInt());
 		}
+#endif
 	}
 
 	if (authorized) {
@@ -1464,7 +1488,7 @@ void EmbeddedNetworkController::_request(
 	nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU);
 	nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL);
 
-	nc->ssoEnabled = OSUtils::jsonBool(network["ssoEnabled"], false);
+	nc->ssoEnabled = networkSSOEnabled; //OSUtils::jsonBool(network["ssoEnabled"], false);
 	nc->ssoVersion = info.version;
 
 	if (info.version == 0) {