diff --git a/pkg/attributes/attributes.go b/pkg/attributes/attributes.go index f97550e6..41624741 100644 --- a/pkg/attributes/attributes.go +++ b/pkg/attributes/attributes.go @@ -127,6 +127,25 @@ func Access(s *types.APISchema) interface{} { return s.Attributes["access"] } +func AddDisallowMethods(s *types.APISchema, methods ...string) { + data, ok := s.Attributes["disallowMethods"].(map[string]bool) + if !ok { + data = map[string]bool{} + s.Attributes["disallowMethods"] = data + } + for _, method := range methods { + data[method] = true + } +} + +func DisallowMethods(s *types.APISchema) map[string]bool { + data, ok := s.Attributes["disallowMethods"].(map[string]bool) + if !ok { + return nil + } + return data +} + func SetAPIResource(s *types.APISchema, resource v1.APIResource) { SetResource(s, resource.Name) SetVerbs(s, resource.Verbs) diff --git a/pkg/schema/factory.go b/pkg/schema/factory.go index 7e1263ff..0c811cf4 100644 --- a/pkg/schema/factory.go +++ b/pkg/schema/factory.go @@ -97,21 +97,28 @@ func (c *Collection) schemasForSubject(access *accesscontrol.AccessSet) (*types. } } + allowed := func(method string) string { + if attributes.DisallowMethods(s)[method] { + return "blocked-" + method + } + return method + } + s = s.DeepCopy() attributes.SetAccess(s, verbAccess) if verbAccess.AnyVerb("list", "get") { - s.ResourceMethods = append(s.ResourceMethods, http.MethodGet) - s.CollectionMethods = append(s.CollectionMethods, http.MethodGet) + s.ResourceMethods = append(s.ResourceMethods, allowed(http.MethodGet)) + s.CollectionMethods = append(s.CollectionMethods, allowed(http.MethodGet)) } if verbAccess.AnyVerb("delete") { - s.ResourceMethods = append(s.ResourceMethods, http.MethodDelete) + s.ResourceMethods = append(s.ResourceMethods, allowed(http.MethodDelete)) } if verbAccess.AnyVerb("update") { - s.ResourceMethods = append(s.ResourceMethods, http.MethodPut) - s.ResourceMethods = append(s.ResourceMethods, http.MethodPatch) + s.ResourceMethods = append(s.ResourceMethods, allowed(http.MethodPut)) + s.ResourceMethods = append(s.ResourceMethods, allowed(http.MethodPatch)) } if verbAccess.AnyVerb("create") { - s.CollectionMethods = append(s.CollectionMethods, http.MethodPost) + s.CollectionMethods = append(s.CollectionMethods, allowed(http.MethodPost)) } if err := result.AddSchema(*s); err != nil { diff --git a/pkg/server/resources/common/formatter.go b/pkg/server/resources/common/formatter.go index a2c3b19a..2e00cdba 100644 --- a/pkg/server/resources/common/formatter.go +++ b/pkg/server/resources/common/formatter.go @@ -8,6 +8,7 @@ import ( "github.com/rancher/steve/pkg/schemaserver/types" "github.com/rancher/steve/pkg/server/store/proxy" "github.com/rancher/wrangler/pkg/data" + "github.com/rancher/wrangler/pkg/slice" "github.com/rancher/wrangler/pkg/summary" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -38,6 +39,14 @@ func Formatter(request *types.APIRequest, resource *types.RawResource) { resource.Links["update"] = u } + if _, ok := resource.Links["update"]; !ok && slice.ContainsString(resource.Schema.ResourceMethods, "blocked-PUT") { + resource.Links["update"] = "blocked" + } + + if _, ok := resource.Links["remove"]; !ok && slice.ContainsString(resource.Schema.ResourceMethods, "blocked-DELETE") { + resource.Links["remove"] = "blocked" + } + if unstr, ok := resource.APIObject.Object.(*unstructured.Unstructured); ok { summary := summary.Summarize(unstr) data.PutValue(unstr.Object, map[string]interface{}{