From 54afe7e5d4edfa5e7ed838662e02e5def4e05f9f Mon Sep 17 00:00:00 2001 From: James Tanner Date: Wed, 13 Nov 2024 13:57:15 -0500 Subject: [PATCH] Handle CRC service accounts. No-Issue Signed-off-by: James Tanner --- galaxy_ng/app/auth/auth.py | 32 ++++-- galaxy_ng/tests/integration/utils/tasks.py | 2 +- profiles/insights/proxy/main.go | 116 ++++++++++++++++++++- 3 files changed, 137 insertions(+), 13 deletions(-) diff --git a/galaxy_ng/app/auth/auth.py b/galaxy_ng/app/auth/auth.py index 7dfde6464f..9a27f0489b 100644 --- a/galaxy_ng/app/auth/auth.py +++ b/galaxy_ng/app/auth/auth.py @@ -43,14 +43,32 @@ def authenticate(self, request): return None header = self._decode_header(request.META[self.header]) + identity = header.get("identity") + if identity is None: + raise AuthenticationFailed - try: - identity = header['identity'] - account = identity['account_number'] - - user = identity['user'] - username = user['username'] - except KeyError: + identity_type = identity.get("type", "User") + if identity_type == "User": + try: + identity = header['identity'] + account = identity['account_number'] + + user = identity['user'] + username = user['username'] + except KeyError: + raise AuthenticationFailed + elif identity_type == "ServiceAccount": + try: + service_account = identity['service_account'] + # service-account- is too long for the username field + username = service_account['username'].replace('service-account-', '') + # make this the same? + account = username + # all other attributes for service accounts is null + user = {} + except KeyError: + raise AuthenticationFailed + else: raise AuthenticationFailed email = user.get('email', '') diff --git a/galaxy_ng/tests/integration/utils/tasks.py b/galaxy_ng/tests/integration/utils/tasks.py index 64a7226416..eccf51f1b9 100644 --- a/galaxy_ng/tests/integration/utils/tasks.py +++ b/galaxy_ng/tests/integration/utils/tasks.py @@ -88,7 +88,7 @@ def wait_for_task_ui_client(gc, task): if state == 'completed': break time.sleep(SLEEP_SECONDS_POLLING) - assert state == 'completed' + assert state == 'completed', ds def wait_for_namespace_tasks_gk(gc, timeout=300): diff --git a/profiles/insights/proxy/main.go b/profiles/insights/proxy/main.go index e8f1c19cc1..0bb2ea2483 100644 --- a/profiles/insights/proxy/main.go +++ b/profiles/insights/proxy/main.go @@ -46,6 +46,11 @@ type User struct { IsOrgAdmin bool `json:"is_org_admin"` } +type ServiceAccount struct { + ClientId string `json:"client_id"` + Username string `json:"username"` +} + type Account struct { AccountNumber int `json:"account_number"` User User `json:"user"` @@ -60,6 +65,24 @@ type XRHItentity struct { Entitlements Entitlement `json:"entitlements"` } +type XRHSVCItentity struct { + Entitlements Entitlement `json:"entitlements"` + Identity struct { + AuthType string `json:"auth_type"` + Internal struct { + AuthTime int `json:"auth_time"` + CrossAccess bool `json:"cross_access"` + OrgID string `json:"org_id"` + } `json:"internal"` + OrgID string `json:"org_id"` + Type string `json:"type"` + ServiceAccount struct { + ClientID string `json:"client_id"` + Username string `json:"username"` + } `json:"service_account"` + } `json:"identity"` +} + var accounts = map[string]Account{ "jdoe": { AccountNumber: 6089719, @@ -103,6 +126,13 @@ var accounts = map[string]Account{ }, } +var serviceAccounts = map[string]ServiceAccount { + "service-account-b69eaf9e-e6a6-4f9e-805e-02987daddfbd": { + Username: "service-account-b69eaf9e-e6a6-4f9e-805e-02987daddfbd", + ClientId: "b69eaf9e-e6a6-4f9e-805e-02987daddfbd", + }, +} + func randomString(length int) string { rand.Seed(time.Now().UnixNano()) b := make([]byte, length) @@ -149,19 +179,95 @@ func userToIentityHeader(account Account) string { return base64.StdEncoding.EncodeToString([]byte(data)) } +func serviceAccountToIentityHeader(svc_account ServiceAccount) string { + /* + { + "entitlements": {}, + "identity": { + "auth_type": "jwt-auth", + "internal": { + "auth_time": 500, + "cross_access": false, + "org_id": "456" + }, + "org_id": "456", + "type": "ServiceAccount", + "service_account": { + "client_id": "b69eaf9e-e6a6-4f9e-805e-02987daddfbd", + "username": "service-account-b69eaf9e-e6a6-4f9e-805e-02987daddfbd" + } + } + } + */ + + data := XRHSVCItentity{ + Entitlements: Entitlement{ + Insights: map[string]bool{ + "is_entitled": true, + "is_trial": false, + }, + }, + Identity: struct { + AuthType string `json:"auth_type"` + Internal struct { + AuthTime int `json:"auth_time"` + CrossAccess bool `json:"cross_access"` + OrgID string `json:"org_id"` + } `json:"internal"` + OrgID string `json:"org_id"` + Type string `json:"type"` + ServiceAccount struct { + ClientID string `json:"client_id"` + Username string `json:"username"` + } `json:"service_account"` + }{ + AuthType: "jwt-auth", + Internal: struct { + AuthTime int `json:"auth_time"` + CrossAccess bool `json:"cross_access"` + OrgID string `json:"org_id"` + }{ + AuthTime: 500, + CrossAccess: false, + OrgID: "456", + }, + OrgID: "456", + Type: "ServiceAccount", + ServiceAccount: struct { + ClientID string `json:"client_id"` + Username string `json:"username"` + }{ + ClientID: svc_account.ClientId, + Username: svc_account.Username, + }, + }, + } + jsonData, _ := json.MarshalIndent(data, "", " ") + + fmt.Printf("Setting X-RH-IDENTITY: %s\n", string(jsonData)) + return base64.StdEncoding.EncodeToString([]byte(jsonData)) + +} + func setRHIdentityHeader(req *http.Request) { auth_header := req.Header.Get("Authorization") if auth_header != "" { if strings.Contains(auth_header, "Basic") { + user, pass, _ := req.BasicAuth() fmt.Printf("Authenticating with basic auth: %s:%s\n", user, pass) - if account, ok := accounts[user]; ok { - req.Header.Set("X-RH-IDENTITY", userToIentityHeader(account)) - } else { - fmt.Printf("User not found: %s", user) + if svc_account, ok := serviceAccounts[user]; ok { + req.Header.Set("X-RH-IDENTITY", serviceAccountToIentityHeader(svc_account)) + } else { + + if account, ok := accounts[user]; ok { + req.Header.Set("X-RH-IDENTITY", userToIentityHeader(account)) + } else { + fmt.Printf("User not found: %s", user) + } } } else if strings.Contains(auth_header, "Bearer") { @@ -378,7 +484,7 @@ func main() { data, _ := ioutil.ReadAll(upstreamServerResponse.Body) modified := downloadUrlReg.ReplaceAll(data, replacementURL) - fmt.Printf("MODIFIED DATA: %s\n", modified) + //fmt.Printf("MODIFIED DATA: %s\n", modified) // Write the response rw.WriteHeader(upstreamServerResponse.StatusCode)