Basic plumbing for authentication requirement and piping through of URL information.

This commit is contained in:
Adam Ierymenko 2021-05-24 22:58:17 -04:00
commit b270d527f4
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
13 changed files with 124 additions and 13 deletions

View file

@ -1429,6 +1429,9 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
}
memcpy(&ec->dns, &_config.dns, sizeof(ZT_VirtualNetworkDNS));
Utils::scopy(ec->authenticationURL, sizeof(ec->authenticationURL), _config.authenticationURL);
ec->authenticationExpiryTime = _config.authenticationExpiryTime;
}
void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup)

View file

@ -220,6 +220,16 @@ public:
_netconfFailure = NETCONF_FAILURE_NOT_FOUND;
}
/**
* Set netconf failure to 'authentication required' possibly with an authorization URL
*/
inline void setAuthenticationRequired(const char *url)
{
Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED;
_authorizationURL = (url) ? url : "";
}
/**
* Causes this network to request an updated configuration from its master node now
*
@ -435,9 +445,11 @@ private:
NETCONF_FAILURE_NONE,
NETCONF_FAILURE_ACCESS_DENIED,
NETCONF_FAILURE_NOT_FOUND,
NETCONF_FAILURE_INIT_FAILED
NETCONF_FAILURE_INIT_FAILED,
NETCONF_FAILURE_AUTHENTICATION_REQUIRED
} _netconfFailure;
int _portError; // return value from port config callback
std::string _authorizationURL;
Hashtable<Address,Membership> _memberships;

View file

@ -182,6 +182,13 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) return false;
}
if (this->authenticationURL[0]) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false;
}
if (this->authenticationExpiryTime >= 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) return false;
}
delete tmp;
} catch ( ... ) {
delete tmp;
@ -365,6 +372,13 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
unsigned int p = 0;
DNS::deserializeDNS(*tmp, p, &dns);
}
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, -1);
}
//printf("~~~\n%s\n~~~\n",d.data());

View file

@ -178,6 +178,10 @@ namespace ZeroTier {
#define ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP "COO"
// dns (binary blobs)
#define ZT_NETWORKCONFIG_DICT_KEY_DNS "DNS"
// authentication URL
#define ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL "aurl"
// authentication expiry
#define ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME "aexpt"
// Legacy fields -- these are obsoleted but are included when older clients query
@ -604,6 +608,16 @@ public:
* ZT pushed DNS configuration
*/
ZT_VirtualNetworkDNS dns;
/**
* Authentication URL if authentication is required
*/
char authenticationURL[256];
/**
* Time current authentication expires or -1 if external authentication is disabled
*/
int64_t authenticationExpiryTime;
};
} // namespace ZeroTier

View file

@ -38,7 +38,8 @@ public:
NC_ERROR_NONE = 0,
NC_ERROR_OBJECT_NOT_FOUND = 1,
NC_ERROR_ACCESS_DENIED = 2,
NC_ERROR_INTERNAL_SERVER_ERROR = 3
NC_ERROR_INTERNAL_SERVER_ERROR = 3,
NC_ERROR_AUTHENTICATION_REQUIRED = 4
};
/**
@ -69,12 +70,17 @@ public:
/**
* Send a network configuration request error
*
* If errorData/errorDataSize are provided they must point to a valid serialized
* Dictionary containing error data. They can be null/zero if not specified.
*
* @param nwid Network ID
* @param requestPacketId Request packet ID or 0 if none
* @param destination Destination peer Address
* @param errorCode Error code
* @param errorData Data associated with error or NULL if none
* @param errorDataSize Size of errorData in bytes
*/
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode) = 0;
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize) = 0;
};
NetworkController() {}

View file

@ -731,7 +731,7 @@ void Node::ncSendRevocation(const Address &destination,const Revocation &rev)
}
}
void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode)
void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize)
{
if (destination == RR->identity.address()) {
SharedPtr<Network> n(network(nwid));
@ -744,6 +744,9 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des
case NetworkController::NC_ERROR_ACCESS_DENIED:
n->setAccessDenied();
break;
case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED: {
}
break;
default: break;
}
@ -760,8 +763,16 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des
case NetworkController::NC_ERROR_ACCESS_DENIED:
outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_);
break;
case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED:
outp.append((unsigned char)Packet::ERROR_NETWORK_AUTHENTICATION_REQUIRED);
break;
}
outp.append(nwid);
if ((errorData)&&(errorDataSize > 0))
outp.append(errorData, errorDataSize);
RR->sw->send((void *)0,outp,true);
} // else we can't send an ERROR() in response to nothing, so discard
}

View file

@ -245,7 +245,7 @@ public:
virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig);
virtual void ncSendRevocation(const Address &destination,const Revocation &rev);
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode);
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize);
inline const Address &remoteTraceTarget() const { return _remoteTraceTarget; }
inline Trace::Level remoteTraceLevel() const { return _remoteTraceLevel; }

View file

@ -792,6 +792,12 @@ public:
*
* ERROR response payload:
* <[8] 64-bit network ID>
* <[2] 16-bit length of error-related data (optional)>
* <[...] error-related data (optional)>
*
* Error related data is a Dictionary containing things like a URL
* for authentication or a human-readable error message, and is
* optional and may be absent or empty.
*/
VERB_NETWORK_CONFIG_REQUEST = 0x0b,
@ -1076,7 +1082,10 @@ public:
ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */
/* Multicasts to this group are not wanted */
ERROR_UNWANTED_MULTICAST = 0x08
ERROR_UNWANTED_MULTICAST = 0x08,
/* Network requires external or 2FA authentication (e.g. SSO). */
ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09
};
template<unsigned int C2>