permission grant for scanner related actions are not correctly

- add new endpoint for getting scanner candidates of specified project
- adjust the permission granting functions
- fix #9608

Signed-off-by: Steven Zou <szou@vmware.com>
This commit is contained in:
Steven Zou 2019-10-28 16:35:54 +08:00
parent 5c4c04a122
commit 5b2ab34e03
9 changed files with 113 additions and 3 deletions

View File

@ -61,5 +61,6 @@ const (
ResourceRobot = Resource("robot")
ResourceNotificationPolicy = Resource("notification-policy")
ResourceScan = Resource("scan")
ResourceScanner = Resource("scanner")
ResourceSelf = Resource("") // subresource for self
)

View File

@ -45,6 +45,9 @@ var (
{Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionRead},
{Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionList},
{Resource: rbac.ResourceScan, Action: rbac.ActionRead},
{Resource: rbac.ResourceScanner, Action: rbac.ActionRead},
}
// all policies for the projects

View File

@ -124,6 +124,9 @@ var (
{Resource: rbac.ResourceScan, Action: rbac.ActionCreate},
{Resource: rbac.ResourceScan, Action: rbac.ActionRead},
{Resource: rbac.ResourceScanner, Action: rbac.ActionRead},
{Resource: rbac.ResourceScanner, Action: rbac.ActionCreate},
},
"master": {
@ -211,6 +214,8 @@ var (
{Resource: rbac.ResourceScan, Action: rbac.ActionCreate},
{Resource: rbac.ResourceScan, Action: rbac.ActionRead},
{Resource: rbac.ResourceScanner, Action: rbac.ActionRead},
},
"developer": {
@ -266,6 +271,8 @@ var (
{Resource: rbac.ResourceScan, Action: rbac.ActionCreate},
{Resource: rbac.ResourceScan, Action: rbac.ActionRead},
{Resource: rbac.ResourceScanner, Action: rbac.ActionRead},
},
"guest": {
@ -306,6 +313,10 @@ var (
{Resource: rbac.ResourceRobot, Action: rbac.ActionRead},
{Resource: rbac.ResourceRobot, Action: rbac.ActionList},
{Resource: rbac.ResourceScan, Action: rbac.ActionRead},
{Resource: rbac.ResourceScanner, Action: rbac.ActionRead},
},
"limitedGuest": {
@ -330,6 +341,10 @@ var (
{Resource: rbac.ResourceHelmChartVersion, Action: rbac.ActionList},
{Resource: rbac.ResourceConfiguration, Action: rbac.ActionRead},
{Resource: rbac.ResourceScan, Action: rbac.ActionRead},
{Resource: rbac.ResourceScanner, Action: rbac.ActionRead},
},
}
)

View File

@ -217,6 +217,7 @@ func init() {
// Add routes for project level scanner
proScannerAPI := &ProjectScannerAPI{}
beego.Router("/api/projects/:pid([0-9]+)/scanner", proScannerAPI, "get:GetProjectScanner;put:SetProjectScanner")
beego.Router("/api/projects/:pid([0-9]+)/scanner/candidates", proScannerAPI, "get:GetProScannerCandidates")
// Add routes for scan
scanAPI := &ScanAPI{}

View File

@ -16,6 +16,7 @@ package api
import (
"github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/pkg/q"
"github.com/goharbor/harbor/src/pkg/scan/api/scanner"
"github.com/pkg/errors"
)
@ -67,7 +68,7 @@ func (sa *ProjectScannerAPI) Prepare() {
// GetProjectScanner gets the project level scanner
func (sa *ProjectScannerAPI) GetProjectScanner() {
// Check access permissions
if !sa.RequireProjectAccess(sa.pid, rbac.ActionRead, rbac.ResourceConfiguration) {
if !sa.RequireProjectAccess(sa.pid, rbac.ActionRead, rbac.ResourceScanner) {
return
}
@ -89,7 +90,7 @@ func (sa *ProjectScannerAPI) GetProjectScanner() {
// SetProjectScanner sets the project level scanner
func (sa *ProjectScannerAPI) SetProjectScanner() {
// Check access permissions
if !sa.RequireProjectAccess(sa.pid, rbac.ActionUpdate, rbac.ResourceConfiguration) {
if !sa.RequireProjectAccess(sa.pid, rbac.ActionCreate, rbac.ResourceScanner) {
return
}
@ -110,3 +111,33 @@ func (sa *ProjectScannerAPI) SetProjectScanner() {
return
}
}
// GetProScannerCandidates gets the candidates for setting project level scanner.
func (sa *ProjectScannerAPI) GetProScannerCandidates() {
// Check access permissions
// Same permission with project level scanner set action
if !sa.RequireProjectAccess(sa.pid, rbac.ActionCreate, rbac.ResourceScanner) {
return
}
p, pz, err := sa.GetPaginationParams()
if err != nil {
sa.SendBadRequestError(errors.Wrap(err, "scanner API: get project scanner candidates"))
return
}
query := &q.Query{
PageSize: pz,
PageNumber: p,
}
all, err := sa.c.ListRegistrations(query)
if err != nil {
sa.SendInternalServerError(errors.Wrap(err, "scanner API: get project scanner candidates"))
return
}
// Response to the client
sa.Data["json"] = all
sa.ServeJSON()
}

View File

@ -19,6 +19,7 @@ import (
"net/http"
"testing"
"github.com/goharbor/harbor/src/pkg/q"
"github.com/goharbor/harbor/src/pkg/scan/dao/scanner"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -93,3 +94,33 @@ func (suite *ProScannerAPITestSuite) TestScannerAPIProjectScanner() {
assert.Equal(suite.T(), r.Name, rr.Name)
assert.Equal(suite.T(), r.UUID, rr.UUID)
}
// TestScannerAPIGetScannerCandidates ...
func (suite *ProScannerAPITestSuite) TestScannerAPIGetScannerCandidates() {
query := &q.Query{
PageNumber: 1,
PageSize: 500,
}
ll := []*scanner.Registration{
{
ID: 1005,
UUID: "uuid",
Name: "TestScannerAPIGetScannerCandidates",
Description: "JUST FOR TEST",
URL: "https://a.b.c",
}}
suite.mockC.On("ListRegistrations", query).Return(ll, nil)
// Get
l := make([]*scanner.Registration, 0)
err := handleAndParse(&testingRequest{
url: fmt.Sprintf("/api/projects/%d/scanner/candidates", 1),
method: http.MethodGet,
credential: projAdmin,
}, &l)
require.NoError(suite.T(), err)
assert.Equal(suite.T(), 1, len(l))
assert.Equal(suite.T(), "uuid", l[0].UUID)
}

View File

@ -204,6 +204,7 @@ func initRouters() {
// Add routes for project level scanner
proScannerAPI := &api.ProjectScannerAPI{}
beego.Router("/api/projects/:pid([0-9]+)/scanner", proScannerAPI, "get:GetProjectScanner;put:SetProjectScanner")
beego.Router("/api/projects/:pid([0-9]+)/scanner/candidates", proScannerAPI, "get:GetProScannerCandidates")
// Add routes for scan
scanAPI := &api.ScanAPI{}

View File

@ -15,6 +15,7 @@
package scanner
import (
"github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/promgr/metamgr"
"github.com/goharbor/harbor/src/jobservice/logger"
"github.com/goharbor/harbor/src/pkg/q"
@ -26,6 +27,8 @@ import (
const (
proScannerMetaKey = "projectScanner"
statusUnhealthy = "unhealthy"
statusHealthy = "healthy"
)
// DefaultController is a singleton api controller for plug scanners
@ -214,6 +217,25 @@ func (bc *basicController) GetRegistrationByProject(projectID int64) (*scanner.R
}
}
// No scanner configured
if registration == nil {
return nil, nil
}
// Get metadata of the configured registration
meta, err := bc.Ping(registration)
if err != nil {
// Not blocked, just logged it
log.Error(errors.Wrap(err, "api controller: get project scanner"))
registration.Health = statusUnhealthy
} else {
registration.Health = statusHealthy
// Fill in some metadata
registration.Adapter = meta.Scanner.Name
registration.Vendor = meta.Scanner.Vendor
registration.Version = meta.Scanner.Version
}
return registration, err
}

View File

@ -37,7 +37,7 @@ type Registration struct {
URL string `orm:"column(url);unique;size(512)" json:"url"`
Disabled bool `orm:"column(disabled);default(true)" json:"disabled"`
IsDefault bool `orm:"column(is_default);default(false)" json:"is_default"`
Health bool `orm:"-" json:"-"` // Reserved for future use
Health string `orm:"-" json:"health,omitempty"`
// Authentication settings
// "","Basic", "Bearer" and api key header "X-ScannerAdapter-API-Key" can be supported
@ -53,6 +53,11 @@ type Registration struct {
// Indicate if the registration is immutable which is not allowed to remove
Immutable bool `orm:"column(immutable);default(false)" json:"-"`
// Optional properties for describing the adapter
Adapter string `orm:"-" json:"adapter,omitempty"`
Vendor string `orm:"-" json:"vendor,omitempty"`
Version string `orm:"-" json:"version,omitempty"`
// Timestamps
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`