From 07194a6bc033689b142e642a85c04a3c3ae2ae7f Mon Sep 17 00:00:00 2001 From: pg9182 <96569817+pg9182@users.noreply.github.com> Date: Mon, 22 Jan 2024 06:59:50 -0500 Subject: pkg/api/api0: Implement stryder username source --- pkg/api/api0/client.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++--- pkg/api/api0/metrics.go | 8 ++++++ 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/pkg/api/api0/client.go b/pkg/api/api0/client.go index b62107d..b3fd686 100644 --- a/pkg/api/api0/client.go +++ b/pkg/api/api0/client.go @@ -41,6 +41,17 @@ const ( // Get the username from EAX, but fall back to the Origin API on failure. UsernameSourceEAXOrigin UsernameSource = "eax-origin" + + // Get the username from Stryder (available since October 2, 2023). Note + // that this source only returns usernames for valid tokens. + UsernameSourceStryder UsernameSource = "stryder" + + // Get the username from Stryder, but fall back to EAX on missing/failure. + UsernameSourceStryderEAX UsernameSource = "stryder-eax" + + // Get the username from Stryder, but also check EAX and warn if it's + // different. + UsernameSourceStryderEAXDebug UsernameSource = "stryder-eax-debug" ) type MainMenuPromos struct { @@ -149,6 +160,7 @@ func (h *Handler) handleClientOriginAuth(w http.ResponseWriter, r *http.Request) default: } + var stryderRes []byte if !h.InsecureDevNoCheckPlayerAuth { token := r.URL.Query().Get("token") if token == "" { @@ -162,7 +174,7 @@ func (h *Handler) handleClientOriginAuth(w http.ResponseWriter, r *http.Request) stryderCtx, cancel := context.WithTimeout(r.Context(), time.Second*5) defer cancel() - stryderRes, err := stryder.NucleusAuth(stryderCtx, token, uid) + stryderRes, err = stryder.NucleusAuth(stryderCtx, token, uid) h.m().client_originauth_stryder_auth_duration_seconds.UpdateDuration(stryderStart) if err != nil { switch { @@ -223,7 +235,7 @@ func (h *Handler) handleClientOriginAuth(w http.ResponseWriter, r *http.Request) default: } - username := h.lookupUsername(r, uid) + username := h.lookupUsername(r, uid, stryderRes) select { case <-r.Context().Done(): // check if the request was canceled to avoid making unnecessary requests @@ -302,7 +314,7 @@ func (h *Handler) handleClientOriginAuth(w http.ResponseWriter, r *http.Request) // lookupUsername gets the username for uid according to the configured // UsernameSource, returning an empty string if not found or on error. -func (h *Handler) lookupUsername(r *http.Request, uid uint64) (username string) { +func (h *Handler) lookupUsername(r *http.Request, uid uint64, stryderRes []byte) (username string) { switch h.UsernameSource { case UsernameSourceNone: break @@ -348,6 +360,35 @@ func (h *Handler) lookupUsername(r *http.Request, uid uint64) (username string) Msgf("failed to get username from eax, but got it from origin") } } + case UsernameSourceStryder: + username, _ = h.lookupUsernameStryder(r, uid, stryderRes) + case UsernameSourceStryderEAX: + username, _ = h.lookupUsernameStryder(r, uid, stryderRes) + if username == "" { + if eaxUsername, ok := h.lookupUsernameEAX(r, uid); ok { + username = eaxUsername + hlog.FromRequest(r).Warn(). + Uint64("uid", uid). + Str("eax_username", eaxUsername). + Msgf("failed to get username from stryder, but got it from eax") + } + } + case UsernameSourceStryderEAXDebug: + username, _ = h.lookupUsernameStryder(r, uid, stryderRes) + if eaxUsername, ok := h.lookupUsernameEAX(r, uid); ok { + if eaxUsername != username { + hlog.FromRequest(r).Warn(). + Uint64("uid", uid). + Str("stryder_username", username). + Str("eax_username", eaxUsername). + Msgf("got username from stryder and eax, but they don't match; using the stryder one") + } + } else { + hlog.FromRequest(r).Warn(). + Uint64("uid", uid). + Str("stryder_username", username). + Msgf("got username from stryder, but failed to get username from eax") + } default: hlog.FromRequest(r).Error(). Msgf("unknown username source %q", h.UsernameSource) @@ -467,6 +508,31 @@ func (h *Handler) lookupUsernameEAX(r *http.Request, uid uint64) (username strin return } +// lookupUsernameStryder gets the username for uid from the Stryder response, +// returning an empty string if the username is empty, or false if the +// username is not present in the response or the response is invalid. +func (h *Handler) lookupUsernameStryder(r *http.Request, uid uint64, res []byte) (username string, ok bool) { + select { + case <-r.Context().Done(): // check if the request was canceled to avoid polluting the metrics + return + default: + } + u, err := stryder.NucleusAuthUsername(res) + if err != nil { + hlog.FromRequest(r).Warn(). + Err(err). + Uint64("uid", uid). + Str("username_source", "stryder"). + Msgf("failed to get username from stryder nucleus auth response") + h.m().client_originauth_stryder_username_lookup_calls_total.fail_other_error.Inc() + } else if u == "" { + h.m().client_originauth_stryder_username_lookup_calls_total.notfound.Inc() + } else { + h.m().client_originauth_stryder_username_lookup_calls_total.success.Inc() + } + return u, err == nil +} + func (h *Handler) handleClientAuthWithServer(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodOptions && r.Method != http.MethodPost { h.m().client_authwithserver_requests_total.http_method_not_allowed.Inc() diff --git a/pkg/api/api0/metrics.go b/pkg/api/api0/metrics.go index ac54944..0c18d0a 100644 --- a/pkg/api/api0/metrics.go +++ b/pkg/api/api0/metrics.go @@ -86,6 +86,11 @@ type apiMetrics struct { fail_update_check *metrics.Counter fail_other_error *metrics.Counter } + client_originauth_stryder_username_lookup_calls_total struct { + success *metrics.Counter + notfound *metrics.Counter + fail_other_error *metrics.Counter + } client_authwithserver_requests_total struct { success *metrics.Counter reject_bad_request *metrics.Counter @@ -275,6 +280,9 @@ func (h *Handler) m() *apiMetrics { mo.client_originauth_eax_username_lookup_calls_total.notfound = mo.set.NewCounter(`atlas_api0_client_originauth_eax_username_lookup_calls_total{result="notfound"}`) mo.client_originauth_eax_username_lookup_calls_total.fail_update_check = mo.set.NewCounter(`atlas_api0_client_originauth_eax_username_lookup_calls_total{result="fail_update_check"}`) mo.client_originauth_eax_username_lookup_calls_total.fail_other_error = mo.set.NewCounter(`atlas_api0_client_originauth_eax_username_lookup_calls_total{result="fail_other_error"}`) + mo.client_originauth_stryder_username_lookup_calls_total.success = mo.set.NewCounter(`atlas_api0_client_originauth_stryder_username_lookup_calls_total{result="success"}`) + mo.client_originauth_stryder_username_lookup_calls_total.notfound = mo.set.NewCounter(`atlas_api0_client_originauth_stryder_username_lookup_calls_total{result="notfound"}`) + mo.client_originauth_stryder_username_lookup_calls_total.fail_other_error = mo.set.NewCounter(`atlas_api0_client_originauth_stryder_username_lookup_calls_total{result="fail_other_error"}`) mo.client_authwithserver_requests_total.success = mo.set.NewCounter(`atlas_api0_client_authwithserver_requests_total{result="success"}`) mo.client_authwithserver_requests_total.reject_bad_request = mo.set.NewCounter(`atlas_api0_client_authwithserver_requests_total{result="reject_bad_request"}`) mo.client_authwithserver_requests_total.reject_versiongate = mo.set.NewCounter(`atlas_api0_client_authwithserver_requests_total{result="reject_versiongate"}`) -- cgit v1.2.3