From f7412b0c313c613b7528d25ee5aed58423a8e794 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Thu, 6 Jul 2017 17:52:25 +0800 Subject: [PATCH] update auth context as Admiral's API changed --- .../{ => admiral}/authcontext/authcontext.go | 52 +++++++++++-------- .../authcontext/authcontext_test.go | 9 ++-- src/common/security/admiral/context.go | 2 +- src/common/utils/utils.go | 32 ++++++++++++ src/common/utils/utils_test.go | 32 ++++++++++++ src/ui/filter/security.go | 13 ++--- 6 files changed, 106 insertions(+), 34 deletions(-) rename src/common/security/{ => admiral}/authcontext/authcontext.go (85%) rename src/common/security/{ => admiral}/authcontext/authcontext_test.go (87%) diff --git a/src/common/security/authcontext/authcontext.go b/src/common/security/admiral/authcontext/authcontext.go similarity index 85% rename from src/common/security/authcontext/authcontext.go rename to src/common/security/admiral/authcontext/authcontext.go index 927be96d0..2ca9ed5f9 100644 --- a/src/common/security/authcontext/authcontext.go +++ b/src/common/security/admiral/authcontext/authcontext.go @@ -20,10 +20,12 @@ import ( "fmt" "io/ioutil" "net/http" + "strconv" "strings" "github.com/vmware/harbor/src/common" "github.com/vmware/harbor/src/common/models" + "github.com/vmware/harbor/src/common/utils" "github.com/vmware/harbor/src/common/utils/log" ) @@ -37,9 +39,10 @@ const ( ) type project struct { - DocumentSelfLink string `json:"documentSelfLink"` - Name string `json:"name"` - Roles []string `json:"roles"` + SelfLink string `json:"documentSelfLink"` + Name string `json:"name"` + Roles []string `json:"roles"` + Properties map[string]string `json:"customProperties"` } // AuthContext ... @@ -63,28 +66,18 @@ func (a *AuthContext) IsSysAdmin() bool { // GetProjectRoles ... func (a *AuthContext) GetProjectRoles(projectIDOrName interface{}) []int { - var isID bool - var id int64 - var name string - - id, isID = projectIDOrName.(int64) - if !isID { - name, _ = projectIDOrName.(string) + id, name, err := utils.ParseProjectIDOrName(projectIDOrName) + if err != nil { + log.Errorf("failed to parse project ID or name: %v", err) + return []int{} } roles := []string{} for _, project := range a.Projects { p := convertProject(project) - if isID { - if p.ProjectID == id { - roles = append(roles, project.Roles...) - break - } - } else { - if p.Name == name { - roles = append(roles, project.Roles...) - break - } + if p.ProjectID == id || p.Name == name { + roles = append(roles, project.Roles...) + break } } @@ -100,12 +93,29 @@ func (a *AuthContext) GetMyProjects() []*models.Project { return projects } -// TODO populate harbor ID to the project // convert project returned by Admiral to project used in Harbor func convertProject(p *project) *models.Project { project := &models.Project{ Name: p.Name, } + + index := "" + if p.Properties != nil { + index = p.Properties["__projectIndex"] + } + + if len(index) == 0 { + log.Errorf("property __projectIndex not found when parsing project") + return project + } + + id, err := strconv.ParseInt(index, 10, 64) + if err != nil { + log.Errorf("failed to parse __projectIndex %s: %v", index, err) + return project + } + + project.ProjectID = id return project } diff --git a/src/common/security/authcontext/authcontext_test.go b/src/common/security/admiral/authcontext/authcontext_test.go similarity index 87% rename from src/common/security/authcontext/authcontext_test.go rename to src/common/security/admiral/authcontext/authcontext_test.go index a18169c5c..d0b417fe0 100644 --- a/src/common/security/authcontext/authcontext_test.go +++ b/src/common/security/admiral/authcontext/authcontext_test.go @@ -42,8 +42,9 @@ func TestGetProjectRoles(t *testing.T) { ctx := &AuthContext{ Projects: []*project{ &project{ - Name: "project", - Roles: []string{projectAdminRole, developerRole, guestRole}, + Name: "project", + Roles: []string{projectAdminRole, developerRole, guestRole}, + Properties: map[string]string{"__projectIndex": "9"}, }, }, } @@ -52,7 +53,9 @@ func TestGetProjectRoles(t *testing.T) { roles := ctx.GetProjectRoles("project") assert.Equal(t, 3, len(roles)) - // TODO add test case with ID + // test with ID + roles = ctx.GetProjectRoles(9) + assert.Equal(t, 3, len(roles)) } func TestGetMyProjects(t *testing.T) { diff --git a/src/common/security/admiral/context.go b/src/common/security/admiral/context.go index a848ceae1..a748f856f 100644 --- a/src/common/security/admiral/context.go +++ b/src/common/security/admiral/context.go @@ -17,7 +17,7 @@ package admiral import ( "github.com/vmware/harbor/src/common" "github.com/vmware/harbor/src/common/models" - "github.com/vmware/harbor/src/common/security/authcontext" + "github.com/vmware/harbor/src/common/security/admiral/authcontext" "github.com/vmware/harbor/src/common/utils/log" "github.com/vmware/harbor/src/ui/projectmanager" ) diff --git a/src/common/utils/utils.go b/src/common/utils/utils.go index c8cdbc750..ff1fcd2b1 100644 --- a/src/common/utils/utils.go +++ b/src/common/utils/utils.go @@ -16,6 +16,7 @@ package utils import ( "crypto/rand" + "errors" "fmt" "net" "net/url" @@ -125,3 +126,34 @@ func ParseTimeStamp(timestamp string) (*time.Time, error) { t := time.Unix(i, 0) return &t, nil } + +// ParseProjectIDOrName parses value to ID(int64) or name(string) +func ParseProjectIDOrName(value interface{}) (int64, string, error) { + if value == nil { + return 0, "", errors.New("harborIDOrName is nil") + } + + var id int64 + var name string + switch value.(type) { + case int: + i := value.(int) + id = int64(i) + if id == 0 { + return 0, "", fmt.Errorf("invalid ID: 0") + } + case int64: + id = value.(int64) + if id == 0 { + return 0, "", fmt.Errorf("invalid ID: 0") + } + case string: + name = value.(string) + if len(name) == 0 { + return 0, "", fmt.Errorf("empty name") + } + default: + return 0, "", fmt.Errorf("unsupported type") + } + return id, name, nil +} diff --git a/src/common/utils/utils_test.go b/src/common/utils/utils_test.go index 782355de2..fda1695b7 100644 --- a/src/common/utils/utils_test.go +++ b/src/common/utils/utils_test.go @@ -211,3 +211,35 @@ func TestParseTimeStamp(t *testing.T) { assert.Nil(t, err) assert.Equal(t, now, result.Unix()) } + +func TestParseHarborIDOrName(t *testing.T) { + // nil input + id, name, err := ParseProjectIDOrName(nil) + assert.NotNil(t, err) + + // invalid ID + id, name, err = ParseProjectIDOrName(0) + assert.NotNil(t, err) + + // invalid name + id, name, err = ParseProjectIDOrName("") + assert.NotNil(t, err) + + // valid int ID + id, name, err = ParseProjectIDOrName(1) + assert.Nil(t, err) + assert.Equal(t, int64(1), id) + assert.Equal(t, "", name) + + // valid int64 ID + id, name, err = ParseProjectIDOrName(int64(1)) + assert.Nil(t, err) + assert.Equal(t, int64(1), id) + assert.Equal(t, "", name) + + // valid name + id, name, err = ParseProjectIDOrName("project") + assert.Nil(t, err) + assert.Equal(t, int64(0), id) + assert.Equal(t, "project", name) +} diff --git a/src/ui/filter/security.go b/src/ui/filter/security.go index a66812004..11bd28182 100644 --- a/src/ui/filter/security.go +++ b/src/ui/filter/security.go @@ -24,7 +24,7 @@ import ( secstore "github.com/vmware/harbor/src/common/secret" "github.com/vmware/harbor/src/common/security" "github.com/vmware/harbor/src/common/security/admiral" - "github.com/vmware/harbor/src/common/security/authcontext" + "github.com/vmware/harbor/src/common/security/admiral/authcontext" "github.com/vmware/harbor/src/common/security/local" "github.com/vmware/harbor/src/common/security/secret" "github.com/vmware/harbor/src/common/utils/log" @@ -99,19 +99,14 @@ func (s *secretReqCtxModifier) Modify(ctx *beegoctx.Context) bool { if len(scrt) == 0 { return false } - log.Debug("got secret from request") - var pm projectmanager.ProjectManager - if config.WithAdmiral() { - // TODO project manager with harbor service accout - } else { - log.Debug("using local database project manager") - pm = config.GlobalProjectMgr - } + log.Debug("using global project manager") + pm := config.GlobalProjectMgr log.Debug("creating a secret security context...") securCtx := secret.NewSecurityContext(scrt, s.store) + setSecurCtxAndPM(ctx.Request, securCtx, pm) return true