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
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)
}
handler = apiRequest.Schema.UpdateHandler
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)
}
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)
rawResource.Links["self"] = self
if schema.CanUpdate() {
if context.AccessControl.CanUpdate(context, input, schema) {
rawResource.Links["update"] = self
}
if schema.CanDelete() {
if context.AccessControl.CanDelete(context, input, schema) {
rawResource.Links["remove"] = self
}
for _, backRef := range context.Schemas.References(schema) {
if !backRef.Schema.CanList() {
if !backRef.Schema.CanList(context) {
continue
}

View File

@@ -18,11 +18,11 @@ func (*AllAccess) CanList(apiContext *types.APIContext, schema *types.Schema) bo
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)
}
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)
}

View File

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

View File

@@ -2,12 +2,13 @@ package schema
import (
"encoding/json"
"net/http"
"strings"
"github.com/rancher/norman/store/empty"
"github.com/rancher/norman/types"
"github.com/rancher/norman/types/definition"
"github.com/rancher/norman/types/slice"
)
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) {
schemaData := map[string]interface{}{}
data, err := json.Marshal(schema)
data, err := json.Marshal(s.modifyForAccessControl(apiContext, *schema))
if err != nil {
return nil, err
}
@@ -34,6 +35,29 @@ func (s *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id stri
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) {
return nil, nil
}
@@ -50,8 +74,8 @@ func (s *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *ty
continue
}
if schema.CanList() {
schemas = addSchema(schema, schemaMap, schemas, included)
if schema.CanList(apiContext) {
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)
}
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
schemas = traverseAndAdd(schema, schemaMap, schemas, included)
schemas = append(schemas, schema)
schemas = s.traverseAndAdd(apiContext, schema, schemaMap, schemas, included)
schemas = append(schemas, s.modifyForAccessControl(apiContext, *schema))
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 {
t := ""
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] {
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] {
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)
if s.DefaultMappers != nil {
if schema.CanList() {
if schema.CanList(nil) {
mappers = append(s.DefaultMappers(), mappers...)
}
}
@@ -179,7 +179,7 @@ func (s *Schemas) importType(version *APIVersion, t reflect.Type, overrides ...r
mapper := &typeMapper{
Mappers: mappers,
root: schema.CanList(),
root: schema.CanList(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
}
func (s *Schema) CanList() bool {
func (s *Schema) CanList(context *APIContext) bool {
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 {
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 {
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 {
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 {
CanCreate(apiContext *APIContext, schema *Schema) bool
CanList(apiContext *APIContext, schema *Schema) bool
CanUpdate(apiContext *APIContext, schema *Schema) bool
CanDelete(apiContext *APIContext, schema *Schema) bool
CanUpdate(apiContext *APIContext, obj map[string]interface{}, 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{}
FilterList(apiContext *APIContext, obj []map[string]interface{}, context map[string]string) []map[string]interface{}