mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-05 01:59:44 +01:00
1. only apply security filter to /api/ and /service/ 2.support basic auth for deleting repository and tag in integration mode
This commit is contained in:
parent
ce169e74dc
commit
cdb75519a9
@ -18,9 +18,10 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"regexp"
|
||||
|
||||
beegoctx "github.com/astaxie/beego/context"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
secstore "github.com/vmware/harbor/src/common/secret"
|
||||
"github.com/vmware/harbor/src/common/security"
|
||||
@ -37,6 +38,11 @@ import (
|
||||
|
||||
type key string
|
||||
|
||||
type pathMethod struct {
|
||||
path string
|
||||
method string
|
||||
}
|
||||
|
||||
const (
|
||||
securCtxKey key = "harbor_security_context"
|
||||
pmKey key = "harbor_project_manager"
|
||||
@ -44,6 +50,35 @@ const (
|
||||
|
||||
var (
|
||||
reqCtxModifiers []ReqCtxModifier
|
||||
// the pattern needs security filter
|
||||
reqPatterns = []string{
|
||||
"/api/",
|
||||
"/service/",
|
||||
}
|
||||
// basic auth request context modifier only takes effect on the patterns
|
||||
// in the slice
|
||||
basicAuthReqPatterns = []*pathMethod{
|
||||
// create project
|
||||
&pathMethod{
|
||||
path: "/api/projects",
|
||||
method: http.MethodPost,
|
||||
},
|
||||
// token service
|
||||
&pathMethod{
|
||||
path: "/service/token",
|
||||
method: http.MethodGet,
|
||||
},
|
||||
// delete repository
|
||||
&pathMethod{
|
||||
path: "/api/repositories/" + reference.NameRegexp.String(),
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
// delete tag
|
||||
&pathMethod{
|
||||
path: "/api/repositories/" + reference.NameRegexp.String() + "/tags/" + reference.TagRegexp.String(),
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Init ReqCtxMofiers list
|
||||
@ -78,6 +113,11 @@ func SecurityFilter(ctx *beegoctx.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !filterReq(req) {
|
||||
log.Debugf("%s doesn't match security filter pattern, skip", req.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
// add security context and project manager to request context
|
||||
for _, modifier := range reqCtxModifiers {
|
||||
if modifier.Modify(ctx) {
|
||||
@ -86,6 +126,21 @@ func SecurityFilter(ctx *beegoctx.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func filterReq(req *http.Request) bool {
|
||||
path := req.URL.Path
|
||||
for _, pattern := range reqPatterns {
|
||||
match, err := regexp.MatchString(pattern, path)
|
||||
if err != nil {
|
||||
log.Errorf("failed to match %s with pattern %s", path, pattern)
|
||||
continue
|
||||
}
|
||||
if match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ReqCtxModifier modifies the context of request
|
||||
type ReqCtxModifier interface {
|
||||
Modify(*beegoctx.Context) bool
|
||||
@ -128,7 +183,20 @@ func (b *basicAuthReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
|
||||
// create a project manager with the token of the solution user.
|
||||
// That way may cause some wrong permission promotion in some API
|
||||
// calls, so we just handle the requests which are necessary
|
||||
if !filterReq(ctx.Request) {
|
||||
match := false
|
||||
var err error
|
||||
path := ctx.Request.URL.Path
|
||||
for _, pattern := range basicAuthReqPatterns {
|
||||
match, err = regexp.MatchString(pattern.path, path)
|
||||
if err != nil {
|
||||
log.Errorf("failed to match %s with pattern %s", path, pattern)
|
||||
continue
|
||||
}
|
||||
if match {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
log.Debugf("basic auth is not supported for request %s %s, skip",
|
||||
ctx.Request.Method, ctx.Request.URL.Path)
|
||||
return false
|
||||
@ -177,15 +245,6 @@ func (b *basicAuthReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func filterReq(req *http.Request) bool {
|
||||
path := strings.TrimRight(req.URL.Path, "/")
|
||||
if path == "/api/projects" && req.Method == http.MethodPost ||
|
||||
path == "/service/token" && req.Method == http.MethodGet {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type sessionReqCtxModifier struct{}
|
||||
|
||||
func (s *sessionReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
|
||||
|
@ -322,3 +322,20 @@ func TestGetProjectManager(t *testing.T) {
|
||||
_, ok := pm.(projectmanager.ProjectManager)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
func TestFilterReq(t *testing.T) {
|
||||
cases := []struct {
|
||||
path string
|
||||
result bool
|
||||
}{
|
||||
{"http://server/api/", true},
|
||||
{"http://server/service/", true},
|
||||
{"http://server/registryproxy/v2/", false},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
req, err := http.NewRequest(http.MethodGet, c.path, nil)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, c.result, filterReq(req))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user