Starbound/attic/old_source/StarAuthentication.cpp
2025-03-21 22:23:30 +11:00

290 lines
8.4 KiB
C++

#include "StarAuthentication.hpp"
#include "StarRoot.hpp"
#include "StarConfiguration.hpp"
#include "StarClientAuthentication.hpp"
#include "StarAuthenticationConnection.hpp"
#include "StarAuthenticationService.hpp"
#include "StarLogging.hpp"
#include "StarFile.hpp"
using namespace Star::Auth;
namespace Star {
class AuthenticationImpl {
public:
AuthenticationImpl(Configuration const* configuration) {
m_rootKey = make_shared<Key>();
m_clientKey = make_shared<Key>();
m_rootKey->loadPublicKey(configuration->getString("rootKey"));
m_authenticator = make_shared<ClientAuthentication>(m_rootKey);
m_connector = make_shared<AuthenticationConnection>(configuration->getString("authHostname"), configuration->getInt("authPort"));
m_claimFile = Root::singleton().toStoragePath(configuration->getString("claimFile"));
m_hasClaim = false;
m_lazyLoadClaim = true;
m_remoteValidated = false;
}
bool validateClaim(bool remoteValidate) {
if (m_lazyLoadClaim)
loadClaim();
if (validClaim()) {
if (remoteValidate && !m_remoteValidated) {
remoteValidateClaim();
}
}
if (!m_hasClaim) {
deleteClaim();
}
return m_hasClaim;
}
Variant claim() {
if (!m_hasClaim)
throw StarException("No valid claim.");
return m_claim;
}
String decrypt(String const& message) {
if (!m_hasClaim)
throw StarException("No valid claim.");
return m_clientKey->decryptMessage(message);
}
String sign(String const& message) {
if (!m_hasClaim)
throw StarException("No valid claim.");
return m_clientKey->signMessage(message);
}
bool logon(String const& username, String const& passwordHash) {
m_lazyLoadClaim = false;
m_hasClaim = false;
m_remoteValidated = false;
try {
Variant authPubKeyRequest = VariantMap{
{"command", "getAuthKey"}
};
auto authSignatureString = m_connector->query(authPubKeyRequest.repr(0, true));
Variant authSignature = Variant::parse(authSignatureString);
if (!AuthenticationService::validateAuthSignature(*m_rootKey, authSignature))
throw StarException("Auth server key failure.");
m_clientKey->regenerate();
auto authsvrRequest = m_authenticator->authsvrRequest(username, passwordHash, authSignatureString, *m_clientKey);
Variant authorizeClientRequest = VariantMap{
{"command", "authorizeClient"},
{"body", authsvrRequest}
};
auto authsvrResponse = m_connector->query(authorizeClientRequest.repr(0, true));
auto logonResult = m_authenticator->authsvrResponse(authsvrResponse, *m_clientKey);
if (!AuthenticationService::validateClientClaim(*m_rootKey, logonResult))
throw StarException("Logon failure.");
m_claim = logonResult;
m_hasClaim = true;
m_remoteValidated = true;
saveClaim();
} catch (std::exception const& e) {
Logger::error("Exception while validating claim. %s", e.what());
}
return m_hasClaim;
}
bool remoteValidateClaim() {
if (!m_hasClaim)
return m_hasClaim;
try {
Variant authPubKeyRequest = VariantMap{
{"command", "getAuthKey"}
};
auto authSignatureString = m_connector->query(authPubKeyRequest.repr(0, true));
Variant authSignature = Variant::parse(authSignatureString);
if (!AuthenticationService::validateAuthSignature(*m_rootKey, authSignature))
throw StarException("Auth server key failure.");
auto authsvrRequest = m_authenticator->authsvrValidateRequest(m_claim, authSignatureString, *m_clientKey);
Variant authorizeClientRequest = VariantMap{
{"command", "validateClient"},
{"body", authsvrRequest}
};
auto authsvrResponse = m_connector->query(authorizeClientRequest.repr(0, true));
auto validateResult = m_authenticator->authsvrValidateResponse(authsvrResponse, *m_clientKey);
if (!validateResult) {
m_hasClaim = false;
m_remoteValidated = false;
}
} catch (std::exception const& e) {
// validation failure will not cause an exception btw
Logger::error("Exception while validating claim. %s", e.what());
}
return m_hasClaim;
}
bool validClaim() {
if (!m_hasClaim)
return false;
m_hasClaim = AuthenticationService::validateClientClaim(*m_rootKey, m_claim);
if (!m_hasClaim)
m_remoteValidated = false;
return m_hasClaim;
}
void loadClaim() {
m_lazyLoadClaim = false;
try {
m_hasClaim = false;
m_remoteValidated = false;
if (m_claimFile.empty())
return;
if (!File::isFile(m_claimFile))
return;
VariantMap file = Variant::parseJson(File::readFileString(m_claimFile)).toMap();
m_claim = file["claim"];
m_hasClaim = true;
m_clientKey->loadPrivateKey(file["key"].toString());
m_hasClaim = validClaim();
} catch (std::exception const& e) {
Logger::error("Exception while loading claim. %s", e.what());
}
if (!m_hasClaim) {
deleteClaim();
}
}
void saveClaim() {
m_lazyLoadClaim = false;
m_hasClaim = validClaim();
if (!m_hasClaim) {
deleteClaim();
return;
}
if (m_claimFile.empty())
return;
try {
VariantMap file;
file.insert("key", m_clientKey->privateKey());
file.insert("claim", m_claim);
File::overwriteFileWithRename(Variant(file).toJson(1), m_claimFile);
} catch (std::exception const& e) {
Logger::error("Exception while saving claim. %s", e.what());
}
}
void deleteClaim() {
m_lazyLoadClaim = false;
m_hasClaim = false;
m_remoteValidated = false;
m_claim = {};
try {
if (m_claimFile.empty())
return;
if (File::isFile(m_claimFile)) {
if (File::isFile(m_claimFile + ".old"))
File::remove(m_claimFile + ".old");
File::rename(m_claimFile, m_claimFile + ".old");
File::remove(m_claimFile + ".old");
}
} catch (std::exception const& e) {
Logger::error("Exception while removing claim. %s", e.what());
}
}
shared_ptr<ClientAuthentication> m_authenticator;
shared_ptr<AuthenticationConnection> m_connector;
String m_claimFile;
bool m_lazyLoadClaim;
bool m_hasClaim;
bool m_remoteValidated;
Variant m_claim;
shared_ptr<Key> m_rootKey;
shared_ptr<Key> m_clientKey;
};
class SharedClaimImpl: public SharedClaim {
public:
SharedClaimImpl(AuthenticationImpl* parent, Variant const& claim) {
m_parent = parent;
m_claim = claim;
m_clientKey = make_shared<Key>();
m_clientKey->loadPublicKey(m_claim.get("claim").get("metadata").get("clientPublicKey").toString());
}
bool validateClaim() {
return AuthenticationService::validateClientClaim(*(m_parent->m_rootKey), m_claim);
}
Variant claim() {
return m_claim;
}
String encrypt(String const& message) {
return m_clientKey->encryptMessage(message);
}
bool verify(String const& message, String const& signature) {
return m_clientKey->verifyMessage(message, signature);
}
String username() {
return m_claim.get("claim").get("metadata").getString("username");
}
AuthenticationImpl* m_parent;
Variant m_claim;
shared_ptr<Key> m_clientKey;
};
void Authentication::load() {
MutexLocker locker(m_mutex);
if (!m_impl)
m_impl = make_shared<AuthenticationImpl>(Root::singleton().configuration());
}
bool Authentication::validateClaim(bool remoteValidate) {
if (remoteValidate) {
auto remotevalidationimpl = make_shared<AuthenticationImpl>(Root::singleton().configuration());
bool result = remotevalidationimpl->validateClaim(true);
{
MutexLocker locker(m_mutex);
m_impl = remotevalidationimpl;
}
return result;
} else {
MutexLocker locker(m_mutex);
return m_impl->validateClaim(false);
}
}
bool Authentication::logon(String const& username, String const& passwordHash) {
MutexLocker locker(m_mutex);
return m_impl->logon(username, passwordHash);
}
Variant Authentication::claim() {
MutexLocker locker(m_mutex);
return m_impl->claim();
}
String Authentication::decrypt(String const& message) {
MutexLocker locker(m_mutex);
return m_impl->decrypt(message);
}
String Authentication::sign(String const& message) {
MutexLocker locker(m_mutex);
return m_impl->sign(message);
}
SharedClaimPtr Authentication::sharedClaim(Variant const& data) {
MutexLocker locker(m_mutex);
if (!m_impl)
throw StarException("Invalid state");
return make_shared<SharedClaimImpl>(m_impl.get(), data);
}
}