aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/httpclientauth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenhttp/httpclientauth.cpp')
-rw-r--r--src/zenhttp/httpclientauth.cpp111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/zenhttp/httpclientauth.cpp b/src/zenhttp/httpclientauth.cpp
index 04ac2ad3f..39efe1d0c 100644
--- a/src/zenhttp/httpclientauth.cpp
+++ b/src/zenhttp/httpclientauth.cpp
@@ -2,14 +2,26 @@
#include <zenhttp/httpclientauth.h>
+#include <zencore/fmtutils.h>
+#include <zencore/logging.h>
+#include <zencore/process.h>
+#include <zencore/scopeguard.h>
+#include <zencore/timer.h>
+#include <zencore/uid.h>
#include <zenhttp/auth/authmgr.h>
+#include <ctime>
+
ZEN_THIRD_PARTY_INCLUDES_START
#include <cpr/cpr.h>
#include <fmt/format.h>
#include <json11.hpp>
ZEN_THIRD_PARTY_INCLUDES_END
+#if ZEN_PLATFORM_WINDOWS
+# define timegm _mkgmtime
+#endif // ZEN_PLATFORM_WINDOWS
+
namespace zen { namespace httpclientauth {
using namespace std::literals;
@@ -41,6 +53,7 @@ namespace zen { namespace httpclientauth {
if (Response.error || Response.status_code != 200)
{
+ ZEN_WARN("Failed fetching OAuth access token {}. Reason: '{}'", OAuthParams.Url, Response.reason);
return HttpClientAccessToken{};
}
@@ -49,6 +62,7 @@ namespace zen { namespace httpclientauth {
if (JsonError.empty() == false)
{
+ ZEN_WARN("Unable to parse OAuth json response from {}. Reason: '{}'", OAuthParams.Url, JsonError);
return HttpClientAccessToken{};
}
@@ -73,4 +87,101 @@ namespace zen { namespace httpclientauth {
return CreateFromOpenIdProvider(AuthManager, "Default"sv);
}
+ static HttpClientAccessToken GetOidcTokenFromExe(const std::filesystem::path& OidcExecutablePath,
+ std::string_view CloudHost,
+ bool Unattended)
+ {
+ Stopwatch Timer;
+
+ CreateProcOptions ProcOptions;
+
+ const std::filesystem::path AuthTokenPath(std::filesystem::temp_directory_path() / fmt::format(".zen-auth-{}", Oid::NewOid()));
+ auto _ = MakeGuard([AuthTokenPath]() { RemoveFile(AuthTokenPath); });
+
+ const std::string ProcArgs = fmt::format("{} --AuthConfigUrl {} --OutFile {} --Unattended={}",
+ OidcExecutablePath,
+ CloudHost,
+ AuthTokenPath,
+ Unattended ? "true"sv : "false"sv);
+ ZEN_DEBUG("Running: {}", ProcArgs);
+ ProcessHandle Proc;
+ Proc.Initialize(CreateProc(OidcExecutablePath, ProcArgs, ProcOptions));
+ if (!Proc.IsValid())
+ {
+ throw std::runtime_error(fmt::format("failed to launch '{}'", OidcExecutablePath));
+ }
+
+ int ExitCode = Proc.WaitExitCode();
+
+ auto EndTime = std::chrono::system_clock::now();
+
+ if (ExitCode == 0)
+ {
+ IoBuffer Body = IoBufferBuilder::MakeFromFile(AuthTokenPath);
+ std::string JsonText(reinterpret_cast<const char*>(Body.GetData()), Body.GetSize());
+
+ std::string JsonError;
+ json11::Json Json = json11::Json::parse(JsonText, JsonError);
+
+ if (JsonError.empty() == false)
+ {
+ ZEN_WARN("Unable to parse Oidcs json response from {}. Reason: '{}'", AuthTokenPath, JsonError);
+ return HttpClientAccessToken{};
+ }
+ std::string Token = Json["Token"].string_value();
+ std::string ExpiresAtUTCString = Json["ExpiresAtUtc"].string_value();
+ ZEN_ASSERT(!ExpiresAtUTCString.empty());
+
+ int Year = 0;
+ int Month = 0;
+ int Day = 0;
+ int Hour = 0;
+ int Minute = 0;
+ int Second = 0;
+ int Millisecond = 0;
+ sscanf(ExpiresAtUTCString.c_str(), "%d-%d-%dT%d:%d:%d.%dZ", &Year, &Month, &Day, &Hour, &Minute, &Second, &Millisecond);
+
+ std::tm Time = {
+ Second,
+ Minute,
+ Hour,
+ Day,
+ Month - 1,
+ Year - 1900,
+ };
+
+ time_t UTCTime = timegm(&Time);
+ HttpClientAccessToken::TimePoint ExpireTime = std::chrono::system_clock::from_time_t(UTCTime);
+ ExpireTime += std::chrono::microseconds(Millisecond);
+
+ return HttpClientAccessToken{.Value = fmt::format("Bearer {}"sv, Token), .ExpireTime = ExpireTime};
+ }
+ else
+ {
+ ZEN_WARN("Failed running {} to get auth token, error code {}", OidcExecutablePath, ExitCode);
+ }
+ return HttpClientAccessToken{};
+ }
+
+ std::optional<std::function<HttpClientAccessToken()>> CreateFromOidcTokenExecutable(const std::filesystem::path& OidcExecutablePath,
+ std::string_view CloudHost)
+ {
+ HttpClientAccessToken InitialToken = GetOidcTokenFromExe(OidcExecutablePath, CloudHost, false);
+ if (InitialToken.IsValid())
+ {
+ return [OidcExecutablePath = std::filesystem::path(OidcExecutablePath),
+ CloudHost = std::string(CloudHost),
+ InitialToken]() mutable {
+ if (InitialToken.IsValid())
+ {
+ HttpClientAccessToken Result = InitialToken;
+ InitialToken = {};
+ return Result;
+ }
+ return GetOidcTokenFromExe(OidcExecutablePath, CloudHost, true);
+ };
+ }
+ return {};
+ }
+
}} // namespace zen::httpclientauth