Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
6dc2f633
Commit
6dc2f633
authored
Sep 26, 2016
by
Dr. Stefan Schimanski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Separate apiserver handler filters
parent
a2f943e7
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
353 additions
and
279 deletions
+353
-279
apiserver.go
pkg/apiserver/apiserver.go
+0
-26
apiserver_test.go
pkg/apiserver/apiserver_test.go
+0
-5
errors.go
pkg/apiserver/errors.go
+0
-19
audit.go
pkg/apiserver/filters/audit.go
+2
-3
audit_test.go
pkg/apiserver/filters/audit_test.go
+2
-2
authorization.go
pkg/apiserver/filters/authorization.go
+91
-0
authorization_test.go
pkg/apiserver/filters/authorization_test.go
+111
-0
doc.go
pkg/apiserver/filters/doc.go
+19
-0
errors.go
pkg/apiserver/filters/errors.go
+43
-0
impersonation.go
pkg/apiserver/filters/impersonation.go
+1
-1
impersonation_test.go
pkg/apiserver/filters/impersonation_test.go
+2
-2
requestinfo.go
pkg/apiserver/requestinfo.go
+26
-106
requestinfo_test.go
pkg/apiserver/requestinfo_test.go
+9
-108
serviceerror.go
pkg/apiserver/serviceerror.go
+42
-0
config.go
pkg/genericapiserver/config.go
+5
-7
No files found.
pkg/apiserver/apiserver.go
View file @
6dc2f633
...
...
@@ -27,7 +27,6 @@ import (
"path"
rt
"runtime"
"strconv"
"strings"
"time"
"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
})
}
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.
func
AddApiWebService
(
s
runtime
.
NegotiatedSerializer
,
container
*
restful
.
Container
,
apiPrefix
string
,
getAPIVersionsFunc
func
(
req
*
restful
.
Request
)
*
unversioned
.
APIVersions
)
{
// TODO: InstallREST should register each version automatically
...
...
@@ -501,12 +484,3 @@ func readBody(req *http.Request) ([]byte, error) {
defer
req
.
Body
.
Close
()
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
,
"/"
)
}
pkg/apiserver/apiserver_test.go
View file @
6dc2f633
...
...
@@ -44,7 +44,6 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/diff"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/watch"
"k8s.io/kubernetes/pkg/watch/versioned"
"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
)
}
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
{
container
:=
restful
.
NewContainer
()
container
.
Router
(
restful
.
CurlyRouter
{})
...
...
pkg/apiserver/errors.go
View file @
6dc2f633
...
...
@@ -76,25 +76,6 @@ func notFound(w http.ResponseWriter, req *http.Request) {
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
// any known API prefixes
type
errAPIPrefixNotFound
struct
{
...
...
pkg/apiserver/
audit
/audit.go
→
pkg/apiserver/
filters
/audit.go
View file @
6dc2f633
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
audit
package
filters
import
(
"bufio"
...
...
@@ -27,7 +27,6 @@ import (
"github.com/golang/glog"
"github.com/pborman/uuid"
"k8s.io/kubernetes/pkg/apiserver"
utilnet
"k8s.io/kubernetes/pkg/util/net"
)
...
...
@@ -85,7 +84,7 @@ var _ http.Hijacker = &fancyResponseWriterDelegator{}
// 2. the response line containing:
// - the unique id from 1
// - 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
{
return
handler
}
...
...
pkg/apiserver/
audit
/audit_test.go
→
pkg/apiserver/
filters
/audit_test.go
View file @
6dc2f633
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
audit
package
filters
import
(
"bufio"
...
...
@@ -85,7 +85,7 @@ func (*fakeRequestContextMapper) Update(req *http.Request, context api.Context)
func
TestAudit
(
t
*
testing
.
T
)
{
var
buf
bytes
.
Buffer
attributeGetter
:=
apiserver
.
NewRequestAttributeGetter
(
&
fakeRequestContextMapper
{},
attributeGetter
:=
NewRequestAttributeGetter
(
&
fakeRequestContextMapper
{},
&
apiserver
.
RequestInfoResolver
{
APIPrefixes
:
sets
.
NewString
(
"api"
,
"apis"
),
GrouplessAPIPrefixes
:
sets
.
NewString
(
"api"
)})
handler
:=
WithAudit
(
&
fakeHTTPHandler
{},
attributeGetter
,
&
buf
)
req
,
_
:=
http
.
NewRequest
(
"GET"
,
"/api/v1/namespaces/default/pods"
,
nil
)
...
...
pkg/apiserver/filters/authorization.go
0 → 100644
View file @
6dc2f633
/*
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
}
pkg/apiserver/filters/authorization_test.go
0 → 100644
View file @
6dc2f633
/*
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
\n
got
\n\t
%#v"
,
k
,
tc
.
ExpectedAttributes
,
attribs
)
}
}
}
pkg/apiserver/filters/doc.go
0 → 100644
View file @
6dc2f633
/*
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"
pkg/apiserver/filters/errors.go
0 → 100755
View file @
6dc2f633
/*
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
)
}
pkg/apiserver/
handler_
impersonation.go
→
pkg/apiserver/
filters/
impersonation.go
View file @
6dc2f633
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
apiserver
package
filters
import
(
"fmt"
...
...
pkg/apiserver/
handler_
impersonation_test.go
→
pkg/apiserver/
filters/
impersonation_test.go
View file @
6dc2f633
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
apiserver
package
filters
import
(
"fmt"
...
...
@@ -264,7 +264,7 @@ func TestImpersonationFilter(t *testing.T) {
},
}
requestContextMapper
=
api
.
NewRequestContextMapper
()
requestContextMapper
:
=
api
.
NewRequestContextMapper
()
var
ctx
api
.
Context
var
actualUser
user
.
Info
var
lock
sync
.
Mutex
...
...
pkg/apiserver/
handlers
.go
→
pkg/apiserver/
requestinfo
.go
View file @
6dc2f633
/*
Copyright 201
4
The Kubernetes Authors.
Copyright 201
5
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.
...
...
@@ -21,115 +21,10 @@ import (
"net/http"
"strings"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/auth/authorizer"
"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
type
RequestInfo
struct
{
// IsResourceRequest indicates whether or not the request is for an API resource or subresource
...
...
@@ -156,6 +51,22 @@ type RequestInfo struct {
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
{
APIPrefixes
sets
.
String
GrouplessAPIPrefixes
sets
.
String
...
...
@@ -295,3 +206,12 @@ func (r *RequestInfoResolver) GetRequestInfo(req *http.Request) (RequestInfo, er
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
,
"/"
)
}
pkg/apiserver/
handlers
_test.go
→
pkg/apiserver/
requestinfo
_test.go
View file @
6dc2f633
...
...
@@ -18,14 +18,11 @@ package apiserver
import
(
"net/http"
"net/http/httptest"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/auth/authorizer"
"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
)
}
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
\n
got
\n\t
%#v"
,
k
,
tc
.
ExpectedAttributes
,
attribs
)
}
}
}
func
TestGetAPIRequestInfo
(
t
*
testing
.
T
)
{
successCases
:=
[]
struct
{
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"
}},
}
re
questInfoRe
solver
:=
newTestRequestInfoResolver
()
resolver
:=
newTestRequestInfoResolver
()
for
_
,
successCase
:=
range
successCases
{
req
,
_
:=
http
.
NewRequest
(
successCase
.
method
,
successCase
.
url
,
nil
)
apiRequestInfo
,
err
:=
re
questInfoRe
solver
.
GetRequestInfo
(
req
)
apiRequestInfo
,
err
:=
resolver
.
GetRequestInfo
(
req
)
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error for url: %s %v"
,
successCase
.
url
,
err
)
}
...
...
@@ -250,7 +147,7 @@ func TestGetAPIRequestInfo(t *testing.T) {
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error %v"
,
err
)
}
apiRequestInfo
,
err
:=
re
questInfoRe
solver
.
GetRequestInfo
(
req
)
apiRequestInfo
,
err
:=
resolver
.
GetRequestInfo
(
req
)
if
err
!=
nil
{
t
.
Errorf
(
"%s: Unexpected error %v"
,
k
,
err
)
}
...
...
@@ -281,12 +178,12 @@ func TestGetNonAPIRequestInfo(t *testing.T) {
"empty"
:
{
""
,
false
},
}
re
questInfoRe
solver
:=
newTestRequestInfoResolver
()
resolver
:=
newTestRequestInfoResolver
()
for
testName
,
tc
:=
range
tests
{
req
,
_
:=
http
.
NewRequest
(
"GET"
,
tc
.
url
,
nil
)
apiRequestInfo
,
err
:=
re
questInfoRe
solver
.
GetRequestInfo
(
req
)
apiRequestInfo
,
err
:=
resolver
.
GetRequestInfo
(
req
)
if
err
!=
nil
{
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"
)}
}
pkg/apiserver/serviceerror.go
0 → 100644
View file @
6dc2f633
/*
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
,
)
}
pkg/genericapiserver/config.go
View file @
6dc2f633
...
...
@@ -36,7 +36,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"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/authorizer"
authhandlers
"k8s.io/kubernetes/pkg/auth/handlers"
...
...
@@ -363,18 +363,16 @@ func (s *GenericAPIServer) buildHandlerChains(c *Config, handler http.Handler) (
// insecure filters
insecure
=
handler
insecure
=
api
.
WithRequestContext
(
insecure
,
c
.
RequestContextMapper
)
insecure
=
genericfilters
.
WithPanicRecovery
(
insecure
,
s
.
NewRequestInfoResolver
())
insecure
=
genericfilters
.
WithTimeoutForNonLongRunningRequests
(
insecure
,
longRunningFunc
)
// secure filters
attributeGetter
:=
apiserver
.
NewRequestAttributeGetter
(
c
.
RequestContextMapper
,
s
.
NewRequestInfoResolver
())
attributeGetter
:=
apiserver
filters
.
NewRequestAttributeGetter
(
c
.
RequestContextMapper
,
s
.
NewRequestInfoResolver
())
secure
=
handler
secure
=
apiserver
.
WithAuthorization
(
secure
,
attributeGetter
,
c
.
Authorizer
)
secure
=
apiserver
.
WithImpersonation
(
secure
,
c
.
RequestContextMapper
,
c
.
Authorizer
)
secure
=
a
udit
.
WithAudit
(
secure
,
attributeGetter
,
s
.
auditWriter
)
// before impersonation to read original user
secure
=
apiserver
filters
.
WithAuthorization
(
secure
,
attributeGetter
,
c
.
Authorizer
)
secure
=
apiserver
filters
.
WithImpersonation
(
secure
,
c
.
RequestContextMapper
,
c
.
Authorizer
)
secure
=
a
piserverfilters
.
WithAudit
(
secure
,
attributeGetter
,
s
.
auditWriter
)
// before impersonation to read original user
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
.
WithTimeoutForNonLongRunningRequests
(
secure
,
longRunningFunc
)
secure
=
genericfilters
.
WithMaxInFlightLimit
(
secure
,
c
.
MaxRequestsInFlight
,
longRunningFunc
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment