1
0
mirror of https://github.com/rancher/norman.git synced 2025-09-01 15:18:20 +00:00

Put in stubs for dynamic access control on schemas

This commit is contained in:
Darren Shepherd
2018-01-16 18:03:35 -07:00
parent f7f989c4e2
commit 245c089cd5
8 changed files with 66 additions and 30 deletions

View File

@@ -195,12 +195,12 @@ func (s *Server) handle(rw http.ResponseWriter, req *http.Request) (*types.APICo
} }
handler = apiRequest.Schema.CreateHandler handler = apiRequest.Schema.CreateHandler
case http.MethodPut: case http.MethodPut:
if !apiRequest.AccessControl.CanUpdate(apiRequest, apiRequest.Schema) { if !apiRequest.AccessControl.CanUpdate(apiRequest, nil, apiRequest.Schema) {
return apiRequest, httperror.NewAPIError(httperror.PermissionDenied, "Can not update "+apiRequest.Schema.Type) return apiRequest, httperror.NewAPIError(httperror.PermissionDenied, "Can not update "+apiRequest.Schema.Type)
} }
handler = apiRequest.Schema.UpdateHandler handler = apiRequest.Schema.UpdateHandler
case http.MethodDelete: case http.MethodDelete:
if !apiRequest.AccessControl.CanDelete(apiRequest, apiRequest.Schema) { if !apiRequest.AccessControl.CanDelete(apiRequest, nil, apiRequest.Schema) {
return apiRequest, httperror.NewAPIError(httperror.PermissionDenied, "Can not delete "+apiRequest.Schema.Type) return apiRequest, httperror.NewAPIError(httperror.PermissionDenied, "Can not delete "+apiRequest.Schema.Type)
} }
handler = apiRequest.Schema.DeleteHandler handler = apiRequest.Schema.DeleteHandler

View File

@@ -127,15 +127,15 @@ func (j *JSONResponseWriter) addLinks(b *builder.Builder, schema *types.Schema,
self := context.URLBuilder.ResourceLink(rawResource) self := context.URLBuilder.ResourceLink(rawResource)
rawResource.Links["self"] = self rawResource.Links["self"] = self
if schema.CanUpdate() { if context.AccessControl.CanUpdate(context, input, schema) {
rawResource.Links["update"] = self rawResource.Links["update"] = self
} }
if schema.CanDelete() { if context.AccessControl.CanDelete(context, input, schema) {
rawResource.Links["remove"] = self rawResource.Links["remove"] = self
} }
for _, backRef := range context.Schemas.References(schema) { for _, backRef := range context.Schemas.References(schema) {
if !backRef.Schema.CanList() { if !backRef.Schema.CanList(context) {
continue continue
} }

View File

@@ -18,11 +18,11 @@ func (*AllAccess) CanList(apiContext *types.APIContext, schema *types.Schema) bo
return slice.ContainsString(schema.CollectionMethods, http.MethodGet) return slice.ContainsString(schema.CollectionMethods, http.MethodGet)
} }
func (*AllAccess) CanUpdate(apiContext *types.APIContext, schema *types.Schema) bool { func (*AllAccess) CanUpdate(apiContext *types.APIContext, obj map[string]interface{}, schema *types.Schema) bool {
return slice.ContainsString(schema.ResourceMethods, http.MethodPut) return slice.ContainsString(schema.ResourceMethods, http.MethodPut)
} }
func (*AllAccess) CanDelete(apiContext *types.APIContext, schema *types.Schema) bool { func (*AllAccess) CanDelete(apiContext *types.APIContext, obj map[string]interface{}, schema *types.Schema) bool {
return slice.ContainsString(schema.ResourceMethods, http.MethodDelete) return slice.ContainsString(schema.ResourceMethods, http.MethodDelete)
} }

View File

@@ -105,7 +105,7 @@ func (c *Store) AddSchemas(ctx context.Context, schemas ...*types.Schema) error
var allSchemas []*types.Schema var allSchemas []*types.Schema
for _, schema := range schemas { for _, schema := range schemas {
if schema.Store != nil || !schema.CanList() { if schema.Store != nil || !schema.CanList(nil) {
continue continue
} }

View File

@@ -2,12 +2,13 @@ package schema
import ( import (
"encoding/json" "encoding/json"
"net/http"
"strings" "strings"
"github.com/rancher/norman/store/empty" "github.com/rancher/norman/store/empty"
"github.com/rancher/norman/types" "github.com/rancher/norman/types"
"github.com/rancher/norman/types/definition" "github.com/rancher/norman/types/definition"
"github.com/rancher/norman/types/slice"
) )
type Store struct { type Store struct {
@@ -23,7 +24,7 @@ func (s *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id stri
if strings.EqualFold(schema.ID, id) { if strings.EqualFold(schema.ID, id) {
schemaData := map[string]interface{}{} schemaData := map[string]interface{}{}
data, err := json.Marshal(schema) data, err := json.Marshal(s.modifyForAccessControl(apiContext, *schema))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -34,6 +35,29 @@ func (s *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id stri
return nil, nil return nil, nil
} }
func (s *Store) modifyForAccessControl(context *types.APIContext, schema types.Schema) *types.Schema {
var resourceMethods []string
if slice.ContainsString(schema.ResourceMethods, http.MethodPut) && schema.CanUpdate(context) {
resourceMethods = append(resourceMethods, http.MethodPut)
}
if slice.ContainsString(schema.ResourceMethods, http.MethodDelete) && schema.CanDelete(context) {
resourceMethods = append(resourceMethods, http.MethodDelete)
}
var collectionMethods []string
if slice.ContainsString(schema.CollectionMethods, http.MethodPost) && schema.CanCreate(context) {
collectionMethods = append(collectionMethods, http.MethodPost)
}
if slice.ContainsString(schema.CollectionMethods, http.MethodGet) && schema.CanList(context) {
collectionMethods = append(collectionMethods, http.MethodGet)
}
schema.ResourceMethods = resourceMethods
schema.CollectionMethods = collectionMethods
return &schema
}
func (s *Store) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) { func (s *Store) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
return nil, nil return nil, nil
} }
@@ -50,8 +74,8 @@ func (s *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *ty
continue continue
} }
if schema.CanList() { if schema.CanList(apiContext) {
schemas = addSchema(schema, schemaMap, schemas, included) schemas = s.addSchema(apiContext, schema, schemaMap, schemas, included)
} }
} }
@@ -63,14 +87,14 @@ func (s *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *ty
return schemaData, json.Unmarshal(data, &schemaData) return schemaData, json.Unmarshal(data, &schemaData)
} }
func addSchema(schema *types.Schema, schemaMap map[string]*types.Schema, schemas []*types.Schema, included map[string]bool) []*types.Schema { func (s *Store) addSchema(apiContext *types.APIContext, schema *types.Schema, schemaMap map[string]*types.Schema, schemas []*types.Schema, included map[string]bool) []*types.Schema {
included[schema.ID] = true included[schema.ID] = true
schemas = traverseAndAdd(schema, schemaMap, schemas, included) schemas = s.traverseAndAdd(apiContext, schema, schemaMap, schemas, included)
schemas = append(schemas, schema) schemas = append(schemas, s.modifyForAccessControl(apiContext, *schema))
return schemas return schemas
} }
func traverseAndAdd(schema *types.Schema, schemaMap map[string]*types.Schema, schemas []*types.Schema, included map[string]bool) []*types.Schema { func (s *Store) traverseAndAdd(apiContext *types.APIContext, schema *types.Schema, schemaMap map[string]*types.Schema, schemas []*types.Schema, included map[string]bool) []*types.Schema {
for _, field := range schema.ResourceFields { for _, field := range schema.ResourceFields {
t := "" t := ""
subType := field.Type subType := field.Type
@@ -80,7 +104,7 @@ func traverseAndAdd(schema *types.Schema, schemaMap map[string]*types.Schema, sc
} }
if refSchema, ok := schemaMap[t]; ok && !included[t] { if refSchema, ok := schemaMap[t]; ok && !included[t] {
schemas = addSchema(refSchema, schemaMap, schemas, included) schemas = s.addSchema(apiContext, refSchema, schemaMap, schemas, included)
} }
} }
@@ -91,7 +115,7 @@ func traverseAndAdd(schema *types.Schema, schemaMap map[string]*types.Schema, sc
} }
if refSchema, ok := schemaMap[t]; ok && !included[t] { if refSchema, ok := schemaMap[t]; ok && !included[t] {
schemas = addSchema(refSchema, schemaMap, schemas, included) schemas = s.addSchema(apiContext, refSchema, schemaMap, schemas, included)
} }
} }
} }

View File

@@ -155,7 +155,7 @@ func (s *Schemas) importType(version *APIVersion, t reflect.Type, overrides ...r
mappers := s.mapper(&schema.Version, schema.ID) mappers := s.mapper(&schema.Version, schema.ID)
if s.DefaultMappers != nil { if s.DefaultMappers != nil {
if schema.CanList() { if schema.CanList(nil) {
mappers = append(s.DefaultMappers(), mappers...) mappers = append(s.DefaultMappers(), mappers...)
} }
} }
@@ -179,7 +179,7 @@ func (s *Schemas) importType(version *APIVersion, t reflect.Type, overrides ...r
mapper := &typeMapper{ mapper := &typeMapper{
Mappers: mappers, Mappers: mappers,
root: schema.CanList(), root: schema.CanList(nil),
} }
if err := mapper.ModifySchema(schema, s); err != nil { if err := mapper.ModifySchema(schema, s); err != nil {

View File

@@ -21,18 +21,30 @@ func (v *APIVersion) Equals(other *APIVersion) bool {
v.Path == other.Path v.Path == other.Path
} }
func (s *Schema) CanList() bool { func (s *Schema) CanList(context *APIContext) bool {
return slice.ContainsString(s.CollectionMethods, http.MethodGet) if context == nil {
return slice.ContainsString(s.CollectionMethods, http.MethodGet)
}
return context.AccessControl.CanList(context, s)
} }
func (s *Schema) CanCreate() bool { func (s *Schema) CanCreate(context *APIContext) bool {
return slice.ContainsString(s.CollectionMethods, http.MethodPost) if context == nil {
return slice.ContainsString(s.CollectionMethods, http.MethodPost)
}
return context.AccessControl.CanCreate(context, s)
} }
func (s *Schema) CanUpdate() bool { func (s *Schema) CanUpdate(context *APIContext) bool {
return slice.ContainsString(s.ResourceMethods, http.MethodPut) if context == nil {
return slice.ContainsString(s.ResourceMethods, http.MethodPut)
}
return context.AccessControl.CanUpdate(context, nil, s)
} }
func (s *Schema) CanDelete() bool { func (s *Schema) CanDelete(context *APIContext) bool {
return slice.ContainsString(s.ResourceMethods, http.MethodDelete) if context == nil {
return slice.ContainsString(s.ResourceMethods, http.MethodDelete)
}
return context.AccessControl.CanDelete(context, nil, s)
} }

View File

@@ -68,8 +68,8 @@ type ResponseWriter interface {
type AccessControl interface { type AccessControl interface {
CanCreate(apiContext *APIContext, schema *Schema) bool CanCreate(apiContext *APIContext, schema *Schema) bool
CanList(apiContext *APIContext, schema *Schema) bool CanList(apiContext *APIContext, schema *Schema) bool
CanUpdate(apiContext *APIContext, schema *Schema) bool CanUpdate(apiContext *APIContext, obj map[string]interface{}, schema *Schema) bool
CanDelete(apiContext *APIContext, schema *Schema) bool CanDelete(apiContext *APIContext, obj map[string]interface{}, schema *Schema) bool
Filter(apiContext *APIContext, obj map[string]interface{}, context map[string]string) map[string]interface{} Filter(apiContext *APIContext, obj map[string]interface{}, context map[string]string) map[string]interface{}
FilterList(apiContext *APIContext, obj []map[string]interface{}, context map[string]string) []map[string]interface{} FilterList(apiContext *APIContext, obj []map[string]interface{}, context map[string]string) []map[string]interface{}