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