mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 05:03:09 +00:00
Separate apiserver handler filters
This commit is contained in:
parent
a2f943e7c1
commit
6dc2f6337b
@ -27,7 +27,6 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
rt "runtime"
|
rt "runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
@ -210,22 +209,6 @@ func logStackOnRecover(s runtime.NegotiatedSerializer, panicReason interface{},
|
|||||||
errorNegotiated(apierrors.NewGenericServerResponse(http.StatusInternalServerError, "", api.Resource(""), "", "", 0, false), s, unversioned.GroupVersion{}, w, &http.Request{Header: headers})
|
errorNegotiated(apierrors.NewGenericServerResponse(http.StatusInternalServerError, "", api.Resource(""), "", "", 0, false), s, unversioned.GroupVersion{}, w, &http.Request{Header: headers})
|
||||||
}
|
}
|
||||||
|
|
||||||
func InstallServiceErrorHandler(s runtime.NegotiatedSerializer, container *restful.Container) {
|
|
||||||
container.ServiceErrorHandler(func(serviceErr restful.ServiceError, request *restful.Request, response *restful.Response) {
|
|
||||||
serviceErrorHandler(s, serviceErr, request, response)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func serviceErrorHandler(s runtime.NegotiatedSerializer, serviceErr restful.ServiceError, request *restful.Request, response *restful.Response) {
|
|
||||||
errorNegotiated(
|
|
||||||
apierrors.NewGenericServerResponse(serviceErr.Code, "", api.Resource(""), "", serviceErr.Message, 0, false),
|
|
||||||
s,
|
|
||||||
unversioned.GroupVersion{},
|
|
||||||
response.ResponseWriter,
|
|
||||||
request.Request,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds a service to return the supported api versions at the legacy /api.
|
// Adds a service to return the supported api versions at the legacy /api.
|
||||||
func AddApiWebService(s runtime.NegotiatedSerializer, container *restful.Container, apiPrefix string, getAPIVersionsFunc func(req *restful.Request) *unversioned.APIVersions) {
|
func AddApiWebService(s runtime.NegotiatedSerializer, container *restful.Container, apiPrefix string, getAPIVersionsFunc func(req *restful.Request) *unversioned.APIVersions) {
|
||||||
// TODO: InstallREST should register each version automatically
|
// TODO: InstallREST should register each version automatically
|
||||||
@ -501,12 +484,3 @@ func readBody(req *http.Request) ([]byte, error) {
|
|||||||
defer req.Body.Close()
|
defer req.Body.Close()
|
||||||
return ioutil.ReadAll(req.Body)
|
return ioutil.ReadAll(req.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitPath returns the segments for a URL path.
|
|
||||||
func splitPath(path string) []string {
|
|
||||||
path = strings.Trim(path, "/")
|
|
||||||
if path == "" {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
return strings.Split(path, "/")
|
|
||||||
}
|
|
||||||
|
@ -44,7 +44,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/diff"
|
"k8s.io/kubernetes/pkg/util/diff"
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
|
||||||
"k8s.io/kubernetes/pkg/watch"
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
"k8s.io/kubernetes/pkg/watch/versioned"
|
"k8s.io/kubernetes/pkg/watch/versioned"
|
||||||
"k8s.io/kubernetes/plugin/pkg/admission/admit"
|
"k8s.io/kubernetes/plugin/pkg/admission/admit"
|
||||||
@ -252,10 +251,6 @@ func handleLinker(storage map[string]rest.Storage, selfLinker runtime.SelfLinker
|
|||||||
return handleInternal(storage, admissionControl, selfLinker)
|
return handleInternal(storage, admissionControl, selfLinker)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestRequestInfoResolver() *RequestInfoResolver {
|
|
||||||
return &RequestInfoResolver{sets.NewString("api", "apis"), sets.NewString("api")}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleInternal(storage map[string]rest.Storage, admissionControl admission.Interface, selfLinker runtime.SelfLinker) http.Handler {
|
func handleInternal(storage map[string]rest.Storage, admissionControl admission.Interface, selfLinker runtime.SelfLinker) http.Handler {
|
||||||
container := restful.NewContainer()
|
container := restful.NewContainer()
|
||||||
container.Router(restful.CurlyRouter{})
|
container.Router(restful.CurlyRouter{})
|
||||||
|
@ -76,25 +76,6 @@ func notFound(w http.ResponseWriter, req *http.Request) {
|
|||||||
fmt.Fprintf(w, "Not Found: %#v", req.RequestURI)
|
fmt.Fprintf(w, "Not Found: %#v", req.RequestURI)
|
||||||
}
|
}
|
||||||
|
|
||||||
// badGatewayError renders a simple bad gateway error.
|
|
||||||
func badGatewayError(w http.ResponseWriter, req *http.Request) {
|
|
||||||
w.WriteHeader(http.StatusBadGateway)
|
|
||||||
fmt.Fprintf(w, "Bad Gateway: %#v", req.RequestURI)
|
|
||||||
}
|
|
||||||
|
|
||||||
// forbidden renders a simple forbidden error
|
|
||||||
func forbidden(w http.ResponseWriter, req *http.Request) {
|
|
||||||
w.WriteHeader(http.StatusForbidden)
|
|
||||||
fmt.Fprintf(w, "Forbidden: %#v", req.RequestURI)
|
|
||||||
}
|
|
||||||
|
|
||||||
// internalError renders a simple internal error
|
|
||||||
func internalError(w http.ResponseWriter, req *http.Request, err error) {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
fmt.Fprintf(w, "Internal Server Error: %#v", req.RequestURI)
|
|
||||||
runtime.HandleError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// errAPIPrefixNotFound indicates that a RequestInfo resolution failed because the request isn't under
|
// errAPIPrefixNotFound indicates that a RequestInfo resolution failed because the request isn't under
|
||||||
// any known API prefixes
|
// any known API prefixes
|
||||||
type errAPIPrefixNotFound struct {
|
type errAPIPrefixNotFound struct {
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package audit
|
package filters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@ -27,7 +27,6 @@ import (
|
|||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
|
||||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -85,7 +84,7 @@ var _ http.Hijacker = &fancyResponseWriterDelegator{}
|
|||||||
// 2. the response line containing:
|
// 2. the response line containing:
|
||||||
// - the unique id from 1
|
// - the unique id from 1
|
||||||
// - response code
|
// - response code
|
||||||
func WithAudit(handler http.Handler, attributeGetter apiserver.RequestAttributeGetter, out io.Writer) http.Handler {
|
func WithAudit(handler http.Handler, attributeGetter RequestAttributeGetter, out io.Writer) http.Handler {
|
||||||
if out == nil {
|
if out == nil {
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package audit
|
package filters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@ -85,7 +85,7 @@ func (*fakeRequestContextMapper) Update(req *http.Request, context api.Context)
|
|||||||
|
|
||||||
func TestAudit(t *testing.T) {
|
func TestAudit(t *testing.T) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
attributeGetter := apiserver.NewRequestAttributeGetter(&fakeRequestContextMapper{},
|
attributeGetter := NewRequestAttributeGetter(&fakeRequestContextMapper{},
|
||||||
&apiserver.RequestInfoResolver{APIPrefixes: sets.NewString("api", "apis"), GrouplessAPIPrefixes: sets.NewString("api")})
|
&apiserver.RequestInfoResolver{APIPrefixes: sets.NewString("api", "apis"), GrouplessAPIPrefixes: sets.NewString("api")})
|
||||||
handler := WithAudit(&fakeHTTPHandler{}, attributeGetter, &buf)
|
handler := WithAudit(&fakeHTTPHandler{}, attributeGetter, &buf)
|
||||||
req, _ := http.NewRequest("GET", "/api/v1/namespaces/default/pods", nil)
|
req, _ := http.NewRequest("GET", "/api/v1/namespaces/default/pods", nil)
|
91
pkg/apiserver/filters/authorization.go
Normal file
91
pkg/apiserver/filters/authorization.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package filters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithAuthorizationCheck passes all authorized requests on to handler, and returns a forbidden error otherwise.
|
||||||
|
func WithAuthorization(handler http.Handler, getAttribs RequestAttributeGetter, a authorizer.Authorizer) http.Handler {
|
||||||
|
if a == nil {
|
||||||
|
glog.Warningf("Authorization is disabled")
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
authorized, reason, err := a.Authorize(getAttribs.GetAttribs(req))
|
||||||
|
if err != nil {
|
||||||
|
internalError(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !authorized {
|
||||||
|
glog.V(4).Infof("Forbidden: %#v, Reason: %s", req.RequestURI, reason)
|
||||||
|
forbidden(w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handler.ServeHTTP(w, req)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestAttributeGetter is a function that extracts authorizer.Attributes from an http.Request
|
||||||
|
type RequestAttributeGetter interface {
|
||||||
|
GetAttribs(req *http.Request) (attribs authorizer.Attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestAttributeGetter struct {
|
||||||
|
requestContextMapper api.RequestContextMapper
|
||||||
|
requestInfoResolver *apiserver.RequestInfoResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAttributeGetter returns an object which implements the RequestAttributeGetter interface.
|
||||||
|
func NewRequestAttributeGetter(requestContextMapper api.RequestContextMapper, requestInfoResolver *apiserver.RequestInfoResolver) RequestAttributeGetter {
|
||||||
|
return &requestAttributeGetter{requestContextMapper, requestInfoResolver}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestAttributeGetter) GetAttribs(req *http.Request) authorizer.Attributes {
|
||||||
|
attribs := authorizer.AttributesRecord{}
|
||||||
|
|
||||||
|
ctx, ok := r.requestContextMapper.Get(req)
|
||||||
|
if ok {
|
||||||
|
user, ok := api.UserFrom(ctx)
|
||||||
|
if ok {
|
||||||
|
attribs.User = user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestInfo, _ := r.requestInfoResolver.GetRequestInfo(req)
|
||||||
|
|
||||||
|
// Start with common attributes that apply to resource and non-resource requests
|
||||||
|
attribs.ResourceRequest = requestInfo.IsResourceRequest
|
||||||
|
attribs.Path = requestInfo.Path
|
||||||
|
attribs.Verb = requestInfo.Verb
|
||||||
|
|
||||||
|
attribs.APIGroup = requestInfo.APIGroup
|
||||||
|
attribs.APIVersion = requestInfo.APIVersion
|
||||||
|
attribs.Resource = requestInfo.Resource
|
||||||
|
attribs.Subresource = requestInfo.Subresource
|
||||||
|
attribs.Namespace = requestInfo.Namespace
|
||||||
|
attribs.Name = requestInfo.Name
|
||||||
|
|
||||||
|
return &attribs
|
||||||
|
}
|
111
pkg/apiserver/filters/authorization_test.go
Normal file
111
pkg/apiserver/filters/authorization_test.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package filters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetAttribs(t *testing.T) {
|
||||||
|
r := &requestAttributeGetter{api.NewRequestContextMapper(), &apiserver.RequestInfoResolver{APIPrefixes: sets.NewString("api", "apis"), GrouplessAPIPrefixes: sets.NewString("api")}}
|
||||||
|
|
||||||
|
testcases := map[string]struct {
|
||||||
|
Verb string
|
||||||
|
Path string
|
||||||
|
ExpectedAttributes *authorizer.AttributesRecord
|
||||||
|
}{
|
||||||
|
"non-resource root": {
|
||||||
|
Verb: "POST",
|
||||||
|
Path: "/",
|
||||||
|
ExpectedAttributes: &authorizer.AttributesRecord{
|
||||||
|
Verb: "post",
|
||||||
|
Path: "/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"non-resource api prefix": {
|
||||||
|
Verb: "GET",
|
||||||
|
Path: "/api/",
|
||||||
|
ExpectedAttributes: &authorizer.AttributesRecord{
|
||||||
|
Verb: "get",
|
||||||
|
Path: "/api/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"non-resource group api prefix": {
|
||||||
|
Verb: "GET",
|
||||||
|
Path: "/apis/extensions/",
|
||||||
|
ExpectedAttributes: &authorizer.AttributesRecord{
|
||||||
|
Verb: "get",
|
||||||
|
Path: "/apis/extensions/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"resource": {
|
||||||
|
Verb: "POST",
|
||||||
|
Path: "/api/v1/nodes/mynode",
|
||||||
|
ExpectedAttributes: &authorizer.AttributesRecord{
|
||||||
|
Verb: "create",
|
||||||
|
Path: "/api/v1/nodes/mynode",
|
||||||
|
ResourceRequest: true,
|
||||||
|
Resource: "nodes",
|
||||||
|
APIVersion: "v1",
|
||||||
|
Name: "mynode",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"namespaced resource": {
|
||||||
|
Verb: "PUT",
|
||||||
|
Path: "/api/v1/namespaces/myns/pods/mypod",
|
||||||
|
ExpectedAttributes: &authorizer.AttributesRecord{
|
||||||
|
Verb: "update",
|
||||||
|
Path: "/api/v1/namespaces/myns/pods/mypod",
|
||||||
|
ResourceRequest: true,
|
||||||
|
Namespace: "myns",
|
||||||
|
Resource: "pods",
|
||||||
|
APIVersion: "v1",
|
||||||
|
Name: "mypod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"API group resource": {
|
||||||
|
Verb: "GET",
|
||||||
|
Path: "/apis/extensions/v1beta1/namespaces/myns/jobs",
|
||||||
|
ExpectedAttributes: &authorizer.AttributesRecord{
|
||||||
|
Verb: "list",
|
||||||
|
Path: "/apis/extensions/v1beta1/namespaces/myns/jobs",
|
||||||
|
ResourceRequest: true,
|
||||||
|
APIGroup: extensions.GroupName,
|
||||||
|
APIVersion: "v1beta1",
|
||||||
|
Namespace: "myns",
|
||||||
|
Resource: "jobs",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, tc := range testcases {
|
||||||
|
req, _ := http.NewRequest(tc.Verb, tc.Path, nil)
|
||||||
|
attribs := r.GetAttribs(req)
|
||||||
|
if !reflect.DeepEqual(attribs, tc.ExpectedAttributes) {
|
||||||
|
t.Errorf("%s: expected\n\t%#v\ngot\n\t%#v", k, tc.ExpectedAttributes, attribs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
pkg/apiserver/filters/doc.go
Normal file
19
pkg/apiserver/filters/doc.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package filters contains all the http handler chain filters which
|
||||||
|
// _are_ api related.
|
||||||
|
package filters // import "k8s.io/kubernetes/pkg/apiserver/filters"
|
43
pkg/apiserver/filters/errors.go
Executable file
43
pkg/apiserver/filters/errors.go
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package filters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/util/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// badGatewayError renders a simple bad gateway error.
|
||||||
|
func badGatewayError(w http.ResponseWriter, req *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusBadGateway)
|
||||||
|
fmt.Fprintf(w, "Bad Gateway: %#v", req.RequestURI)
|
||||||
|
}
|
||||||
|
|
||||||
|
// forbidden renders a simple forbidden error
|
||||||
|
func forbidden(w http.ResponseWriter, req *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusForbidden)
|
||||||
|
fmt.Fprintf(w, "Forbidden: %#v", req.RequestURI)
|
||||||
|
}
|
||||||
|
|
||||||
|
// internalError renders a simple internal error
|
||||||
|
func internalError(w http.ResponseWriter, req *http.Request, err error) {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
fmt.Fprintf(w, "Internal Server Error: %#v", req.RequestURI)
|
||||||
|
runtime.HandleError(err)
|
||||||
|
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package apiserver
|
package filters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package apiserver
|
package filters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -264,7 +264,7 @@ func TestImpersonationFilter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
requestContextMapper = api.NewRequestContextMapper()
|
requestContextMapper := api.NewRequestContextMapper()
|
||||||
var ctx api.Context
|
var ctx api.Context
|
||||||
var actualUser user.Info
|
var actualUser user.Info
|
||||||
var lock sync.Mutex
|
var lock sync.Mutex
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2014 The Kubernetes Authors.
|
Copyright 2015 The Kubernetes Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -21,115 +21,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
)
|
)
|
||||||
|
|
||||||
// specialVerbs contains just strings which are used in REST paths for special actions that don't fall under the normal
|
|
||||||
// CRUDdy GET/POST/PUT/DELETE actions on REST objects.
|
|
||||||
// TODO: find a way to keep this up to date automatically. Maybe dynamically populate list as handlers added to
|
|
||||||
// master's Mux.
|
|
||||||
var specialVerbs = sets.NewString("proxy", "redirect", "watch")
|
|
||||||
|
|
||||||
// specialVerbsNoSubresources contains root verbs which do not allow subresources
|
|
||||||
var specialVerbsNoSubresources = sets.NewString("proxy", "redirect")
|
|
||||||
|
|
||||||
// namespaceSubresources contains subresources of namespace
|
|
||||||
// this list allows the parser to distinguish between a namespace subresource, and a namespaced resource
|
|
||||||
var namespaceSubresources = sets.NewString("status", "finalize")
|
|
||||||
|
|
||||||
// NamespaceSubResourcesForTest exports namespaceSubresources for testing in pkg/master/master_test.go, so we never drift
|
|
||||||
var NamespaceSubResourcesForTest = sets.NewString(namespaceSubresources.List()...)
|
|
||||||
|
|
||||||
// IsReadOnlyReq() is true for any (or at least many) request which has no observable
|
|
||||||
// side effects on state of apiserver (though there may be internal side effects like
|
|
||||||
// caching and logging).
|
|
||||||
func IsReadOnlyReq(req http.Request) bool {
|
|
||||||
if req.Method == "GET" {
|
|
||||||
// TODO: add OPTIONS and HEAD if we ever support those.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadOnly passes all GET requests on to handler, and returns an error on all other requests.
|
|
||||||
func ReadOnly(handler http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
||||||
if IsReadOnlyReq(*req) {
|
|
||||||
handler.ServeHTTP(w, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.WriteHeader(http.StatusForbidden)
|
|
||||||
fmt.Fprintf(w, "This is a read-only endpoint.")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestAttributeGetter is a function that extracts authorizer.Attributes from an http.Request
|
|
||||||
type RequestAttributeGetter interface {
|
|
||||||
GetAttribs(req *http.Request) (attribs authorizer.Attributes)
|
|
||||||
}
|
|
||||||
|
|
||||||
type requestAttributeGetter struct {
|
|
||||||
requestContextMapper api.RequestContextMapper
|
|
||||||
requestInfoResolver *RequestInfoResolver
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAttributeGetter returns an object which implements the RequestAttributeGetter interface.
|
|
||||||
func NewRequestAttributeGetter(requestContextMapper api.RequestContextMapper, requestInfoResolver *RequestInfoResolver) RequestAttributeGetter {
|
|
||||||
return &requestAttributeGetter{requestContextMapper, requestInfoResolver}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestAttributeGetter) GetAttribs(req *http.Request) authorizer.Attributes {
|
|
||||||
attribs := authorizer.AttributesRecord{}
|
|
||||||
|
|
||||||
ctx, ok := r.requestContextMapper.Get(req)
|
|
||||||
if ok {
|
|
||||||
user, ok := api.UserFrom(ctx)
|
|
||||||
if ok {
|
|
||||||
attribs.User = user
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
requestInfo, _ := r.requestInfoResolver.GetRequestInfo(req)
|
|
||||||
|
|
||||||
// Start with common attributes that apply to resource and non-resource requests
|
|
||||||
attribs.ResourceRequest = requestInfo.IsResourceRequest
|
|
||||||
attribs.Path = requestInfo.Path
|
|
||||||
attribs.Verb = requestInfo.Verb
|
|
||||||
|
|
||||||
attribs.APIGroup = requestInfo.APIGroup
|
|
||||||
attribs.APIVersion = requestInfo.APIVersion
|
|
||||||
attribs.Resource = requestInfo.Resource
|
|
||||||
attribs.Subresource = requestInfo.Subresource
|
|
||||||
attribs.Namespace = requestInfo.Namespace
|
|
||||||
attribs.Name = requestInfo.Name
|
|
||||||
|
|
||||||
return &attribs
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithAuthorizationCheck passes all authorized requests on to handler, and returns a forbidden error otherwise.
|
|
||||||
func WithAuthorization(handler http.Handler, getAttribs RequestAttributeGetter, a authorizer.Authorizer) http.Handler {
|
|
||||||
if a == nil {
|
|
||||||
glog.Warningf("Authorization is disabled")
|
|
||||||
return handler
|
|
||||||
}
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
||||||
authorized, reason, err := a.Authorize(getAttribs.GetAttribs(req))
|
|
||||||
if err != nil {
|
|
||||||
internalError(w, req, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !authorized {
|
|
||||||
glog.V(4).Infof("Forbidden: %#v, Reason: %s", req.RequestURI, reason)
|
|
||||||
forbidden(w, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
handler.ServeHTTP(w, req)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestInfo holds information parsed from the http.Request
|
// RequestInfo holds information parsed from the http.Request
|
||||||
type RequestInfo struct {
|
type RequestInfo struct {
|
||||||
// IsResourceRequest indicates whether or not the request is for an API resource or subresource
|
// IsResourceRequest indicates whether or not the request is for an API resource or subresource
|
||||||
@ -156,6 +51,22 @@ type RequestInfo struct {
|
|||||||
Parts []string
|
Parts []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// specialVerbs contains just strings which are used in REST paths for special actions that don't fall under the normal
|
||||||
|
// CRUDdy GET/POST/PUT/DELETE actions on REST objects.
|
||||||
|
// TODO: find a way to keep this up to date automatically. Maybe dynamically populate list as handlers added to
|
||||||
|
// master's Mux.
|
||||||
|
var specialVerbs = sets.NewString("proxy", "redirect", "watch")
|
||||||
|
|
||||||
|
// specialVerbsNoSubresources contains root verbs which do not allow subresources
|
||||||
|
var specialVerbsNoSubresources = sets.NewString("proxy", "redirect")
|
||||||
|
|
||||||
|
// namespaceSubresources contains subresources of namespace
|
||||||
|
// this list allows the parser to distinguish between a namespace subresource, and a namespaced resource
|
||||||
|
var namespaceSubresources = sets.NewString("status", "finalize")
|
||||||
|
|
||||||
|
// NamespaceSubResourcesForTest exports namespaceSubresources for testing in pkg/master/master_test.go, so we never drift
|
||||||
|
var NamespaceSubResourcesForTest = sets.NewString(namespaceSubresources.List()...)
|
||||||
|
|
||||||
type RequestInfoResolver struct {
|
type RequestInfoResolver struct {
|
||||||
APIPrefixes sets.String
|
APIPrefixes sets.String
|
||||||
GrouplessAPIPrefixes sets.String
|
GrouplessAPIPrefixes sets.String
|
||||||
@ -295,3 +206,12 @@ func (r *RequestInfoResolver) GetRequestInfo(req *http.Request) (RequestInfo, er
|
|||||||
|
|
||||||
return requestInfo, nil
|
return requestInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// splitPath returns the segments for a URL path.
|
||||||
|
func splitPath(path string) []string {
|
||||||
|
path = strings.Trim(path, "/")
|
||||||
|
if path == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
return strings.Split(path, "/")
|
||||||
|
}
|
@ -18,14 +18,11 @@ package apiserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,106 +40,6 @@ func pathWithPrefix(prefix, resource, namespace, name string) string {
|
|||||||
return testapi.Default.ResourcePathWithPrefix(prefix, resource, namespace, name)
|
return testapi.Default.ResourcePathWithPrefix(prefix, resource, namespace, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadOnly(t *testing.T) {
|
|
||||||
server := httptest.NewServer(ReadOnly(http.HandlerFunc(
|
|
||||||
func(w http.ResponseWriter, req *http.Request) {
|
|
||||||
if req.Method != "GET" {
|
|
||||||
t.Errorf("Unexpected call: %v", req.Method)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)))
|
|
||||||
defer server.Close()
|
|
||||||
for _, verb := range []string{"GET", "POST", "PUT", "DELETE", "CREATE"} {
|
|
||||||
req, err := http.NewRequest(verb, server.URL, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Couldn't make request: %v", err)
|
|
||||||
}
|
|
||||||
http.DefaultClient.Do(req)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAttribs(t *testing.T) {
|
|
||||||
r := &requestAttributeGetter{api.NewRequestContextMapper(), &RequestInfoResolver{sets.NewString("api", "apis"), sets.NewString("api")}}
|
|
||||||
|
|
||||||
testcases := map[string]struct {
|
|
||||||
Verb string
|
|
||||||
Path string
|
|
||||||
ExpectedAttributes *authorizer.AttributesRecord
|
|
||||||
}{
|
|
||||||
"non-resource root": {
|
|
||||||
Verb: "POST",
|
|
||||||
Path: "/",
|
|
||||||
ExpectedAttributes: &authorizer.AttributesRecord{
|
|
||||||
Verb: "post",
|
|
||||||
Path: "/",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"non-resource api prefix": {
|
|
||||||
Verb: "GET",
|
|
||||||
Path: "/api/",
|
|
||||||
ExpectedAttributes: &authorizer.AttributesRecord{
|
|
||||||
Verb: "get",
|
|
||||||
Path: "/api/",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"non-resource group api prefix": {
|
|
||||||
Verb: "GET",
|
|
||||||
Path: "/apis/extensions/",
|
|
||||||
ExpectedAttributes: &authorizer.AttributesRecord{
|
|
||||||
Verb: "get",
|
|
||||||
Path: "/apis/extensions/",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
"resource": {
|
|
||||||
Verb: "POST",
|
|
||||||
Path: "/api/v1/nodes/mynode",
|
|
||||||
ExpectedAttributes: &authorizer.AttributesRecord{
|
|
||||||
Verb: "create",
|
|
||||||
Path: "/api/v1/nodes/mynode",
|
|
||||||
ResourceRequest: true,
|
|
||||||
Resource: "nodes",
|
|
||||||
APIVersion: "v1",
|
|
||||||
Name: "mynode",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"namespaced resource": {
|
|
||||||
Verb: "PUT",
|
|
||||||
Path: "/api/v1/namespaces/myns/pods/mypod",
|
|
||||||
ExpectedAttributes: &authorizer.AttributesRecord{
|
|
||||||
Verb: "update",
|
|
||||||
Path: "/api/v1/namespaces/myns/pods/mypod",
|
|
||||||
ResourceRequest: true,
|
|
||||||
Namespace: "myns",
|
|
||||||
Resource: "pods",
|
|
||||||
APIVersion: "v1",
|
|
||||||
Name: "mypod",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"API group resource": {
|
|
||||||
Verb: "GET",
|
|
||||||
Path: "/apis/extensions/v1beta1/namespaces/myns/jobs",
|
|
||||||
ExpectedAttributes: &authorizer.AttributesRecord{
|
|
||||||
Verb: "list",
|
|
||||||
Path: "/apis/extensions/v1beta1/namespaces/myns/jobs",
|
|
||||||
ResourceRequest: true,
|
|
||||||
APIGroup: extensions.GroupName,
|
|
||||||
APIVersion: "v1beta1",
|
|
||||||
Namespace: "myns",
|
|
||||||
Resource: "jobs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, tc := range testcases {
|
|
||||||
req, _ := http.NewRequest(tc.Verb, tc.Path, nil)
|
|
||||||
attribs := r.GetAttribs(req)
|
|
||||||
if !reflect.DeepEqual(attribs, tc.ExpectedAttributes) {
|
|
||||||
t.Errorf("%s: expected\n\t%#v\ngot\n\t%#v", k, tc.ExpectedAttributes, attribs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAPIRequestInfo(t *testing.T) {
|
func TestGetAPIRequestInfo(t *testing.T) {
|
||||||
successCases := []struct {
|
successCases := []struct {
|
||||||
method string
|
method string
|
||||||
@ -202,12 +99,12 @@ func TestGetAPIRequestInfo(t *testing.T) {
|
|||||||
{"POST", "/apis/extensions/v1beta3/namespaces/other/pods", "create", "api", "extensions", "v1beta3", "other", "pods", "", "", []string{"pods"}},
|
{"POST", "/apis/extensions/v1beta3/namespaces/other/pods", "create", "api", "extensions", "v1beta3", "other", "pods", "", "", []string{"pods"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
requestInfoResolver := newTestRequestInfoResolver()
|
resolver := newTestRequestInfoResolver()
|
||||||
|
|
||||||
for _, successCase := range successCases {
|
for _, successCase := range successCases {
|
||||||
req, _ := http.NewRequest(successCase.method, successCase.url, nil)
|
req, _ := http.NewRequest(successCase.method, successCase.url, nil)
|
||||||
|
|
||||||
apiRequestInfo, err := requestInfoResolver.GetRequestInfo(req)
|
apiRequestInfo, err := resolver.GetRequestInfo(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error for url: %s %v", successCase.url, err)
|
t.Errorf("Unexpected error for url: %s %v", successCase.url, err)
|
||||||
}
|
}
|
||||||
@ -250,7 +147,7 @@ func TestGetAPIRequestInfo(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error %v", err)
|
t.Errorf("Unexpected error %v", err)
|
||||||
}
|
}
|
||||||
apiRequestInfo, err := requestInfoResolver.GetRequestInfo(req)
|
apiRequestInfo, err := resolver.GetRequestInfo(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: Unexpected error %v", k, err)
|
t.Errorf("%s: Unexpected error %v", k, err)
|
||||||
}
|
}
|
||||||
@ -281,12 +178,12 @@ func TestGetNonAPIRequestInfo(t *testing.T) {
|
|||||||
"empty": {"", false},
|
"empty": {"", false},
|
||||||
}
|
}
|
||||||
|
|
||||||
requestInfoResolver := newTestRequestInfoResolver()
|
resolver := newTestRequestInfoResolver()
|
||||||
|
|
||||||
for testName, tc := range tests {
|
for testName, tc := range tests {
|
||||||
req, _ := http.NewRequest("GET", tc.url, nil)
|
req, _ := http.NewRequest("GET", tc.url, nil)
|
||||||
|
|
||||||
apiRequestInfo, err := requestInfoResolver.GetRequestInfo(req)
|
apiRequestInfo, err := resolver.GetRequestInfo(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: Unexpected error %v", testName, err)
|
t.Errorf("%s: Unexpected error %v", testName, err)
|
||||||
}
|
}
|
||||||
@ -295,3 +192,7 @@ func TestGetNonAPIRequestInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newTestRequestInfoResolver() *RequestInfoResolver {
|
||||||
|
return &RequestInfoResolver{sets.NewString("api", "apis"), sets.NewString("api")}
|
||||||
|
}
|
42
pkg/apiserver/serviceerror.go
Normal file
42
pkg/apiserver/serviceerror.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package apiserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/emicklei/go-restful"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InstallServiceErrorHandler(s runtime.NegotiatedSerializer, container *restful.Container) {
|
||||||
|
container.ServiceErrorHandler(func(serviceErr restful.ServiceError, request *restful.Request, response *restful.Response) {
|
||||||
|
serviceErrorHandler(s, serviceErr, request, response)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func serviceErrorHandler(s runtime.NegotiatedSerializer, serviceErr restful.ServiceError, request *restful.Request, response *restful.Response) {
|
||||||
|
errorNegotiated(
|
||||||
|
apierrors.NewGenericServerResponse(serviceErr.Code, "", api.Resource(""), "", serviceErr.Message, 0, false),
|
||||||
|
s,
|
||||||
|
unversioned.GroupVersion{},
|
||||||
|
response.ResponseWriter,
|
||||||
|
request.Request,
|
||||||
|
)
|
||||||
|
}
|
@ -36,7 +36,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/pkg/apiserver/audit"
|
apiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters"
|
||||||
"k8s.io/kubernetes/pkg/auth/authenticator"
|
"k8s.io/kubernetes/pkg/auth/authenticator"
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
authhandlers "k8s.io/kubernetes/pkg/auth/handlers"
|
authhandlers "k8s.io/kubernetes/pkg/auth/handlers"
|
||||||
@ -363,18 +363,16 @@ func (s *GenericAPIServer) buildHandlerChains(c *Config, handler http.Handler) (
|
|||||||
|
|
||||||
// insecure filters
|
// insecure filters
|
||||||
insecure = handler
|
insecure = handler
|
||||||
insecure = api.WithRequestContext(insecure, c.RequestContextMapper)
|
|
||||||
insecure = genericfilters.WithPanicRecovery(insecure, s.NewRequestInfoResolver())
|
insecure = genericfilters.WithPanicRecovery(insecure, s.NewRequestInfoResolver())
|
||||||
insecure = genericfilters.WithTimeoutForNonLongRunningRequests(insecure, longRunningFunc)
|
insecure = genericfilters.WithTimeoutForNonLongRunningRequests(insecure, longRunningFunc)
|
||||||
|
|
||||||
// secure filters
|
// secure filters
|
||||||
attributeGetter := apiserver.NewRequestAttributeGetter(c.RequestContextMapper, s.NewRequestInfoResolver())
|
attributeGetter := apiserverfilters.NewRequestAttributeGetter(c.RequestContextMapper, s.NewRequestInfoResolver())
|
||||||
secure = handler
|
secure = handler
|
||||||
secure = apiserver.WithAuthorization(secure, attributeGetter, c.Authorizer)
|
secure = apiserverfilters.WithAuthorization(secure, attributeGetter, c.Authorizer)
|
||||||
secure = apiserver.WithImpersonation(secure, c.RequestContextMapper, c.Authorizer)
|
secure = apiserverfilters.WithImpersonation(secure, c.RequestContextMapper, c.Authorizer)
|
||||||
secure = audit.WithAudit(secure, attributeGetter, s.auditWriter) // before impersonation to read original user
|
secure = apiserverfilters.WithAudit(secure, attributeGetter, s.auditWriter) // before impersonation to read original user
|
||||||
secure = authhandlers.WithAuthentication(secure, c.RequestContextMapper, c.Authenticator, authhandlers.Unauthorized(c.SupportsBasicAuth))
|
secure = authhandlers.WithAuthentication(secure, c.RequestContextMapper, c.Authenticator, authhandlers.Unauthorized(c.SupportsBasicAuth))
|
||||||
secure = api.WithRequestContext(secure, c.RequestContextMapper)
|
|
||||||
secure = genericfilters.WithPanicRecovery(secure, s.NewRequestInfoResolver())
|
secure = genericfilters.WithPanicRecovery(secure, s.NewRequestInfoResolver())
|
||||||
secure = genericfilters.WithTimeoutForNonLongRunningRequests(secure, longRunningFunc)
|
secure = genericfilters.WithTimeoutForNonLongRunningRequests(secure, longRunningFunc)
|
||||||
secure = genericfilters.WithMaxInFlightLimit(secure, c.MaxRequestsInFlight, longRunningFunc)
|
secure = genericfilters.WithMaxInFlightLimit(secure, c.MaxRequestsInFlight, longRunningFunc)
|
||||||
|
Loading…
Reference in New Issue
Block a user