diff --git a/src/common/security/authcontext/authcontext.go b/src/common/security/authcontext/authcontext.go index b0b0b5bef..2b3c9377c 100644 --- a/src/common/security/authcontext/authcontext.go +++ b/src/common/security/authcontext/authcontext.go @@ -21,8 +21,6 @@ import ( "io/ioutil" "net/http" "strings" - - "github.com/vmware/harbor/src/ui/config" ) const ( @@ -92,9 +90,31 @@ func (a *AuthContext) HasAllPerm(project string) bool { return false } -// GetByToken ... -func GetByToken(token string) (*AuthContext, error) { - req, err := http.NewRequest(http.MethodGet, buildCtxURL(), nil) +// GetMyProjects returns all projects which the user is a member of +func (a *AuthContext) GetMyProjects() ([]string, error) { + existence := map[string]string{} + projects := []string{} + for _, list := range a.Projects { + for _, p := range list { + if len(existence[p]) > 0 { + continue + } + existence[p] = p + projects = append(projects, p) + } + + } + return projects, nil +} + +// GetByToken gets the user's auth context, if the username is not provided +// get the default auth context of the token +func GetByToken(url, token string, username ...string) (*AuthContext, error) { + principalID := "" + if len(username) > 0 { + principalID = username[0] + } + req, err := http.NewRequest(http.MethodGet, buildCtxURL(url, principalID), nil) if err != nil { return nil, err } @@ -119,7 +139,7 @@ func GetByToken(token string) (*AuthContext, error) { } // Login ... -func Login(username, password string) (string, *AuthContext, error) { +func Login(url, username, password string) (string, *AuthContext, error) { data, err := json.Marshal(&struct { Username string `json:"username"` Password string `json:"password"` @@ -131,7 +151,7 @@ func Login(username, password string) (string, *AuthContext, error) { return "", nil, err } - req, err := http.NewRequest(http.MethodPost, buildLoginURL(), bytes.NewBuffer(data)) + req, err := http.NewRequest(http.MethodPost, buildLoginURL(url), bytes.NewBuffer(data)) if err != nil { return "", nil, err } @@ -166,10 +186,14 @@ func send(req *http.Request) (int, http.Header, []byte, error) { return resp.StatusCode, resp.Header, data, nil } -func buildCtxURL() string { - return strings.TrimRight(config.AdmiralEndpoint(), "/") + "/sso/auth-context" +func buildCtxURL(url, principalID string) string { + url = strings.TrimRight(url, "/") + "/sso/auth-context" + if len(principalID) > 0 { + url += "/" + principalID + } + return url } -func buildLoginURL() string { - return strings.TrimRight(config.AdmiralEndpoint(), "/") + "/sso/login" +func buildLoginURL(url string) string { + return strings.TrimRight(url, "/") + "/sso/login" } diff --git a/src/common/security/context.go b/src/common/security/context.go index 3a75a8d25..e491285a1 100644 --- a/src/common/security/context.go +++ b/src/common/security/context.go @@ -24,8 +24,8 @@ type Context interface { IsSysAdmin() bool // HasReadPerm returns whether the user has read permission to the project HasReadPerm(projectIDOrName interface{}) bool - // HasWritePerm returns whether the user has write permission to the project + // HasWritePerm returns whether the user has write permission to the project HasWritePerm(projectIDOrName interface{}) bool - // HasAllPerm returns whether the user has all permissions to the project + // HasAllPerm returns whether the user has all permissions to the project HasAllPerm(projectIDOrName interface{}) bool } diff --git a/src/ui/filter/security.go b/src/ui/filter/security.go index 96e4c01f1..990c7d5b8 100644 --- a/src/ui/filter/security.go +++ b/src/ui/filter/security.go @@ -131,7 +131,7 @@ func (b *basicAuthReqCtxModifier) Modify(ctx *beegoctx.Context) bool { if config.WithAdmiral() { // integration with admiral - token, authCtx, err := authcontext.Login(username, password) + token, authCtx, err := authcontext.Login(config.AdmiralEndpoint(), username, password) if err != nil { log.Errorf("failed to authenticate %s: %v", username, err) return false @@ -204,7 +204,7 @@ func (t *tokenReqCtxModifier) Modify(ctx *beegoctx.Context) bool { log.Debug("got token from request") - authContext, err := authcontext.GetByToken(token) + authContext, err := authcontext.GetByToken(config.AdmiralEndpoint(), token) if err != nil { log.Errorf("failed to get auth context: %v", err) return false diff --git a/src/ui/projectmanager/db/pm.go b/src/ui/projectmanager/db/pm.go index 19a1dc6e7..fdcc7561d 100644 --- a/src/ui/projectmanager/db/pm.go +++ b/src/ui/projectmanager/db/pm.go @@ -115,6 +115,10 @@ func (p *ProjectManager) GetPublic() ([]*models.Project, error) { // GetByMember returns all projects which the user is a member of func (p *ProjectManager) GetByMember(username string) ( []*models.Project, error) { + if len(username) == 0 { + return []*models.Project{}, nil + } + return p.GetAll(&models.ProjectQueryParam{ Member: &models.MemberQuery{ Name: username, diff --git a/src/ui/projectmanager/db/pm_test.go b/src/ui/projectmanager/db/pm_test.go index b19350c79..b705132c9 100644 --- a/src/ui/projectmanager/db/pm_test.go +++ b/src/ui/projectmanager/db/pm_test.go @@ -153,7 +153,13 @@ func TestGetPublic(t *testing.T) { func TestGetByMember(t *testing.T) { pm := &ProjectManager{} - projects, err := pm.GetByMember("admin") + // empty username + projects, err := pm.GetByMember("") + assert.Nil(t, err) + assert.Equal(t, 0, len(projects)) + + //non-empty username + projects, err = pm.GetByMember("admin") assert.Nil(t, err) assert.NotEqual(t, 0, len(projects)) } diff --git a/src/ui/projectmanager/pms/pm.go b/src/ui/projectmanager/pms/pm.go index 1cd0bc444..52ceb9b93 100644 --- a/src/ui/projectmanager/pms/pm.go +++ b/src/ui/projectmanager/pms/pm.go @@ -28,6 +28,7 @@ import ( "github.com/vmware/harbor/src/common" "github.com/vmware/harbor/src/common/models" + "github.com/vmware/harbor/src/common/security/authcontext" er "github.com/vmware/harbor/src/common/utils/error" "github.com/vmware/harbor/src/common/utils/log" ) @@ -230,8 +231,11 @@ func (p *ProjectManager) Exist(projectIDOrName interface{}) (bool, error) { return project != nil, nil } -// GetRoles ... -// TODO empty this method after implementing security context with auth context +// GetRoles gets roles that the user has to the project +// This method is used in GET /projects API. +// Jobservice calls GET /projects API to get information of source +// project when trying to replicate the project. There is no auth +// context in this use case, so the method is needed. func (p *ProjectManager) GetRoles(username string, projectIDOrName interface{}) ([]int, error) { if len(username) == 0 || projectIDOrName == nil { return nil, nil @@ -303,8 +307,26 @@ func (p *ProjectManager) GetPublic() ([]*models.Project, error) { // GetByMember ... func (p *ProjectManager) GetByMember(username string) ([]*models.Project, error) { - // TODO add implement - return nil, nil + projects := []*models.Project{} + ctx, err := authcontext.GetByToken(p.endpoint, p.token, username) + if err != nil { + return projects, err + } + + names, err := ctx.GetMyProjects() + if err != nil { + return projects, err + } + + for _, name := range names { + project, err := p.Get(name) + if err != nil { + return projects, err + } + projects = append(projects, project) + } + + return projects, nil } // Create ... @@ -396,11 +418,9 @@ func (p *ProjectManager) GetTotal(query *models.ProjectQueryParam, base ...*mode return int64(len(projects)), err } -// GetHasReadPerm returns all projects that user has read perm to -// TODO maybe can be removed as search isn't implemented in integration mode +// GetHasReadPerm ... func (p *ProjectManager) GetHasReadPerm(username ...string) ([]*models.Project, error) { - // TODO add implement - return nil, nil + return nil, errors.New("GetHasReadPerm is unsupported") } func (p *ProjectManager) send(method, path string, body io.Reader) ([]byte, error) {