Postgres code for SSO (almost certainly needs work)
This commit is contained in:
parent
198e6f765c
commit
c470c6255e
6 changed files with 102 additions and 13 deletions
|
@ -16,6 +16,7 @@
|
|||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/SHA512.hpp"
|
||||
#include "EmbeddedNetworkController.hpp"
|
||||
#include "../version.h"
|
||||
#include "Redis.hpp"
|
||||
|
@ -90,6 +91,15 @@ PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, R
|
|||
_myAddressStr = myId.address().toString(myAddress);
|
||||
_connString = std::string(path) + " application_name=controller_" + _myAddressStr;
|
||||
|
||||
memset(_ssoPsk, 0, sizeof(_ssoPsk));
|
||||
char *const ssoPskHex = getenv("ZT_SSO_PSK");
|
||||
if (ssoPskHex) {
|
||||
// SECURITY: note that ssoPskHex will always be null-terminated if libc acatually
|
||||
// returns something non-NULL. If the hex encodes something shorter than 48 bytes,
|
||||
// it will be padded at the end with zeroes. If longer, it'll be truncated.
|
||||
Utils::unhex(ssoPskHex, _ssoPsk, sizeof(_ssoPsk));
|
||||
}
|
||||
|
||||
// Database Schema Version Check
|
||||
PGconn *conn = getPgConn();
|
||||
if (PQstatus(conn) != CONNECTION_OK) {
|
||||
|
@ -263,6 +273,88 @@ void PostgreSQL::nodeIsOnline(const uint64_t networkId, const uint64_t memberId,
|
|||
}
|
||||
}
|
||||
|
||||
void PostgreSQL::updateMemberOnLoad(const uint64_t networkId, const uint64_t memberId, nlohmann::json &member)
|
||||
{
|
||||
const uint64_t nwid = OSUtils::jsonIntHex(member["nwid"],0ULL);
|
||||
const uint64_t id = OSUtils::jsonIntHex(member["id"],0ULL);
|
||||
char nwids[24],ids[24];
|
||||
OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", nwid);
|
||||
OSUtils::ztsnprintf(ids, sizeof(ids), "%.10llx", id);
|
||||
|
||||
bool have_auth = false;
|
||||
try {
|
||||
PGconn *conn = getPgConn();
|
||||
if (PQstatus(conn) != CONNECTION_OK) {
|
||||
fprintf(stderr, "Bad Database Connection: %s", PQerrorMessage(conn));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *params[1] = { nwids };
|
||||
PGresult *res = PQexecParams(conn, "SELECT org.client_id, org.authorization_endpoint 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",
|
||||
1,
|
||||
NULL,
|
||||
params,
|
||||
NULL,
|
||||
NULL,
|
||||
0);
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
|
||||
fprintf(stderr, "Org client_id and authorization_endpoint lookup failed: %s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (PQntuples(res) >= 1) {
|
||||
std::string client_id = PQgetvalue(res, 0, 0);
|
||||
std::string authorization_endpoint = PQgetvalue(res, 0, 1);
|
||||
PQclear(res);
|
||||
if ((!client_id.empty())&&(!authorization_endpoint.empty())) {
|
||||
const char *params2[2] = { nwids, ids };
|
||||
res = PQexecParams(conn, "SELECT e.nonce, e.authentication_expiry_time FROM ztc_sso_expiry AS e WHERE e.network_id = $1 AND e.member_id = $2 ORDER BY n.authentication_expiry_time DESC LIMIT 1",
|
||||
1,
|
||||
NULL,
|
||||
params2,
|
||||
NULL,
|
||||
NULL,
|
||||
0);
|
||||
if (PQntuples(res) >= 1) {
|
||||
std::string nonce = PQgetvalue(res, 0, 0);
|
||||
int64_t authentication_expiry_time = std::stoll(PQgetvalue(res, 0, 1));
|
||||
if ((authentication_expiry_time >= 0)&&(!nonce.empty())) {
|
||||
have_auth = true;
|
||||
|
||||
uint8_t state[48];
|
||||
HMACSHA384(_ssoPsk, nonce.data(), (unsigned int)nonce.length(), state);
|
||||
char state_hex[256];
|
||||
Utils::hex(state, 48, state_hex);
|
||||
char authenticationURL[4096];
|
||||
const char *redirect_url = "redirect_uri=http%3A%2F%2Fmy.zerotier.com%2Fapi%2Fnetwork%2Fsso-auth"; // TODO: this should be configurable
|
||||
Utils::ztsnprintf(authenticationURL, sizeof(authenticationURL),
|
||||
"%s?response_type=id_token&response_mode=form_post&scope=openid+email+profile&redriect_uri=%s&nonce=%s&state=%s&client_id=%s",
|
||||
authorization_endpoint.c_str(),
|
||||
redirect_url,
|
||||
nonce.c_str(),
|
||||
state_hex, // NOTE: should these be URL escaped? Don't think there's a risk as they are not user definable.
|
||||
client_id.c_str());
|
||||
|
||||
member["authenticationExpiryTime"] = authentication_expiry_time;
|
||||
member["authenticationURL"] = authenticationURL;
|
||||
}
|
||||
}
|
||||
PQclear(res);
|
||||
}
|
||||
} else {
|
||||
PQclear(res);
|
||||
}
|
||||
|
||||
} catch (sw::redis::Error &e) {
|
||||
fprintf(stderr, "ERROR: Error updating member on load, in Redis: %s\n", e.what());
|
||||
exit(-1);
|
||||
} catch (std::exception &e) {
|
||||
fprintf(stderr, "ERROR: Error updating member on load: %s\n", e.what());
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void PostgreSQL::initializeNetworks(PGconn *conn)
|
||||
{
|
||||
try {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue