From c5d2daa24b1ab0d36ec68a1036abf038beb08214 Mon Sep 17 00:00:00 2001 From: jonathancri Date: Thu, 17 Oct 2024 09:16:16 +0200 Subject: [PATCH 1/5] feat: add support to new crossprofiles --- config/sso_extended.go | 19 +++--------- server/auth/devhub/aplication.go | 52 +++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/config/sso_extended.go b/config/sso_extended.go index 0e1d5307122a..d47af6ff0b28 100644 --- a/config/sso_extended.go +++ b/config/sso_extended.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "os" - "slices" "strings" "github.com/argoproj/argo-workflows/v3/server/auth/devhub" @@ -33,26 +32,16 @@ func RbacDelegateToLabel(ctx context.Context, mail string, apiUrl, apiPassword, resourcesToFilterPopulated := &ResourcesToFilter{} devhubClient := devhub.NewClient() mailParts := strings.Split(mail, "@") - servicesAndRoles, err := devhub.GetServicesAndRoles(devhubClient, apiUrl, apiPassword, mailParts[0]) + servicesAndGroup, err := devhub.GetServicesAndGroup(devhubClient, apiUrl, apiPassword, mailParts[0], writeGroups) if err != nil { fmt.Printf("Can't Procces the petition on devhub to get roles %+v", err) } - resourcesToFilterPopulated.Group = getUserGroup(servicesAndRoles.Roles, writeGroups) - if servicesAndRoles.Services != nil { - for service := range servicesAndRoles.Services { + resourcesToFilterPopulated.Group = servicesAndGroup.Group + if servicesAndGroup.Services != nil { + for service := range servicesAndGroup.Services { resourcesToFilterPopulated.ArrayLabels = append(resourcesToFilterPopulated.ArrayLabels, service) } resourcesToFilterPopulated.LabelsFilter = fmt.Sprintf("%s in (%s)", label, strings.Join(resourcesToFilterPopulated.ArrayLabels[:], ",")) } return resourcesToFilterPopulated, nil } - -func getUserGroup(roles map[string]string, writeGroups []string) string { - sabyRole := "reader" - for role := range roles { - if slices.Contains(writeGroups, role) { - sabyRole = "writer" - } - } - return sabyRole -} diff --git a/server/auth/devhub/aplication.go b/server/auth/devhub/aplication.go index 1c5186adf355..030dba29028f 100644 --- a/server/auth/devhub/aplication.go +++ b/server/auth/devhub/aplication.go @@ -3,41 +3,63 @@ package devhub import ( "encoding/json" "fmt" + "slices" ) -type RolesAndServices struct { - Roles map[string]string +type GroupAndServices struct { Services map[string]string + Group string } -func GetServicesAndRoles(devhubclient *Client, apiUrl, apiPassword, userToIdentify string) (*RolesAndServices, error) { +func GetServicesAndGroup(devhubclient *Client, apiUrl, apiPassword, userToIdentify string, writeGroups []string) (*GroupAndServices, error) { + var result map[string]interface{} roles := make(map[string]string) services := make(map[string]string) - servicesAndRoles := &RolesAndServices{} + servicesAndGroup := &GroupAndServices{} apiDevhub := fmt.Sprintf("%s/api/identity/%s", apiUrl, userToIdentify) res, err := HandleRequestApiInditex(devhubclient, apiDevhub, "GET", apiPassword, map[string]interface{}{}) if err != nil { return nil, err } - var result map[string]interface{} if err := json.NewDecoder(res.Body).Decode(&result); err != nil { return nil, err } if teams, ok := result["teams"].([]interface{}); ok { - for _, team := range teams { - if len(team.(map[string]interface{})["projects"].([]interface{})) > 0 { - for _, project := range team.(map[string]interface{})["projects"].([]interface{}) { - if relationshipType, ok := project.(map[string]interface{})["relationshipType"].(map[string]interface{}); ok && relationshipType["name"] == "Owner" { - services[project.(map[string]interface{})["key"].(string)] = "service" - for _, profile := range team.(map[string]interface{})["profiles"].([]interface{}) { - roles[profile.(map[string]interface{})["name"].(string)] = "role" + roles, services = GetRolesAndServices(teams, services, roles) + } + + servicesAndGroup.Group = GetGroupByRole(writeGroups, roles) + servicesAndGroup.Services = services + return servicesAndGroup, nil +} + +func GetRolesAndServices(teams []interface{}, services, roles map[string]string) (map[string]string, map[string]string) { + for _, team := range teams { + if len(team.(map[string]interface{})["projects"].([]interface{})) > 0 { + for _, project := range team.(map[string]interface{})["projects"].([]interface{}) { + if relationshipType, ok := project.(map[string]interface{})["relationshipType"].(map[string]interface{}); ok && relationshipType["name"] == "Owner" { + services[project.(map[string]interface{})["key"].(string)] = "service" + for _, profile := range team.(map[string]interface{})["profiles"].([]interface{}) { + roles[profile.(map[string]interface{})["name"].(string)] = "role" + } + if len(team.(map[string]interface{})["effectiveCrossProfiles"].([]string)) > 0 { + for _, effectiveCrossProfile := range team.(map[string]interface{})["effectiveCrossProfiles"].([]string) { + roles[effectiveCrossProfile] = "role" } } } } } } - servicesAndRoles.Roles = roles - servicesAndRoles.Services = services - return servicesAndRoles, nil + return roles, services +} + +func GetGroupByRole(writeGroups []string, roles map[string]string) string { + groupByRole := "reader" + for role := range roles { + if slices.Contains(writeGroups, role) { + groupByRole = "writer" + } + } + return groupByRole } From 98e89d17c53d471e6f43a0bd5421429e82fbb9ce Mon Sep 17 00:00:00 2001 From: jonathancri Date: Thu, 17 Oct 2024 14:17:16 +0200 Subject: [PATCH 2/5] feat: variabilice api endpoint --- config/sso_extended.go | 5 +++-- server/auth/devhub/aplication.go | 4 ++-- server/auth/sso/sso.go | 3 ++- server/auth/sso/sso_test.go | 2 ++ 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/config/sso_extended.go b/config/sso_extended.go index d47af6ff0b28..f819ed79d1f8 100644 --- a/config/sso_extended.go +++ b/config/sso_extended.go @@ -12,6 +12,7 @@ import ( type SSOExtendedLabel struct { ApiPassword string `json:"apiPassword,omitempty"` ApiUrl string `json:"apiUrl,omitempty"` + ApiEndpoint string `json:"apiEndpoint,omitempty"` Label string `json:"label,omitempty"` WriteGroups []string `json:"writeGroups,omitempty"` // The AdminGroup does not filter by label gets all the objects @@ -28,11 +29,11 @@ func CanDelegateByLabel() bool { return os.Getenv("SSO_DELEGATE_RBAC_TO_LABEL") == "true" } -func RbacDelegateToLabel(ctx context.Context, mail string, apiUrl, apiPassword, label string, writeGroups []string) (*ResourcesToFilter, error) { +func RbacDelegateToLabel(ctx context.Context, mail string, apiUrl, apiEndpoint, apiPassword, label string, writeGroups []string) (*ResourcesToFilter, error) { resourcesToFilterPopulated := &ResourcesToFilter{} devhubClient := devhub.NewClient() mailParts := strings.Split(mail, "@") - servicesAndGroup, err := devhub.GetServicesAndGroup(devhubClient, apiUrl, apiPassword, mailParts[0], writeGroups) + servicesAndGroup, err := devhub.GetServicesAndGroup(devhubClient, apiUrl, apiEndpoint, apiPassword, mailParts[0], writeGroups) if err != nil { fmt.Printf("Can't Procces the petition on devhub to get roles %+v", err) } diff --git a/server/auth/devhub/aplication.go b/server/auth/devhub/aplication.go index 030dba29028f..f3c478f1afe4 100644 --- a/server/auth/devhub/aplication.go +++ b/server/auth/devhub/aplication.go @@ -11,12 +11,12 @@ type GroupAndServices struct { Group string } -func GetServicesAndGroup(devhubclient *Client, apiUrl, apiPassword, userToIdentify string, writeGroups []string) (*GroupAndServices, error) { +func GetServicesAndGroup(devhubclient *Client, apiUrl, apiEndpoint, apiPassword, userToIdentify string, writeGroups []string) (*GroupAndServices, error) { var result map[string]interface{} roles := make(map[string]string) services := make(map[string]string) servicesAndGroup := &GroupAndServices{} - apiDevhub := fmt.Sprintf("%s/api/identity/%s", apiUrl, userToIdentify) + apiDevhub := fmt.Sprintf("%s%s%s", apiUrl, apiEndpoint, userToIdentify) res, err := HandleRequestApiInditex(devhubclient, apiDevhub, "GET", apiPassword, map[string]interface{}{}) if err != nil { return nil, err diff --git a/server/auth/sso/sso.go b/server/auth/sso/sso.go index 3db9400f3b28..cd821079dfdf 100644 --- a/server/auth/sso/sso.go +++ b/server/auth/sso/sso.go @@ -207,6 +207,7 @@ func newSso( lf["issuerAlias"] = c.IssuerAlias } ssoExtendedConfigurate.ApiUrl = c.SSOExtendedLabel.ApiUrl + ssoExtendedConfigurate.ApiEndpoint = c.SSOExtendedLabel.ApiEndpoint ssoExtendedConfigurate.ApiPassword = c.SSOExtendedLabel.ApiPassword ssoExtendedConfigurate.Label = c.SSOExtendedLabel.Label ssoExtendedConfigurate.AdminGroup = c.SSOExtendedLabel.AdminGroup @@ -331,7 +332,7 @@ func (s *sso) HandleCallback(w http.ResponseWriter, r *http.Request) { } } if !c.TeamFilterClaims.IsAdmin { - resourcesFilter, err := config.RbacDelegateToLabel(ctx, c.Email, ssoExtendedLabelConfig.ApiUrl, ssoExtendedLabelConfig.ApiPassword, ssoExtendedLabelConfig.Label, ssoExtendedLabelConfig.WriteGroups) + resourcesFilter, err := config.RbacDelegateToLabel(ctx, c.Email, ssoExtendedLabelConfig.ApiUrl, ssoExtendedLabelConfig.ApiEndpoint, ssoExtendedLabelConfig.ApiPassword, ssoExtendedLabelConfig.Label, ssoExtendedLabelConfig.WriteGroups) if err != nil { log.WithError(err).Error("failed to perform RBAC authorization") } diff --git a/server/auth/sso/sso_test.go b/server/auth/sso/sso_test.go index d5914a735884..4559e9d80ba2 100644 --- a/server/auth/sso/sso_test.go +++ b/server/auth/sso/sso_test.go @@ -161,6 +161,7 @@ func TestNewSsoWithExtendedSSO(t *testing.T) { SSOExtendedLabel: config.SSOExtendedLabel{ ApiPassword: "testPassword", ApiUrl: "testApiUrl", + ApiEndpoint: "testApiEndpoint", AdminGroup: "testAdminGroup", Label: "testLabel", WriteGroups: []string{"testWriteGroups"}, @@ -172,6 +173,7 @@ func TestNewSsoWithExtendedSSO(t *testing.T) { assert.Equal(t, "testAdminGroup", ssoObject.SSOExtendedLabel.AdminGroup) assert.Equal(t, "testPassword", ssoObject.SSOExtendedLabel.ApiPassword) assert.Equal(t, "testApiUrl", ssoObject.SSOExtendedLabel.ApiUrl) + assert.Equal(t, "testApiEndpoint", ssoObject.SSOExtendedLabel.ApiEndpoint) assert.Equal(t, "testLabel", ssoObject.SSOExtendedLabel.Label) assert.Equal(t, 1, len(ssoObject.SSOExtendedLabel.WriteGroups)) } From 8d1e630af6d532f5aed0fe9302a4a4cbbe737b53 Mon Sep 17 00:00:00 2001 From: jonathancri Date: Thu, 17 Oct 2024 14:30:06 +0200 Subject: [PATCH 3/5] feat: variabilice api endpoint --- server/auth/devhub/aplication.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/auth/devhub/aplication.go b/server/auth/devhub/aplication.go index f3c478f1afe4..634521d57bf2 100644 --- a/server/auth/devhub/aplication.go +++ b/server/auth/devhub/aplication.go @@ -16,7 +16,7 @@ func GetServicesAndGroup(devhubclient *Client, apiUrl, apiEndpoint, apiPassword, roles := make(map[string]string) services := make(map[string]string) servicesAndGroup := &GroupAndServices{} - apiDevhub := fmt.Sprintf("%s%s%s", apiUrl, apiEndpoint, userToIdentify) + apiDevhub := fmt.Sprintf("%s/%s/%s", apiUrl, apiEndpoint, userToIdentify) res, err := HandleRequestApiInditex(devhubclient, apiDevhub, "GET", apiPassword, map[string]interface{}{}) if err != nil { return nil, err From 2292bbd6cec34d62477bbf29dad528919836b97b Mon Sep 17 00:00:00 2001 From: jonathancri Date: Mon, 21 Oct 2024 09:55:10 +0200 Subject: [PATCH 4/5] feat: change the way of get the roles --- config/sso_extended.go | 4 +-- server/auth/devhub/aplication.go | 55 ++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/config/sso_extended.go b/config/sso_extended.go index f819ed79d1f8..89953c3fa286 100644 --- a/config/sso_extended.go +++ b/config/sso_extended.go @@ -39,9 +39,7 @@ func RbacDelegateToLabel(ctx context.Context, mail string, apiUrl, apiEndpoint, } resourcesToFilterPopulated.Group = servicesAndGroup.Group if servicesAndGroup.Services != nil { - for service := range servicesAndGroup.Services { - resourcesToFilterPopulated.ArrayLabels = append(resourcesToFilterPopulated.ArrayLabels, service) - } + resourcesToFilterPopulated.ArrayLabels = append(resourcesToFilterPopulated.ArrayLabels, servicesAndGroup.Services...) resourcesToFilterPopulated.LabelsFilter = fmt.Sprintf("%s in (%s)", label, strings.Join(resourcesToFilterPopulated.ArrayLabels[:], ",")) } return resourcesToFilterPopulated, nil diff --git a/server/auth/devhub/aplication.go b/server/auth/devhub/aplication.go index 634521d57bf2..a0ed097e7425 100644 --- a/server/auth/devhub/aplication.go +++ b/server/auth/devhub/aplication.go @@ -7,14 +7,14 @@ import ( ) type GroupAndServices struct { - Services map[string]string + Services []string Group string } func GetServicesAndGroup(devhubclient *Client, apiUrl, apiEndpoint, apiPassword, userToIdentify string, writeGroups []string) (*GroupAndServices, error) { var result map[string]interface{} - roles := make(map[string]string) - services := make(map[string]string) + var roles []string + var services []string servicesAndGroup := &GroupAndServices{} apiDevhub := fmt.Sprintf("%s/%s/%s", apiUrl, apiEndpoint, userToIdentify) res, err := HandleRequestApiInditex(devhubclient, apiDevhub, "GET", apiPassword, map[string]interface{}{}) @@ -24,29 +24,42 @@ func GetServicesAndGroup(devhubclient *Client, apiUrl, apiEndpoint, apiPassword, if err := json.NewDecoder(res.Body).Decode(&result); err != nil { return nil, err } - if teams, ok := result["teams"].([]interface{}); ok { - roles, services = GetRolesAndServices(teams, services, roles) - } + + roles, services = GetRolesAndServices(result, services, roles) servicesAndGroup.Group = GetGroupByRole(writeGroups, roles) servicesAndGroup.Services = services return servicesAndGroup, nil } -func GetRolesAndServices(teams []interface{}, services, roles map[string]string) (map[string]string, map[string]string) { +func GetRolesAndServices(result map[string]interface{}, services, roles []string) ([]string, []string) { + teams, ok := result["teams"].([]interface{}) + if !ok { + return services, roles + } for _, team := range teams { - if len(team.(map[string]interface{})["projects"].([]interface{})) > 0 { - for _, project := range team.(map[string]interface{})["projects"].([]interface{}) { - if relationshipType, ok := project.(map[string]interface{})["relationshipType"].(map[string]interface{}); ok && relationshipType["name"] == "Owner" { - services[project.(map[string]interface{})["key"].(string)] = "service" - for _, profile := range team.(map[string]interface{})["profiles"].([]interface{}) { - roles[profile.(map[string]interface{})["name"].(string)] = "role" - } - if len(team.(map[string]interface{})["effectiveCrossProfiles"].([]string)) > 0 { - for _, effectiveCrossProfile := range team.(map[string]interface{})["effectiveCrossProfiles"].([]string) { - roles[effectiveCrossProfile] = "role" - } - } + if len(team.(map[string]interface{})["applications"].([]interface{})) <= 0 { + continue + } + for _, project := range team.(map[string]interface{})["applications"].([]interface{}) { + if project.(map[string]interface{})["relationshipType"].(string) != "Owner" { + continue + } + if !slices.Contains(services, project.(map[string]interface{})["key"].(string)) { + services = append(services, project.(map[string]interface{})["key"].(string)) + } + for _, profile := range team.(map[string]interface{})["profiles"].([]interface{}) { + if !slices.Contains(roles, profile.(map[string]interface{})["name"].(string)) { + roles = append(roles, profile.(map[string]interface{})["name"].(string)) + } + } + crossprofiles, ok := result["crossProfiles"].([]interface{}) + if !ok { + continue + } + for _, crossprofile := range crossprofiles { + if !slices.Contains(roles, crossprofile.(map[string]interface{})["name"].(string)) { + roles = append(roles, crossprofile.(map[string]interface{})["name"].(string)) } } } @@ -54,9 +67,9 @@ func GetRolesAndServices(teams []interface{}, services, roles map[string]string) return roles, services } -func GetGroupByRole(writeGroups []string, roles map[string]string) string { +func GetGroupByRole(writeGroups []string, roles []string) string { groupByRole := "reader" - for role := range roles { + for _, role := range roles { if slices.Contains(writeGroups, role) { groupByRole = "writer" } From 4c54d8402d8b19fbd2b0c5cd8b25ad20f7105c12 Mon Sep 17 00:00:00 2001 From: jonathancri Date: Thu, 24 Oct 2024 10:07:43 +0200 Subject: [PATCH 5/5] feat: change decode to struct --- server/auth/devhub/aplication.go | 70 +++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/server/auth/devhub/aplication.go b/server/auth/devhub/aplication.go index a0ed097e7425..383a53e20a99 100644 --- a/server/auth/devhub/aplication.go +++ b/server/auth/devhub/aplication.go @@ -10,56 +10,88 @@ type GroupAndServices struct { Services []string Group string } +type ApiStruct struct { + Login string `json:"login"` + Name string `json:"name"` + Department string `json:"department"` + Mail string `json:"mail"` + Teams []struct { + Key string `json:"key"` + Name string `json:"name"` + CompleteDepartment struct { + ID string `json:"id"` + Name string `json:"name"` + FullDepartmentID string `json:"fullDepartmentId"` + FullDepartment string `json:"fullDepartment"` + } `json:"completeDepartment"` + Applications []struct { + Key string `json:"key"` + Name string `json:"name"` + RelationshipType string `json:"relationshipType"` + } `json:"applications"` + Profiles []struct { + Key int `json:"key"` + Name string `json:"name"` + } `json:"profiles"` + EffectiveCrossProfiles []string `json:"effectiveCrossProfiles"` + IsMember bool `json:"isMember"` + } `json:"teams"` + CrossProfiles []struct { + Key string `json:"key"` + Department string `json:"department"` + Name string `json:"name"` + } `json:"crossProfiles"` +} func GetServicesAndGroup(devhubclient *Client, apiUrl, apiEndpoint, apiPassword, userToIdentify string, writeGroups []string) (*GroupAndServices, error) { - var result map[string]interface{} var roles []string var services []string servicesAndGroup := &GroupAndServices{} + apiResponse := &ApiStruct{} apiDevhub := fmt.Sprintf("%s/%s/%s", apiUrl, apiEndpoint, userToIdentify) res, err := HandleRequestApiInditex(devhubclient, apiDevhub, "GET", apiPassword, map[string]interface{}{}) if err != nil { return nil, err } - if err := json.NewDecoder(res.Body).Decode(&result); err != nil { + if err := json.NewDecoder(res.Body).Decode(apiResponse); err != nil { return nil, err } - roles, services = GetRolesAndServices(result, services, roles) + roles, services = GetRolesAndServices(apiResponse, services, roles) servicesAndGroup.Group = GetGroupByRole(writeGroups, roles) servicesAndGroup.Services = services return servicesAndGroup, nil } -func GetRolesAndServices(result map[string]interface{}, services, roles []string) ([]string, []string) { - teams, ok := result["teams"].([]interface{}) - if !ok { +func GetRolesAndServices(result *ApiStruct, services, roles []string) ([]string, []string) { + if result.Teams == nil { return services, roles } - for _, team := range teams { - if len(team.(map[string]interface{})["applications"].([]interface{})) <= 0 { + for _, team := range result.Teams { + + if len(team.Applications) <= 0 { continue } - for _, project := range team.(map[string]interface{})["applications"].([]interface{}) { - if project.(map[string]interface{})["relationshipType"].(string) != "Owner" { + for _, project := range team.Applications { + if project.RelationshipType != "Owner" { continue } - if !slices.Contains(services, project.(map[string]interface{})["key"].(string)) { - services = append(services, project.(map[string]interface{})["key"].(string)) + if !slices.Contains(services, project.Key) { + services = append(services, project.Key) } - for _, profile := range team.(map[string]interface{})["profiles"].([]interface{}) { - if !slices.Contains(roles, profile.(map[string]interface{})["name"].(string)) { - roles = append(roles, profile.(map[string]interface{})["name"].(string)) + for _, profile := range team.Profiles { + if !slices.Contains(roles, profile.Name) { + roles = append(roles, profile.Name) } } - crossprofiles, ok := result["crossProfiles"].([]interface{}) - if !ok { + crossprofiles := result.CrossProfiles + if crossprofiles == nil { continue } for _, crossprofile := range crossprofiles { - if !slices.Contains(roles, crossprofile.(map[string]interface{})["name"].(string)) { - roles = append(roles, crossprofile.(map[string]interface{})["name"].(string)) + if !slices.Contains(roles, crossprofile.Name) { + roles = append(roles, crossprofile.Name) } } }