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:
Wenkai Yin 2017-07-28 15:06:32 +08:00
parent ce169e74dc
commit cdb75519a9
2 changed files with 87 additions and 11 deletions

View File

@ -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 {

View File

@ -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))
}
}