mirror of
https://github.com/rancher/steve.git
synced 2025-08-01 23:03:28 +00:00
Refactor to add links instead of bool for resourcePermissions, updated tests accordingly.
This commit is contained in:
parent
eed59ebf8a
commit
5fa7be534a
@ -42,15 +42,20 @@ func DefaultTemplateForStore(store types.Store,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func selfLink(gvr schema2.GroupVersionResource, meta metav1.Object) (prefix string) {
|
func selfLink(gvr schema2.GroupVersionResource, meta metav1.Object) (prefix string) {
|
||||||
|
return buildBasePath(gvr, meta.GetNamespace(), meta.GetName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildBasePath(gvr schema2.GroupVersionResource, namespace string, includeName string) string {
|
||||||
buf := &strings.Builder{}
|
buf := &strings.Builder{}
|
||||||
|
|
||||||
if gvr.Group == "management.cattle.io" && gvr.Version == "v3" {
|
if gvr.Group == "management.cattle.io" && gvr.Version == "v3" {
|
||||||
buf.WriteString("/v1/")
|
buf.WriteString("/v1/")
|
||||||
buf.WriteString(gvr.Group)
|
buf.WriteString(gvr.Group)
|
||||||
buf.WriteString(".")
|
buf.WriteString(".")
|
||||||
buf.WriteString(gvr.Resource)
|
buf.WriteString(gvr.Resource)
|
||||||
if meta.GetNamespace() != "" {
|
if namespace != "" {
|
||||||
buf.WriteString("/")
|
buf.WriteString("/")
|
||||||
buf.WriteString(meta.GetNamespace())
|
buf.WriteString(namespace)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if gvr.Group == "" {
|
if gvr.Group == "" {
|
||||||
@ -62,15 +67,19 @@ func selfLink(gvr schema2.GroupVersionResource, meta metav1.Object) (prefix stri
|
|||||||
buf.WriteString(gvr.Version)
|
buf.WriteString(gvr.Version)
|
||||||
buf.WriteString("/")
|
buf.WriteString("/")
|
||||||
}
|
}
|
||||||
if meta.GetNamespace() != "" {
|
if namespace != "" {
|
||||||
buf.WriteString("namespaces/")
|
buf.WriteString("namespaces/")
|
||||||
buf.WriteString(meta.GetNamespace())
|
buf.WriteString(namespace)
|
||||||
buf.WriteString("/")
|
buf.WriteString("/")
|
||||||
}
|
}
|
||||||
buf.WriteString(gvr.Resource)
|
buf.WriteString(gvr.Resource)
|
||||||
}
|
}
|
||||||
buf.WriteString("/")
|
|
||||||
buf.WriteString(meta.GetName())
|
if includeName != "" {
|
||||||
|
buf.WriteString("/")
|
||||||
|
buf.WriteString(includeName)
|
||||||
|
}
|
||||||
|
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,16 +157,23 @@ func formatter(summarycache common.SummaryCache, asl accesscontrol.AccessSetLook
|
|||||||
}
|
}
|
||||||
|
|
||||||
if permsQuery := request.Query.Get("checkPermissions"); permsQuery != "" {
|
if permsQuery := request.Query.Get("checkPermissions"); permsQuery != "" {
|
||||||
id := resource.APIObject.ID
|
ns := getNamespaceFromResource(resource.APIObject)
|
||||||
ns := getNamespaceFromResource(id)
|
permissions := map[string]map[string]string{}
|
||||||
gvr := attributes.GVR(resource.Schema)
|
|
||||||
permissions := map[string]map[string]bool{}
|
|
||||||
for _, res := range strings.Split(permsQuery, ",") {
|
for _, res := range strings.Split(permsQuery, ",") {
|
||||||
perms := map[string]bool{}
|
s := request.Schemas.LookupSchema(res)
|
||||||
|
if s == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gvr := attributes.GVR(s)
|
||||||
|
gr := schema2.GroupResource{Group: gvr.Group, Resource: gvr.Resource}
|
||||||
|
perms := map[string]string{}
|
||||||
|
|
||||||
for _, verb := range []string{"create", "update", "delete", "list", "get", "watch", "patch"} {
|
for _, verb := range []string{"create", "update", "delete", "list", "get", "watch", "patch"} {
|
||||||
allowed := accessSet.Grants(verb, schema2.GroupResource{Group: gvr.Group, Resource: res}, ns, "")
|
if accessSet.Grants(verb, gr, ns, "") {
|
||||||
// TODO maybe add links rather than true/false
|
url := request.URLBuilder.RelativeToRoot(buildBasePath(gvr, ns, ""))
|
||||||
perms[verb] = allowed
|
perms[verb] = url
|
||||||
|
}
|
||||||
}
|
}
|
||||||
permissions[res] = perms
|
permissions[res] = perms
|
||||||
}
|
}
|
||||||
@ -205,10 +221,26 @@ func excludeValues(request *types.APIRequest, unstr *unstructured.Unstructured)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNamespaceFromResource(resourceID string) string {
|
func getNamespaceFromResource(obj types.APIObject) string {
|
||||||
parts := strings.SplitN(resourceID, "/", 2)
|
unstr, ok := obj.Object.(*unstructured.Unstructured)
|
||||||
if len(parts) == 2 {
|
if !ok {
|
||||||
return parts[1]
|
return ""
|
||||||
}
|
}
|
||||||
return resourceID
|
|
||||||
|
// If we have a backingNamespace, use that
|
||||||
|
if statusRaw, ok := unstr.Object["status"]; ok {
|
||||||
|
if statusMap, ok := statusRaw.(map[string]interface{}); ok {
|
||||||
|
if backingNamespace, ok := statusMap["backingNamespace"].(string); ok && backingNamespace != "" {
|
||||||
|
return backingNamespace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, if the id has a slash, we will interpret that
|
||||||
|
parts := strings.SplitN(obj.ID, "/", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
return parts[0] + "-" + parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.ID
|
||||||
}
|
}
|
||||||
|
@ -1088,7 +1088,7 @@ func TestFormatterAddsResourcePermissions(t *testing.T) {
|
|||||||
resourcePermissions map[string][]string
|
resourcePermissions map[string][]string
|
||||||
schema *types.APISchema
|
schema *types.APISchema
|
||||||
apiObject types.APIObject
|
apiObject types.APIObject
|
||||||
want map[string]map[string]bool
|
want map[string]map[string]string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "get update patch on project and get on projectroletemplatebindings",
|
name: "get update patch on project and get on projectroletemplatebindings",
|
||||||
@ -1112,15 +1112,11 @@ func TestFormatterAddsResourcePermissions(t *testing.T) {
|
|||||||
Object: map[string]interface{}{},
|
Object: map[string]interface{}{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: map[string]map[string]bool{
|
want: map[string]map[string]string{
|
||||||
"projectroletemplatebindings": {
|
"projectroletemplatebindings": {
|
||||||
"get": true,
|
"get": "/apis/management.cattle.io/v1/namespaces/clusterid-projectid/projectroletemplatebindings",
|
||||||
"list": true,
|
"list": "/apis/management.cattle.io/v1/namespaces/clusterid-projectid/projectroletemplatebindings",
|
||||||
"watch": true,
|
"watch": "/apis/management.cattle.io/v1/namespaces/clusterid-projectid/projectroletemplatebindings",
|
||||||
"create": false,
|
|
||||||
"delete": false,
|
|
||||||
"patch": false,
|
|
||||||
"update": false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1147,24 +1143,16 @@ func TestFormatterAddsResourcePermissions(t *testing.T) {
|
|||||||
Object: map[string]interface{}{},
|
Object: map[string]interface{}{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: map[string]map[string]bool{
|
want: map[string]map[string]string{
|
||||||
"projectroletemplatebindings": {
|
"projectroletemplatebindings": {
|
||||||
"get": true,
|
"get": "/apis/management.cattle.io/v1/namespaces/clusterid-projectid/projectroletemplatebindings",
|
||||||
"list": true,
|
"list": "/apis/management.cattle.io/v1/namespaces/clusterid-projectid/projectroletemplatebindings",
|
||||||
"watch": true,
|
"watch": "/apis/management.cattle.io/v1/namespaces/clusterid-projectid/projectroletemplatebindings",
|
||||||
"create": false,
|
|
||||||
"delete": false,
|
|
||||||
"patch": false,
|
|
||||||
"update": false,
|
|
||||||
},
|
},
|
||||||
"pods": {
|
"pods": {
|
||||||
"get": true,
|
"get": "/apis/management.cattle.io/v1/namespaces/clusterid-projectid/pods",
|
||||||
"list": true,
|
"list": "/apis/management.cattle.io/v1/namespaces/clusterid-projectid/pods",
|
||||||
"watch": true,
|
"watch": "/apis/management.cattle.io/v1/namespaces/clusterid-projectid/pods",
|
||||||
"create": false,
|
|
||||||
"delete": false,
|
|
||||||
"patch": false,
|
|
||||||
"update": false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1188,17 +1176,7 @@ func TestFormatterAddsResourcePermissions(t *testing.T) {
|
|||||||
Object: map[string]interface{}{},
|
Object: map[string]interface{}{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: map[string]map[string]bool{
|
want: nil,
|
||||||
"unknown": {
|
|
||||||
"get": false,
|
|
||||||
"list": false,
|
|
||||||
"watch": false,
|
|
||||||
"create": false,
|
|
||||||
"delete": false,
|
|
||||||
"patch": false,
|
|
||||||
"update": false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1234,7 +1212,7 @@ func TestFormatterAddsResourcePermissions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, verb := range verbs {
|
for _, verb := range verbs {
|
||||||
accessSet.Add(verb, gvr.GroupResource(), accesscontrol.Access{
|
accessSet.Add(verb, gvr.GroupResource(), accesscontrol.Access{
|
||||||
Namespace: projectid,
|
Namespace: clusterid + "-" + projectid,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1254,6 +1232,30 @@ func TestFormatterAddsResourcePermissions(t *testing.T) {
|
|||||||
Query: url.Values{
|
Query: url.Values{
|
||||||
"checkPermissions": {strings.Join(checkPerms, ",")},
|
"checkPermissions": {strings.Join(checkPerms, ",")},
|
||||||
},
|
},
|
||||||
|
Schemas: types.EmptyAPISchemas(),
|
||||||
|
}
|
||||||
|
addSchema := func(names ...string) {
|
||||||
|
for _, name := range names {
|
||||||
|
if name == "unknown" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
req.Schemas.MustAddSchema(types.APISchema{
|
||||||
|
Schema: &schemas.Schema{
|
||||||
|
ID: name,
|
||||||
|
CollectionMethods: []string{"get"},
|
||||||
|
ResourceMethods: []string{"get"},
|
||||||
|
Attributes: map[string]interface{}{
|
||||||
|
"group": "management.cattle.io",
|
||||||
|
"resource": name,
|
||||||
|
"version": "v1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for res := range test.want {
|
||||||
|
addSchema(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
resource := &types.RawResource{
|
resource := &types.RawResource{
|
||||||
@ -1274,21 +1276,22 @@ func TestFormatterAddsResourcePermissions(t *testing.T) {
|
|||||||
u, ok := resource.APIObject.Object.(*unstructured.Unstructured)
|
u, ok := resource.APIObject.Object.(*unstructured.Unstructured)
|
||||||
require.True(t, ok, "APIObject.Object is not Unstructured")
|
require.True(t, ok, "APIObject.Object is not Unstructured")
|
||||||
|
|
||||||
rawPerms, ok := u.Object["resourcePermissions"]
|
if test.want != nil {
|
||||||
require.True(t, ok, "resourcePermissions field missing")
|
rawPerms, ok := u.Object["resourcePermissions"]
|
||||||
|
require.True(t, ok, "resourcePermissions field missing")
|
||||||
|
|
||||||
permMap, ok := rawPerms.(map[string]map[string]bool)
|
permMap, ok := rawPerms.(map[string]map[string]string)
|
||||||
require.True(t, ok, "resourcePermissions is not map[string]map[string]bool")
|
require.True(t, ok, "resourcePermissions is not map[string]map[string]string")
|
||||||
|
|
||||||
got := map[string]map[string]bool{}
|
got := map[string]map[string]string{}
|
||||||
for res, actionMap := range permMap {
|
for res, actionMap := range permMap {
|
||||||
got[res] = map[string]bool{}
|
got[res] = map[string]string{}
|
||||||
for action, boolVal := range actionMap {
|
for action, boolVal := range actionMap {
|
||||||
got[res][action] = boolVal
|
got[res][action] = boolVal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
require.Equal(t, test.want, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, test.want, got)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user