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:
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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{}
|
||||
|
Reference in New Issue
Block a user