fix(extensions): consolidate extensions headers returned to UI by extensions (#1473)
Signed-off-by: Petu Eusebiu <peusebiu@cisco.com>
This commit is contained in:
parent
6a7035c599
commit
9acd19f7ea
@ -12,10 +12,12 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
@ -31,8 +33,8 @@ const (
|
||||
caCertFilename = "ca.crt"
|
||||
)
|
||||
|
||||
func AllowedMethods(method string) []string {
|
||||
return []string{http.MethodOptions, method}
|
||||
func AllowedMethods(methods ...string) []string {
|
||||
return append(methods, http.MethodOptions)
|
||||
}
|
||||
|
||||
func Contains(slice []string, item string) bool {
|
||||
@ -283,3 +285,30 @@ func GetManifestArtifactType(manifestContent ispec.Manifest) string {
|
||||
|
||||
return manifestContent.Config.MediaType
|
||||
}
|
||||
|
||||
func AddExtensionSecurityHeaders() mux.MiddlewareFunc { //nolint:varnamelen
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
|
||||
next.ServeHTTP(resp, req)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func ACHeadersHandler(allowedMethods ...string) mux.MiddlewareFunc {
|
||||
headerValue := strings.Join(allowedMethods, ",")
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Set("Access-Control-Allow-Methods", headerValue)
|
||||
resp.Header().Set("Access-Control-Allow-Headers", "Authorization,content-type")
|
||||
|
||||
if req.Method == http.MethodOptions {
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(resp, req)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
"zotregistry.io/zot/pkg/common"
|
||||
zcommon "zotregistry.io/zot/pkg/common"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
)
|
||||
|
||||
@ -73,7 +73,7 @@ type mgmt struct {
|
||||
func (mgmt *mgmt) handler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
sanitizedConfig := mgmt.config.Sanitize()
|
||||
buf, err := common.MarshalThroughStruct(sanitizedConfig, &StrippedConfig{})
|
||||
buf, err := zcommon.MarshalThroughStruct(sanitizedConfig, &StrippedConfig{})
|
||||
if err != nil {
|
||||
mgmt.log.Error().Err(err).Msg("mgmt: couldn't marshal config response")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@ -82,20 +82,17 @@ func (mgmt *mgmt) handler() http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func addMgmtSecurityHeaders(h http.Handler) http.HandlerFunc { //nolint:varnamelen
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func SetupMgmtRoutes(config *config.Config, router *mux.Router, log log.Logger) {
|
||||
if config.Extensions.Mgmt != nil && *config.Extensions.Mgmt.Enable {
|
||||
log.Info().Msg("setting up mgmt routes")
|
||||
|
||||
mgmt := mgmt{config: config, log: log}
|
||||
|
||||
router.PathPrefix(constants.ExtMgmt).Methods("GET").Handler(addMgmtSecurityHeaders(mgmt.handler()))
|
||||
allowedMethods := zcommon.AllowedMethods(http.MethodGet)
|
||||
|
||||
mgmtRouter := router.PathPrefix(constants.ExtMgmt).Subrouter()
|
||||
mgmtRouter.Use(zcommon.ACHeadersHandler(allowedMethods...))
|
||||
mgmtRouter.Use(zcommon.AddExtensionSecurityHeaders())
|
||||
mgmtRouter.Methods(allowedMethods...).Handler(mgmt.handler())
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
zcommon "zotregistry.io/zot/pkg/common"
|
||||
"zotregistry.io/zot/pkg/extensions/search"
|
||||
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
|
||||
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
|
||||
@ -165,14 +166,6 @@ func (trivyT *trivyTask) DoWork() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func addSearchSecurityHeaders(h http.Handler) http.HandlerFunc { //nolint:varnamelen
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func SetupSearchRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||
repoDB repodb.RepoDB, cveInfo CveInfo, log log.Logger,
|
||||
) {
|
||||
@ -181,24 +174,12 @@ func SetupSearchRoutes(config *config.Config, router *mux.Router, storeControlle
|
||||
if config.Extensions.Search != nil && *config.Extensions.Search.Enable {
|
||||
resConfig := search.GetResolverConfig(log, storeController, repoDB, cveInfo)
|
||||
|
||||
allowedMethods := zcommon.AllowedMethods(http.MethodGet, http.MethodPost)
|
||||
|
||||
extRouter := router.PathPrefix(constants.ExtSearch).Subrouter()
|
||||
extRouter.Use(SearchACHeadersHandler())
|
||||
extRouter.Methods("GET", "POST", "OPTIONS").
|
||||
Handler(addSearchSecurityHeaders(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig))))
|
||||
}
|
||||
}
|
||||
|
||||
func SearchACHeadersHandler() mux.MiddlewareFunc {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Set("Access-Control-Allow-Methods", "HEAD,GET,POST,OPTIONS")
|
||||
resp.Header().Set("Access-Control-Allow-Headers", "Authorization,content-type")
|
||||
|
||||
if req.Method == http.MethodOptions {
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(resp, req)
|
||||
})
|
||||
extRouter.Use(zcommon.ACHeadersHandler(allowedMethods...))
|
||||
extRouter.Use(zcommon.AddExtensionSecurityHeaders())
|
||||
extRouter.Methods(allowedMethods...).
|
||||
Handler(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig)))
|
||||
}
|
||||
}
|
||||
|
@ -34,25 +34,12 @@ func SetupUserPreferencesRoutes(config *config.Config, router *mux.Router, store
|
||||
if config.Extensions.Search != nil && *config.Extensions.Search.Enable {
|
||||
log.Info().Msg("setting up user preferences routes")
|
||||
|
||||
allowedMethods := zcommon.AllowedMethods(http.MethodPut)
|
||||
|
||||
userprefsRouter := router.PathPrefix(constants.ExtUserPreferences).Subrouter()
|
||||
userprefsRouter.Use(UserPrefsACHeadersHandler())
|
||||
|
||||
userprefsRouter.HandleFunc("", HandleUserPrefs(repoDB, log)).Methods(zcommon.AllowedMethods(http.MethodPut)...)
|
||||
}
|
||||
}
|
||||
|
||||
func UserPrefsACHeadersHandler() mux.MiddlewareFunc {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Set("Access-Control-Allow-Methods", "HEAD,GET,POST,PUT,OPTIONS")
|
||||
resp.Header().Set("Access-Control-Allow-Headers", "Authorization,content-type")
|
||||
|
||||
if req.Method == http.MethodOptions {
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(resp, req)
|
||||
})
|
||||
userprefsRouter.Use(zcommon.ACHeadersHandler(allowedMethods...))
|
||||
userprefsRouter.Use(zcommon.AddExtensionSecurityHeaders())
|
||||
userprefsRouter.HandleFunc("", HandleUserPrefs(repoDB, log)).Methods(allowedMethods...)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ import (
|
||||
|
||||
var ErrTestError = errors.New("TestError")
|
||||
|
||||
func TestAllowedMethodsHeader(t *testing.T) {
|
||||
func TestAllowedMethodsHeaderUserPrefs(t *testing.T) {
|
||||
defaultVal := true
|
||||
|
||||
Convey("Test http options response", t, func() {
|
||||
@ -53,7 +53,7 @@ func TestAllowedMethodsHeader(t *testing.T) {
|
||||
|
||||
resp, _ := resty.R().Options(baseURL + constants.FullUserPreferencesPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.Header().Get("Access-Control-Allow-Methods"), ShouldResemble, "HEAD,GET,POST,PUT,OPTIONS")
|
||||
So(resp.Header().Get("Access-Control-Allow-Methods"), ShouldResemble, "PUT,OPTIONS")
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNoContent)
|
||||
})
|
||||
}
|
||||
|
@ -669,3 +669,32 @@ func TestMgmtWithBearer(t *testing.T) {
|
||||
So(mgmtResp.HTTP.Auth.LDAP, ShouldBeNil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAllowedMethodsHeaderMgmt(t *testing.T) {
|
||||
defaultVal := true
|
||||
|
||||
Convey("Test http options response", t, func() {
|
||||
conf := config.New()
|
||||
port := test.GetFreePort()
|
||||
conf.HTTP.Port = port
|
||||
conf.Extensions = &extconf.ExtensionConfig{
|
||||
Mgmt: &extconf.MgmtConfig{
|
||||
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
||||
},
|
||||
}
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
ctlr.Config.Storage.RootDirectory = t.TempDir()
|
||||
|
||||
ctrlManager := test.NewControllerManager(ctlr)
|
||||
|
||||
ctrlManager.StartAndWait(port)
|
||||
defer ctrlManager.StopServer()
|
||||
|
||||
resp, _ := resty.R().Options(baseURL + constants.FullMgmtPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.Header().Get("Access-Control-Allow-Methods"), ShouldResemble, "GET,OPTIONS")
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNoContent)
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user