mirror of
https://github.com/rancher/norman.git
synced 2025-09-06 01:30:20 +00:00
Refactor access control to return error not bool
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/rancher/norman/api/writer"
|
"github.com/rancher/norman/api/writer"
|
||||||
"github.com/rancher/norman/authorization"
|
"github.com/rancher/norman/authorization"
|
||||||
"github.com/rancher/norman/httperror"
|
"github.com/rancher/norman/httperror"
|
||||||
|
ehandler "github.com/rancher/norman/httperror/handler"
|
||||||
"github.com/rancher/norman/parse"
|
"github.com/rancher/norman/parse"
|
||||||
"github.com/rancher/norman/store/wrapper"
|
"github.com/rancher/norman/store/wrapper"
|
||||||
"github.com/rancher/norman/types"
|
"github.com/rancher/norman/types"
|
||||||
@@ -64,7 +65,7 @@ func NewAPIServer() *Server {
|
|||||||
LinkHandler: func(*types.APIContext, types.RequestHandler) error {
|
LinkHandler: func(*types.APIContext, types.RequestHandler) error {
|
||||||
return httperror.NewAPIError(httperror.NotFound, "Link not found")
|
return httperror.NewAPIError(httperror.NotFound, "Link not found")
|
||||||
},
|
},
|
||||||
ErrorHandler: httperror.ErrorHandler,
|
ErrorHandler: ehandler.ErrorHandler,
|
||||||
},
|
},
|
||||||
StoreWrapper: wrapper.Wrap,
|
StoreWrapper: wrapper.Wrap,
|
||||||
URLParser: parse.DefaultURLParser,
|
URLParser: parse.DefaultURLParser,
|
||||||
@@ -187,31 +188,31 @@ func (s *Server) handle(rw http.ResponseWriter, req *http.Request) (*types.APICo
|
|||||||
switch apiRequest.Method {
|
switch apiRequest.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
if apiRequest.ID == "" {
|
if apiRequest.ID == "" {
|
||||||
if !apiRequest.AccessControl.CanList(apiRequest, apiRequest.Schema) {
|
if err := apiRequest.AccessControl.CanList(apiRequest, apiRequest.Schema); err != nil {
|
||||||
return apiRequest, httperror.NewAPIError(httperror.PermissionDenied, "Can not list "+apiRequest.Schema.ID)
|
return apiRequest, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !apiRequest.AccessControl.CanGet(apiRequest, apiRequest.Schema) {
|
if err := apiRequest.AccessControl.CanGet(apiRequest, apiRequest.Schema); err != nil {
|
||||||
return apiRequest, httperror.NewAPIError(httperror.PermissionDenied, "Can not get "+apiRequest.Schema.ID)
|
return apiRequest, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handler = apiRequest.Schema.ListHandler
|
handler = apiRequest.Schema.ListHandler
|
||||||
nextHandler = s.Defaults.ListHandler
|
nextHandler = s.Defaults.ListHandler
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
if !apiRequest.AccessControl.CanCreate(apiRequest, apiRequest.Schema) {
|
if err := apiRequest.AccessControl.CanCreate(apiRequest, apiRequest.Schema); err != nil {
|
||||||
return apiRequest, httperror.NewAPIError(httperror.PermissionDenied, "Can not create "+apiRequest.Schema.ID)
|
return apiRequest, err
|
||||||
}
|
}
|
||||||
handler = apiRequest.Schema.CreateHandler
|
handler = apiRequest.Schema.CreateHandler
|
||||||
nextHandler = s.Defaults.CreateHandler
|
nextHandler = s.Defaults.CreateHandler
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
if !apiRequest.AccessControl.CanUpdate(apiRequest, nil, apiRequest.Schema) {
|
if err := apiRequest.AccessControl.CanUpdate(apiRequest, nil, apiRequest.Schema); err != nil {
|
||||||
return apiRequest, httperror.NewAPIError(httperror.PermissionDenied, "Can not update "+apiRequest.Schema.ID)
|
return apiRequest, err
|
||||||
}
|
}
|
||||||
handler = apiRequest.Schema.UpdateHandler
|
handler = apiRequest.Schema.UpdateHandler
|
||||||
nextHandler = s.Defaults.UpdateHandler
|
nextHandler = s.Defaults.UpdateHandler
|
||||||
case http.MethodDelete:
|
case http.MethodDelete:
|
||||||
if !apiRequest.AccessControl.CanDelete(apiRequest, nil, apiRequest.Schema) {
|
if err := apiRequest.AccessControl.CanDelete(apiRequest, nil, apiRequest.Schema); err != nil {
|
||||||
return apiRequest, httperror.NewAPIError(httperror.PermissionDenied, "Can not delete "+apiRequest.Schema.ID)
|
return apiRequest, err
|
||||||
}
|
}
|
||||||
handler = apiRequest.Schema.DeleteHandler
|
handler = apiRequest.Schema.DeleteHandler
|
||||||
nextHandler = s.Defaults.DeleteHandler
|
nextHandler = s.Defaults.DeleteHandler
|
||||||
|
@@ -140,16 +140,16 @@ 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 context.AccessControl.CanUpdate(context, input, schema) {
|
if context.AccessControl.CanUpdate(context, input, schema) == nil {
|
||||||
rawResource.Links["update"] = self
|
rawResource.Links["update"] = self
|
||||||
}
|
}
|
||||||
if context.AccessControl.CanDelete(context, input, schema) {
|
if context.AccessControl.CanDelete(context, input, schema) == nil {
|
||||||
rawResource.Links["remove"] = self
|
rawResource.Links["remove"] = self
|
||||||
}
|
}
|
||||||
|
|
||||||
subContextVersion := context.Schemas.SubContextVersionForSchema(schema)
|
subContextVersion := context.Schemas.SubContextVersionForSchema(schema)
|
||||||
for _, backRef := range context.Schemas.References(schema) {
|
for _, backRef := range context.Schemas.References(schema) {
|
||||||
if !backRef.Schema.CanList(context) {
|
if backRef.Schema.CanList(context) != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ func (j *JSONResponseWriter) addLinks(b *builder.Builder, schema *types.Schema,
|
|||||||
|
|
||||||
if subContextVersion != nil {
|
if subContextVersion != nil {
|
||||||
for _, subSchema := range context.Schemas.SchemasForVersion(*subContextVersion) {
|
for _, subSchema := range context.Schemas.SchemasForVersion(*subContextVersion) {
|
||||||
if subSchema.CanList(context) {
|
if subSchema.CanList(context) == nil {
|
||||||
rawResource.Links[subSchema.PluralName] = context.URLBuilder.SubContextCollection(schema, rawResource.ID, subSchema)
|
rawResource.Links[subSchema.PluralName] = context.URLBuilder.SubContextCollection(schema, rawResource.ID, subSchema)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,7 +184,7 @@ func newCollection(apiContext *types.APIContext) *types.GenericCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if apiContext.Method == http.MethodGet {
|
if apiContext.Method == http.MethodGet {
|
||||||
if apiContext.AccessControl.CanCreate(apiContext, apiContext.Schema) {
|
if apiContext.AccessControl.CanCreate(apiContext, apiContext.Schema) == nil {
|
||||||
result.CreateTypes[apiContext.Schema.ID] = apiContext.URLBuilder.Collection(apiContext.Schema, apiContext.Version)
|
result.CreateTypes[apiContext.Schema.ID] = apiContext.URLBuilder.Collection(apiContext.Schema, apiContext.Version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package authorization
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/rancher/norman/httperror"
|
||||||
"github.com/rancher/norman/types"
|
"github.com/rancher/norman/types"
|
||||||
"github.com/rancher/norman/types/slice"
|
"github.com/rancher/norman/types/slice"
|
||||||
)
|
)
|
||||||
@@ -10,24 +11,39 @@ import (
|
|||||||
type AllAccess struct {
|
type AllAccess struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*AllAccess) CanCreate(apiContext *types.APIContext, schema *types.Schema) bool {
|
func (*AllAccess) CanCreate(apiContext *types.APIContext, schema *types.Schema) error {
|
||||||
return slice.ContainsString(schema.CollectionMethods, http.MethodPost)
|
if slice.ContainsString(schema.CollectionMethods, http.MethodPost) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not create "+schema.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*AllAccess) CanGet(apiContext *types.APIContext, schema *types.Schema) bool {
|
func (*AllAccess) CanGet(apiContext *types.APIContext, schema *types.Schema) error {
|
||||||
return slice.ContainsString(schema.ResourceMethods, http.MethodGet)
|
if slice.ContainsString(schema.ResourceMethods, http.MethodGet) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not get "+schema.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*AllAccess) CanList(apiContext *types.APIContext, schema *types.Schema) bool {
|
func (*AllAccess) CanList(apiContext *types.APIContext, schema *types.Schema) error {
|
||||||
return slice.ContainsString(schema.CollectionMethods, http.MethodGet)
|
if slice.ContainsString(schema.CollectionMethods, http.MethodGet) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not list "+schema.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*AllAccess) CanUpdate(apiContext *types.APIContext, obj map[string]interface{}, schema *types.Schema) bool {
|
func (*AllAccess) CanUpdate(apiContext *types.APIContext, obj map[string]interface{}, schema *types.Schema) error {
|
||||||
return slice.ContainsString(schema.ResourceMethods, http.MethodPut)
|
if slice.ContainsString(schema.ResourceMethods, http.MethodPut) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not update "+schema.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*AllAccess) CanDelete(apiContext *types.APIContext, obj map[string]interface{}, schema *types.Schema) bool {
|
func (*AllAccess) CanDelete(apiContext *types.APIContext, obj map[string]interface{}, schema *types.Schema) error {
|
||||||
return slice.ContainsString(schema.ResourceMethods, http.MethodDelete)
|
if slice.ContainsString(schema.ResourceMethods, http.MethodDelete) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not delete "+schema.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*AllAccess) Filter(apiContext *types.APIContext, schema *types.Schema, obj map[string]interface{}, context map[string]string) map[string]interface{} {
|
func (*AllAccess) Filter(apiContext *types.APIContext, schema *types.Schema, obj map[string]interface{}, context map[string]string) map[string]interface{} {
|
||||||
|
@@ -34,40 +34,40 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ErrorCode struct {
|
type ErrorCode struct {
|
||||||
code string
|
Code string
|
||||||
Status int
|
Status int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e ErrorCode) String() string {
|
func (e ErrorCode) String() string {
|
||||||
return fmt.Sprintf("%s %d", e.code, e.Status)
|
return fmt.Sprintf("%s %d", e.Code, e.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
type APIError struct {
|
type APIError struct {
|
||||||
code ErrorCode
|
Code ErrorCode
|
||||||
message string
|
Message string
|
||||||
Cause error
|
Cause error
|
||||||
fieldName string
|
FieldName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAPIErrorLong(status int, code, message string) error {
|
func NewAPIErrorLong(status int, code, message string) error {
|
||||||
return NewAPIError(ErrorCode{
|
return NewAPIError(ErrorCode{
|
||||||
code: code,
|
Code: code,
|
||||||
Status: status,
|
Status: status,
|
||||||
}, message)
|
}, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAPIError(code ErrorCode, message string) error {
|
func NewAPIError(code ErrorCode, message string) error {
|
||||||
return &APIError{
|
return &APIError{
|
||||||
code: code,
|
Code: code,
|
||||||
message: message,
|
Message: message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFieldAPIError(code ErrorCode, fieldName, message string) error {
|
func NewFieldAPIError(code ErrorCode, fieldName, message string) error {
|
||||||
return &APIError{
|
return &APIError{
|
||||||
code: code,
|
Code: code,
|
||||||
message: message,
|
Message: message,
|
||||||
fieldName: fieldName,
|
FieldName: fieldName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,9 +76,9 @@ func NewFieldAPIError(code ErrorCode, fieldName, message string) error {
|
|||||||
func WrapFieldAPIError(err error, code ErrorCode, fieldName, message string) error {
|
func WrapFieldAPIError(err error, code ErrorCode, fieldName, message string) error {
|
||||||
return &APIError{
|
return &APIError{
|
||||||
Cause: err,
|
Cause: err,
|
||||||
code: code,
|
Code: code,
|
||||||
message: message,
|
Message: message,
|
||||||
fieldName: fieldName,
|
FieldName: fieldName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,17 +86,17 @@ func WrapFieldAPIError(err error, code ErrorCode, fieldName, message string) err
|
|||||||
// err WILL NOT be in the API response
|
// err WILL NOT be in the API response
|
||||||
func WrapAPIError(err error, code ErrorCode, message string) error {
|
func WrapAPIError(err error, code ErrorCode, message string) error {
|
||||||
return &APIError{
|
return &APIError{
|
||||||
code: code,
|
Code: code,
|
||||||
message: message,
|
Message: message,
|
||||||
Cause: err,
|
Cause: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APIError) Error() string {
|
func (a *APIError) Error() string {
|
||||||
if a.fieldName != "" {
|
if a.FieldName != "" {
|
||||||
return fmt.Sprintf("%s=%s: %s", a.fieldName, a.code, a.message)
|
return fmt.Sprintf("%s=%s: %s", a.FieldName, a.Code, a.Message)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s: %s", a.code, a.message)
|
return fmt.Sprintf("%s: %s", a.Code, a.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsAPIError(err error) bool {
|
func IsAPIError(err error) bool {
|
||||||
@@ -106,7 +106,7 @@ func IsAPIError(err error) bool {
|
|||||||
|
|
||||||
func IsConflict(err error) bool {
|
func IsConflict(err error) bool {
|
||||||
if apiError, ok := err.(*APIError); ok {
|
if apiError, ok := err.(*APIError); ok {
|
||||||
return apiError.code.Status == 409
|
return apiError.Code.Status == 409
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@@ -1,40 +0,0 @@
|
|||||||
package httperror
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/rancher/norman/types"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ErrorHandler(request *types.APIContext, err error) {
|
|
||||||
var error *APIError
|
|
||||||
if apiError, ok := err.(*APIError); ok {
|
|
||||||
if apiError.Cause != nil {
|
|
||||||
logrus.Errorf("API error response %v for %v %v. Cause: %v", apiError.code.Status, request.Request.Method,
|
|
||||||
request.Request.RequestURI, apiError.Cause)
|
|
||||||
}
|
|
||||||
error = apiError
|
|
||||||
} else {
|
|
||||||
logrus.Errorf("Unknown error: %v", err)
|
|
||||||
error = &APIError{
|
|
||||||
code: ServerError,
|
|
||||||
message: err.Error(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data := toError(error)
|
|
||||||
request.WriteResponse(error.code.Status, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func toError(apiError *APIError) map[string]interface{} {
|
|
||||||
e := map[string]interface{}{
|
|
||||||
"type": "/meta/schemas/error",
|
|
||||||
"status": apiError.code.Status,
|
|
||||||
"code": apiError.code.code,
|
|
||||||
"message": apiError.message,
|
|
||||||
}
|
|
||||||
if apiError.fieldName != "" {
|
|
||||||
e["fieldName"] = apiError.fieldName
|
|
||||||
}
|
|
||||||
|
|
||||||
return e
|
|
||||||
}
|
|
41
httperror/handler/handler.go
Normal file
41
httperror/handler/handler.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/rancher/norman/httperror"
|
||||||
|
"github.com/rancher/norman/types"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ErrorHandler(request *types.APIContext, err error) {
|
||||||
|
var error *httperror.APIError
|
||||||
|
if apiError, ok := err.(*httperror.APIError); ok {
|
||||||
|
if apiError.Cause != nil {
|
||||||
|
logrus.Errorf("API error response %v for %v %v. Cause: %v", apiError.Code.Status, request.Request.Method,
|
||||||
|
request.Request.RequestURI, apiError.Cause)
|
||||||
|
}
|
||||||
|
error = apiError
|
||||||
|
} else {
|
||||||
|
logrus.Errorf("Unknown error: %v", err)
|
||||||
|
error = &httperror.APIError{
|
||||||
|
Code: httperror.ServerError,
|
||||||
|
Message: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data := toError(error)
|
||||||
|
request.WriteResponse(error.Code.Status, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toError(apiError *httperror.APIError) map[string]interface{} {
|
||||||
|
e := map[string]interface{}{
|
||||||
|
"type": "/meta/schemas/error",
|
||||||
|
"status": apiError.Code.Status,
|
||||||
|
"code": apiError.Code.Code,
|
||||||
|
"message": apiError.Message,
|
||||||
|
}
|
||||||
|
if apiError.FieldName != "" {
|
||||||
|
e["fieldName"] = apiError.FieldName
|
||||||
|
}
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
@@ -137,6 +137,8 @@ func (b *Builder) checkDefaultAndRequired(schema *types.Schema, input map[string
|
|||||||
|
|
||||||
if op.IsList() && fieldMatchesOp(field, List) && definition.IsReferenceType(field.Type) && !hasKey {
|
if op.IsList() && fieldMatchesOp(field, List) && definition.IsReferenceType(field.Type) && !hasKey {
|
||||||
result[fieldName] = nil
|
result[fieldName] = nil
|
||||||
|
} else if op.IsList() && fieldMatchesOp(field, List) && !hasKey && field.Default != nil {
|
||||||
|
result[fieldName] = field.Default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,21 +38,21 @@ func (s *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id stri
|
|||||||
|
|
||||||
func (s *Store) modifyForAccessControl(context *types.APIContext, schema types.Schema) *types.Schema {
|
func (s *Store) modifyForAccessControl(context *types.APIContext, schema types.Schema) *types.Schema {
|
||||||
var resourceMethods []string
|
var resourceMethods []string
|
||||||
if slice.ContainsString(schema.ResourceMethods, http.MethodPut) && schema.CanUpdate(context) {
|
if slice.ContainsString(schema.ResourceMethods, http.MethodPut) && schema.CanUpdate(context) == nil {
|
||||||
resourceMethods = append(resourceMethods, http.MethodPut)
|
resourceMethods = append(resourceMethods, http.MethodPut)
|
||||||
}
|
}
|
||||||
if slice.ContainsString(schema.ResourceMethods, http.MethodDelete) && schema.CanDelete(context) {
|
if slice.ContainsString(schema.ResourceMethods, http.MethodDelete) && schema.CanDelete(context) == nil {
|
||||||
resourceMethods = append(resourceMethods, http.MethodDelete)
|
resourceMethods = append(resourceMethods, http.MethodDelete)
|
||||||
}
|
}
|
||||||
if slice.ContainsString(schema.ResourceMethods, http.MethodGet) && schema.CanGet(context) {
|
if slice.ContainsString(schema.ResourceMethods, http.MethodGet) && schema.CanGet(context) == nil {
|
||||||
resourceMethods = append(resourceMethods, http.MethodGet)
|
resourceMethods = append(resourceMethods, http.MethodGet)
|
||||||
}
|
}
|
||||||
|
|
||||||
var collectionMethods []string
|
var collectionMethods []string
|
||||||
if slice.ContainsString(schema.CollectionMethods, http.MethodPost) && schema.CanCreate(context) {
|
if slice.ContainsString(schema.CollectionMethods, http.MethodPost) && schema.CanCreate(context) == nil {
|
||||||
collectionMethods = append(collectionMethods, http.MethodPost)
|
collectionMethods = append(collectionMethods, http.MethodPost)
|
||||||
}
|
}
|
||||||
if slice.ContainsString(schema.CollectionMethods, http.MethodGet) && schema.CanList(context) {
|
if slice.ContainsString(schema.CollectionMethods, http.MethodGet) && schema.CanList(context) == nil {
|
||||||
collectionMethods = append(collectionMethods, http.MethodGet)
|
collectionMethods = append(collectionMethods, http.MethodGet)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ func (s *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *ty
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if schema.CanList(apiContext) || schema.CanGet(apiContext) {
|
if schema.CanList(apiContext) == nil || schema.CanGet(apiContext) == nil {
|
||||||
schemas = s.addSchema(apiContext, schema, schemaMap, schemas, included)
|
schemas = s.addSchema(apiContext, schema, schemaMap, schemas, included)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -151,7 +151,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(nil) {
|
if schema.CanList(nil) == nil {
|
||||||
mappers = append(s.DefaultMappers(), mappers...)
|
mappers = append(s.DefaultMappers(), mappers...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ func (s *Schemas) importType(version *APIVersion, t reflect.Type, overrides ...r
|
|||||||
|
|
||||||
mapper := &typeMapper{
|
mapper := &typeMapper{
|
||||||
Mappers: mappers,
|
Mappers: mappers,
|
||||||
root: schema.CanList(nil),
|
root: schema.CanList(nil) == nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mapper.ModifySchema(schema, s); err != nil {
|
if err := mapper.ModifySchema(schema, s); err != nil {
|
||||||
|
@@ -3,6 +3,7 @@ package types
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/rancher/norman/httperror"
|
||||||
"github.com/rancher/norman/types/slice"
|
"github.com/rancher/norman/types/slice"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,37 +22,52 @@ func (v *APIVersion) Equals(other *APIVersion) bool {
|
|||||||
v.Path == other.Path
|
v.Path == other.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Schema) CanList(context *APIContext) bool {
|
func (s *Schema) CanList(context *APIContext) error {
|
||||||
if context == nil {
|
if context == nil {
|
||||||
return slice.ContainsString(s.CollectionMethods, http.MethodGet)
|
if slice.ContainsString(s.CollectionMethods, http.MethodGet) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not list "+s.ID)
|
||||||
}
|
}
|
||||||
return context.AccessControl.CanList(context, s)
|
return context.AccessControl.CanList(context, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Schema) CanGet(context *APIContext) bool {
|
func (s *Schema) CanGet(context *APIContext) error {
|
||||||
if context == nil {
|
if context == nil {
|
||||||
return slice.ContainsString(s.ResourceMethods, http.MethodGet)
|
if slice.ContainsString(s.ResourceMethods, http.MethodGet) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not get "+s.ID)
|
||||||
}
|
}
|
||||||
return context.AccessControl.CanGet(context, s)
|
return context.AccessControl.CanGet(context, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Schema) CanCreate(context *APIContext) bool {
|
func (s *Schema) CanCreate(context *APIContext) error {
|
||||||
if context == nil {
|
if context == nil {
|
||||||
return slice.ContainsString(s.CollectionMethods, http.MethodPost)
|
if slice.ContainsString(s.CollectionMethods, http.MethodPost) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not create "+s.ID)
|
||||||
}
|
}
|
||||||
return context.AccessControl.CanCreate(context, s)
|
return context.AccessControl.CanCreate(context, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Schema) CanUpdate(context *APIContext) bool {
|
func (s *Schema) CanUpdate(context *APIContext) error {
|
||||||
if context == nil {
|
if context == nil {
|
||||||
return slice.ContainsString(s.ResourceMethods, http.MethodPut)
|
if slice.ContainsString(s.ResourceMethods, http.MethodPut) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not update "+s.ID)
|
||||||
}
|
}
|
||||||
return context.AccessControl.CanUpdate(context, nil, s)
|
return context.AccessControl.CanUpdate(context, nil, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Schema) CanDelete(context *APIContext) bool {
|
func (s *Schema) CanDelete(context *APIContext) error {
|
||||||
if context == nil {
|
if context == nil {
|
||||||
return slice.ContainsString(s.ResourceMethods, http.MethodDelete)
|
if slice.ContainsString(s.ResourceMethods, http.MethodDelete) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return httperror.NewAPIError(httperror.PermissionDenied, "can not delete "+s.ID)
|
||||||
}
|
}
|
||||||
return context.AccessControl.CanDelete(context, nil, s)
|
return context.AccessControl.CanDelete(context, nil, s)
|
||||||
}
|
}
|
||||||
|
@@ -69,11 +69,11 @@ type ResponseWriter interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AccessControl interface {
|
type AccessControl interface {
|
||||||
CanCreate(apiContext *APIContext, schema *Schema) bool
|
CanCreate(apiContext *APIContext, schema *Schema) error
|
||||||
CanList(apiContext *APIContext, schema *Schema) bool
|
CanList(apiContext *APIContext, schema *Schema) error
|
||||||
CanGet(apiContext *APIContext, schema *Schema) bool
|
CanGet(apiContext *APIContext, schema *Schema) error
|
||||||
CanUpdate(apiContext *APIContext, obj map[string]interface{}, schema *Schema) bool
|
CanUpdate(apiContext *APIContext, obj map[string]interface{}, schema *Schema) error
|
||||||
CanDelete(apiContext *APIContext, obj map[string]interface{}, schema *Schema) bool
|
CanDelete(apiContext *APIContext, obj map[string]interface{}, schema *Schema) error
|
||||||
|
|
||||||
Filter(apiContext *APIContext, schema *Schema, obj map[string]interface{}, context map[string]string) map[string]interface{}
|
Filter(apiContext *APIContext, schema *Schema, obj map[string]interface{}, context map[string]string) map[string]interface{}
|
||||||
FilterList(apiContext *APIContext, schema *Schema, obj []map[string]interface{}, context map[string]string) []map[string]interface{}
|
FilterList(apiContext *APIContext, schema *Schema, obj []map[string]interface{}, context map[string]string) []map[string]interface{}
|
||||||
|
Reference in New Issue
Block a user