3
0

Apigw tweaks

- Add system/apigw tests
- Removes permissions from APIGw filters from each level
This commit is contained in:
Vivek Patel
2021-09-17 17:42:25 +05:30
committed by Denis Arh
parent 74d7c6c7a2
commit d2bff9e3fd
29 changed files with 699 additions and 525 deletions

View File

@@ -1,8 +0,0 @@
rbac:
operations:
read:
description: Read API Gateway filter
update:
description: Update API Gateway filter
delete:
description: Delete API Gateway filter

View File

@@ -60,10 +60,5 @@ rbac:
apigw-routes.search:
description: List search or filter API gateway routes
apigw-filter.create:
description: Add API gateway filter to route
apigw-filters.search:
description: List, search or filter API gateway filters
resource-translations.manage:
description: List, search, create, or update resource translations

View File

@@ -113,23 +113,23 @@ func NewDefaultJsonResponse() (e *defaultJsonResponse) {
return
}
func (h defaultJsonResponse) New() types.Handler {
func (j defaultJsonResponse) New() types.Handler {
return NewDefaultJsonResponse()
}
func (h defaultJsonResponse) String() string {
return fmt.Sprintf("apigw filter %s (%s)", h.Name, h.Label)
func (j defaultJsonResponse) String() string {
return fmt.Sprintf("apigw filter %s (%s)", j.Name, j.Label)
}
func (h defaultJsonResponse) Meta() types.FilterMeta {
return h.FilterMeta
func (j defaultJsonResponse) Meta() types.FilterMeta {
return j.FilterMeta
}
func (f *defaultJsonResponse) Merge(params []byte) (h types.Handler, err error) {
return f, err
func (j *defaultJsonResponse) Merge(params []byte) (h types.Handler, err error) {
return j, err
}
func (h defaultJsonResponse) Handler() types.HandlerFunc {
func (j defaultJsonResponse) Handler() types.HandlerFunc {
return func(rw http.ResponseWriter, r *http.Request) error {
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(http.StatusAccepted)

View File

@@ -68,21 +68,21 @@ func (h header) Meta() types.FilterMeta {
return h.FilterMeta
}
func (v *header) Merge(params []byte) (types.Handler, error) {
err := json.NewDecoder(bytes.NewBuffer(params)).Decode(&v.params)
func (h *header) Merge(params []byte) (types.Handler, error) {
err := json.NewDecoder(bytes.NewBuffer(params)).Decode(&h.params)
if err != nil {
return nil, err
}
parser := expr.NewParser()
v.eval, err = parser.Parse(v.params.Expr)
h.eval, err = parser.Parse(h.params.Expr)
if err != nil {
return nil, fmt.Errorf("could not validate origin parameters: %s", err)
}
return v, err
return h, err
}
func (h header) Handler() types.HandlerFunc {
@@ -137,36 +137,36 @@ func NewQueryParam() (v *queryParam) {
return
}
func (h queryParam) New() types.Handler {
func (qp queryParam) New() types.Handler {
return NewQueryParam()
}
func (h queryParam) String() string {
return fmt.Sprintf("apigw filter %s (%s)", h.Name, h.Label)
func (qp queryParam) String() string {
return fmt.Sprintf("apigw filter %s (%s)", qp.Name, qp.Label)
}
func (h queryParam) Meta() types.FilterMeta {
return h.FilterMeta
func (qp queryParam) Meta() types.FilterMeta {
return qp.FilterMeta
}
func (v *queryParam) Merge(params []byte) (types.Handler, error) {
err := json.NewDecoder(bytes.NewBuffer(params)).Decode(&v.params)
func (qp *queryParam) Merge(params []byte) (types.Handler, error) {
err := json.NewDecoder(bytes.NewBuffer(params)).Decode(&qp.params)
if err != nil {
return nil, err
}
parser := expr.NewParser()
v.eval, err = parser.Parse(v.params.Expr)
qp.eval, err = parser.Parse(qp.params.Expr)
if err != nil {
return nil, fmt.Errorf("could not validate query parameters: %s", err)
}
return v, err
return qp, err
}
func (h *queryParam) Handler() types.HandlerFunc {
func (qp *queryParam) Handler() types.HandlerFunc {
return func(rw http.ResponseWriter, r *http.Request) error {
var (
ctx = r.Context()
@@ -183,17 +183,17 @@ func (h *queryParam) Handler() types.HandlerFunc {
out, err := expr.NewVars(vv)
if err != nil {
return pe.Internal("could not validate query parameters: (%v) (%s)", err, h.params.Expr)
return pe.Internal("could not validate query parameters: (%v) (%s)", err, qp.params.Expr)
}
b, err := h.eval.Test(ctx, out)
b, err := qp.eval.Test(ctx, out)
if err != nil {
return pe.InvalidData("could not validate query parameters: (%v) (%s)", err, h.params.Expr)
return pe.InvalidData("could not validate query parameters: (%v) (%s)", err, qp.params.Expr)
}
if !b {
return pe.InvalidData("could not validate query parameters: (%v) (%s)", errors.New("validation failed"), h.params.Expr)
return pe.InvalidData("could not validate query parameters: (%v) (%s)", errors.New("validation failed"), qp.params.Expr)
}
return nil

View File

@@ -77,10 +77,10 @@ func (h workflow) Meta() types.FilterMeta {
return h.FilterMeta
}
func (f *workflow) Merge(params []byte) (types.Handler, error) {
err := json.NewDecoder(bytes.NewBuffer(params)).Decode(&f.params)
func (h *workflow) Merge(params []byte) (types.Handler, error) {
err := json.NewDecoder(bytes.NewBuffer(params)).Decode(&h.params)
return f, err
return h, err
}
func (h workflow) Handler() types.HandlerFunc {

View File

@@ -79,21 +79,21 @@ func (h proxy) Meta() types.FilterMeta {
return h.FilterMeta
}
func (f *proxy) Merge(params []byte) (types.Handler, error) {
err := json.NewDecoder(bytes.NewBuffer(params)).Decode(&f.params)
func (h *proxy) Merge(params []byte) (types.Handler, error) {
err := json.NewDecoder(bytes.NewBuffer(params)).Decode(&h.params)
if err != nil {
return nil, err
}
// get the auth mechanism
f.a, err = NewProxyAuthServicer(f.c, f.params.Auth, f.s)
h.a, err = NewProxyAuthServicer(h.c, h.params.Auth, h.s)
if err != nil {
return nil, fmt.Errorf("could not load auth servicer for proxying: %s", err)
}
return f, err
return h, err
}
func (h proxy) Handler() types.HandlerFunc {

View File

@@ -80,21 +80,21 @@ type (
func NewProxyAuthServicer(c *http.Client, p ProxyAuthParams, s types.SecureStorager) (ProxyAuthServicer, error) {
switch p.Type {
case proxyAuthTypeHeader:
return NewProxyAuthHeader(p)
return newProxyAuthHeader(p)
case proxyAuthTypeQuery:
return NewProxyAuthQuery(p)
return newProxyAuthQuery(p)
case proxyAuthTypeBasic:
return NewProxyAuthBasic(p)
return newProxyAuthBasic(p)
case proxyAuthTypeOauth2:
return NewProxyAuthOauth2(p, c, s)
return newProxyAuthOauth2(p, c, s)
case proxyAuthTypeJWT:
return NewProxyAuthJWT(p)
return newProxyAuthJWT(p)
default:
return proxyAuthServicerNoop{}, nil
}
}
func NewProxyAuthHeader(p ProxyAuthParams) (s proxyAuthServicerHeader, err error) {
func newProxyAuthHeader(p ProxyAuthParams) (s proxyAuthServicerHeader, err error) {
s = proxyAuthServicerHeader{
params: p.Params,
}
@@ -102,7 +102,7 @@ func NewProxyAuthHeader(p ProxyAuthParams) (s proxyAuthServicerHeader, err error
return
}
func NewProxyAuthQuery(p ProxyAuthParams) (s proxyAuthServicerQuery, err error) {
func newProxyAuthQuery(p ProxyAuthParams) (s proxyAuthServicerQuery, err error) {
s = proxyAuthServicerQuery{
params: p.Params,
}
@@ -110,7 +110,7 @@ func NewProxyAuthQuery(p ProxyAuthParams) (s proxyAuthServicerQuery, err error)
return
}
func NewProxyAuthBasic(p ProxyAuthParams) (s proxyAuthServicerBasic, err error) {
func newProxyAuthBasic(p ProxyAuthParams) (s proxyAuthServicerBasic, err error) {
var (
ok bool
user, pass string
@@ -136,7 +136,7 @@ func NewProxyAuthBasic(p ProxyAuthParams) (s proxyAuthServicerBasic, err error)
return
}
func NewProxyAuthOauth2(p ProxyAuthParams, c *http.Client, s types.SecureStorager) (ss proxyAuthServicerOauth2, err error) {
func newProxyAuthOauth2(p ProxyAuthParams, c *http.Client, s types.SecureStorager) (ss proxyAuthServicerOauth2, err error) {
var (
u *url.URL
ok bool
@@ -182,7 +182,7 @@ func NewProxyAuthOauth2(p ProxyAuthParams, c *http.Client, s types.SecureStorage
return
}
func NewProxyAuthJWT(p ProxyAuthParams) (ss proxyAuthServicerJWT, err error) {
func newProxyAuthJWT(p ProxyAuthParams) (ss proxyAuthServicerJWT, err error) {
var (
ok bool
jwt string

View File

@@ -175,7 +175,8 @@ func Test_proxy(t *testing.T) {
}
proxy := New(zap.NewNop(), c, struct{}{})
proxy.Merge([]byte(tc.params))
_, err := proxy.Merge([]byte(tc.params))
req.NoError(err)
scope := &types.Scp{
"opts": options.Apigw(),
@@ -185,7 +186,7 @@ func Test_proxy(t *testing.T) {
rq = rq.WithContext(ctx)
hn := proxy.Handler()
err := hn(rc, rq)
err = hn(rc, rq)
if tc.err != "" {
req.EqualError(err, tc.err)

View File

@@ -50,7 +50,7 @@ func (pp *Pl) Error() types.ErrorHandlerFunc {
return pp.err
}
// add error handler
// ErrorHandler adds error handler
func (pp *Pl) ErrorHandler(ff types.ErrorHandlerFunc) {
pp.err = ff
}

View File

@@ -166,7 +166,7 @@ func (s *apigw) Router(r chi.Router) {
}()
}
// init all the routes
// Init all the routes
func (s *apigw) Init(ctx context.Context, route ...*route) {
var (
defaultPostFilter types.Handler
@@ -240,7 +240,7 @@ func (s *apigw) Init(ctx context.Context, route ...*route) {
r.handler = pipe.Handler()
r.errHandler = pipe.Error()
log.Debug("successfuly registered route")
log.Debug("successfully registered route")
}
}

View File

@@ -7,7 +7,6 @@ package resource
//
// Definitions file that controls how this file is generated:
// - system.apigw-filter.yaml
// - system.apigw-route.yaml
// - system.application.yaml
// - system.auth-client.yaml
@@ -21,19 +20,6 @@ import (
"github.com/cortezaproject/corteza-server/system/types"
)
// SystemApigwFilterRbacReferences generates RBAC references
//
// Resources with "envoy: false" are skipped
//
// This function is auto-generated
func SystemApigwFilterRbacReferences(apigwFilter string) (res *Ref, pp []*Ref, err error) {
if apigwFilter != "*" {
res = &Ref{ResourceType: types.ApigwFilterResourceType, Identifiers: MakeIdentifiers(apigwFilter)}
}
return
}
// SystemApigwRouteRbacReferences generates RBAC references
//
// Resources with "envoy: false" are skipped

View File

@@ -16,7 +16,6 @@ package resource
// - compose.page.yaml
// - compose.record.yaml
// - compose.yaml
// - system.apigw-filter.yaml
// - system.apigw-route.yaml
// - system.application.yaml
// - system.auth-client.yaml
@@ -171,16 +170,6 @@ func ParseRule(res string) (string, *Ref, []*Ref, error) {
// Component resource, no path
return composeTypes.ComponentResourceType, nil, nil, nil
case systemTypes.ApigwFilterResourceType:
if len(path) != 1 {
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
}
ref, pp, err := SystemApigwFilterRbacReferences(
// apigwFilter
path[0],
)
return systemTypes.ApigwFilterResourceType, ref, pp, err
case systemTypes.ApigwRouteResourceType:
if len(path) != 1 {
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))

View File

@@ -37,8 +37,6 @@ allow:
- application.flag.global
- apigw-route.create
- apigw-routes.search
- apigw-filter.create
- apigw-filters.search
- report.create
- reports.search

View File

@@ -37,7 +37,6 @@ rdbms:
search:
enablePaging: true
enableFilterCheckFunction: false
upsert:
enable: false

View File

@@ -37,7 +37,6 @@ rdbms:
search:
enablePaging: true
enableFilterCheckFunction: false
upsert:
enable: false

View File

@@ -81,7 +81,7 @@ func (s Store) SearchApigwFilters(ctx context.Context, f types.ApigwFilterFilter
ctx,
q, f.Sort, f.PageCursor,
f.Limit,
nil,
f.Check,
func(cur *filter.PagingCursor) squirrel.Sqlizer {
return builders.CursorCondition(cur, nil)
},
@@ -265,6 +265,16 @@ func (s Store) QueryApigwFilters(
for _, res = range tmp {
// check fn set, call it and see if it passed the test
// if not, skip the item
if check != nil {
if chk, err := check(res); err != nil {
return nil, err
} else if !chk {
continue
}
}
set = append(set, res)
}
@@ -465,7 +475,7 @@ func (Store) apigwFilterColumns(aa ...string) []string {
}
}
// {true true false true true false}
// {true true false true true true}
// sortableApigwFilterColumns returns all ApigwFilter columns flagged as sortable
//

View File

@@ -81,7 +81,7 @@ func (s Store) SearchApigwRoutes(ctx context.Context, f types.ApigwRouteFilter)
ctx,
q, f.Sort, f.PageCursor,
f.Limit,
nil,
f.Check,
func(cur *filter.PagingCursor) squirrel.Sqlizer {
return builders.CursorCondition(cur, nil)
},
@@ -265,6 +265,16 @@ func (s Store) QueryApigwRoutes(
for _, res = range tmp {
// check fn set, call it and see if it passed the test
// if not, skip the item
if check != nil {
if chk, err := check(res); err != nil {
return nil, err
} else if !chk {
continue
}
}
set = append(set, res)
}
@@ -465,7 +475,7 @@ func (Store) apigwRouteColumns(aa ...string) []string {
}
}
// {true true false true true false}
// {true true false true true true}
// sortableApigwRouteColumns returns all ApigwRoute columns flagged as sortable
//

View File

@@ -1699,8 +1699,7 @@ endpoints:
path: "/"
parameters:
get:
- { name: routeID, type: "uint64", title: "Filter by route ID" }
- { name: query, type: "string", title: "Filter filters" }
- { name: routeID, type: "uint64", title: "Filter by route ID", required: true }
- { name: deleted, type: "uint64", title: "Exclude (0, default), include (1) or return only (2) deleted filters" }
- { name: disabled, type: "uint64", title: "Exclude (0, default), include (1) or return only (2) disabled filters" }
- { name: limit, type: "uint", title: "Limit" }

View File

@@ -40,11 +40,6 @@ type (
// Filter by route ID
RouteID uint64 `json:",string"`
// Query GET parameter
//
// Filter filters
Query string
// Deleted GET parameter
//
// Exclude (0, default), include (1) or return only (2) deleted filters
@@ -171,7 +166,6 @@ func NewApigwFilterList() *ApigwFilterList {
func (r ApigwFilterList) Auditable() map[string]interface{} {
return map[string]interface{}{
"routeID": r.RouteID,
"query": r.Query,
"deleted": r.Deleted,
"disabled": r.Disabled,
"limit": r.Limit,
@@ -185,11 +179,6 @@ func (r ApigwFilterList) GetRouteID() uint64 {
return r.RouteID
}
// Auditable returns all auditable/loggable parameters
func (r ApigwFilterList) GetQuery() string {
return r.Query
}
// Auditable returns all auditable/loggable parameters
func (r ApigwFilterList) GetDeleted() uint64 {
return r.Deleted
@@ -228,12 +217,6 @@ func (r *ApigwFilterList) Fill(req *http.Request) (err error) {
return err
}
}
if val, ok := tmp["query"]; ok && len(val) > 0 {
r.Query, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["deleted"]; ok && len(val) > 0 {
r.Deleted, err = payload.ParseUint64(val[0]), nil
if err != nil {

View File

@@ -7,7 +7,6 @@ package service
//
// Definitions file that controls how this file is generated:
// - system.apigw-filter.yaml
// - system.apigw-route.yaml
// - system.application.yaml
// - system.auth-client.yaml
@@ -64,21 +63,6 @@ func (svc accessControl) Effective(ctx context.Context, rr ...rbac.Resource) (ee
func (svc accessControl) List() (out []map[string]string) {
def := []map[string]string{
{
"type": types.ApigwFilterResourceType,
"any": types.ApigwFilterRbacResource(0),
"op": "read",
},
{
"type": types.ApigwFilterResourceType,
"any": types.ApigwFilterRbacResource(0),
"op": "update",
},
{
"type": types.ApigwFilterResourceType,
"any": types.ApigwFilterRbacResource(0),
"op": "delete",
},
{
"type": types.ApigwRouteResourceType,
"any": types.ApigwRouteRbacResource(0),
@@ -344,16 +328,6 @@ func (svc accessControl) List() (out []map[string]string) {
"any": types.ComponentRbacResource(),
"op": "apigw-routes.search",
},
{
"type": types.ComponentResourceType,
"any": types.ComponentRbacResource(),
"op": "apigw-filter.create",
},
{
"type": types.ComponentResourceType,
"any": types.ComponentRbacResource(),
"op": "apigw-filters.search",
},
{
"type": types.ComponentResourceType,
"any": types.ComponentRbacResource(),
@@ -421,27 +395,6 @@ func (svc accessControl) FindRulesByRoleID(ctx context.Context, roleID uint64) (
return svc.rbac.FindRulesByRoleID(roleID), nil
}
// CanReadApigwFilter checks if current user can read api gateway filter
//
// This function is auto-generated
func (svc accessControl) CanReadApigwFilter(ctx context.Context, r *types.ApigwFilter) bool {
return svc.can(ctx, "read", r)
}
// CanUpdateApigwFilter checks if current user can update api gateway filter
//
// This function is auto-generated
func (svc accessControl) CanUpdateApigwFilter(ctx context.Context, r *types.ApigwFilter) bool {
return svc.can(ctx, "update", r)
}
// CanDeleteApigwFilter checks if current user can delete api gateway filter
//
// This function is auto-generated
func (svc accessControl) CanDeleteApigwFilter(ctx context.Context, r *types.ApigwFilter) bool {
return svc.can(ctx, "delete", r)
}
// CanReadApigwRoute checks if current user can read api gateway route
//
// This function is auto-generated
@@ -813,20 +766,6 @@ func (svc accessControl) CanSearchApigwRoutes(ctx context.Context) bool {
return svc.can(ctx, "apigw-routes.search", &types.Component{})
}
// CanCreateApigwFilter checks if current user can add api gateway filter to route
//
// This function is auto-generated
func (svc accessControl) CanCreateApigwFilter(ctx context.Context) bool {
return svc.can(ctx, "apigw-filter.create", &types.Component{})
}
// CanSearchApigwFilters checks if current user can list, search or filter api gateway filters
//
// This function is auto-generated
func (svc accessControl) CanSearchApigwFilters(ctx context.Context) bool {
return svc.can(ctx, "apigw-filters.search", &types.Component{})
}
// CanManageResourceTranslations checks if current user can list, search, create, or update resource translations
//
// This function is auto-generated
@@ -839,8 +778,6 @@ func (svc accessControl) CanManageResourceTranslations(ctx context.Context) bool
// This function is auto-generated
func rbacResourceValidator(r string, oo ...string) error {
switch rbac.ResourceType(r) {
case types.ApigwFilterResourceType:
return rbacApigwFilterResourceValidator(r, oo...)
case types.ApigwRouteResourceType:
return rbacApigwRouteResourceValidator(r, oo...)
case types.ApplicationResourceType:
@@ -867,12 +804,6 @@ func rbacResourceValidator(r string, oo ...string) error {
// This function is auto-generated
func rbacResourceOperations(r string) map[string]bool {
switch rbac.ResourceType(r) {
case types.ApigwFilterResourceType:
return map[string]bool{
"read": true,
"update": true,
"delete": true,
}
case types.ApigwRouteResourceType:
return map[string]bool{
"read": true,
@@ -949,8 +880,6 @@ func rbacResourceOperations(r string) map[string]bool {
"queues.search": true,
"apigw-route.create": true,
"apigw-routes.search": true,
"apigw-filter.create": true,
"apigw-filters.search": true,
"resource-translations.manage": true,
}
}
@@ -958,50 +887,6 @@ func rbacResourceOperations(r string) map[string]bool {
return nil
}
// rbacApigwFilterResourceValidator checks validity of rbac resource and operations
//
// Can be called without operations to check for validity of resource string only
//
// This function is auto-generated
func rbacApigwFilterResourceValidator(r string, oo ...string) error {
defOps := rbacResourceOperations(r)
for _, o := range oo {
if !defOps[o] {
return fmt.Errorf("invalid operation '%s' for system ApigwFilter resource", o)
}
}
if !strings.HasPrefix(r, types.ApigwFilterResourceType) {
// expecting resource to always include path
return fmt.Errorf("invalid resource type")
}
const sep = "/"
var (
pp = strings.Split(strings.Trim(r[len(types.ApigwFilterResourceType):], sep), sep)
prc = []string{
"ID",
}
)
if len(pp) != len(prc) {
return fmt.Errorf("invalid resource path structure")
}
for i := 0; i < len(pp); i++ {
if pp[i] != "*" {
if i > 0 && pp[i-1] == "*" {
return fmt.Errorf("invalid resource path wildcard level (%d) for ApigwFilter", i)
}
if _, err := cast.ToUint64E(pp[i]); err != nil {
return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i])
}
}
}
return nil
}
// rbacApigwRouteResourceValidator checks validity of rbac resource and operations
//
// Can be called without operations to check for validity of resource string only

View File

@@ -15,49 +15,46 @@ type (
apigwFilter struct {
actionlog actionlog.Recorder
store store.Storer
ac functionAccessController
ac routeAccessController
route *apigwRoute
}
functionAccessController interface {
CanSearchApigwFilters(context.Context) bool
CanCreateApigwFilter(context.Context) bool
CanReadApigwFilter(context.Context, *types.ApigwFilter) bool
CanUpdateApigwFilter(context.Context, *types.ApigwFilter) bool
CanDeleteApigwFilter(context.Context, *types.ApigwFilter) bool
}
)
func Filter() *apigwFilter {
return (&apigwFilter{
return &apigwFilter{
route: DefaultApigwRoute,
ac: DefaultAccessControl,
actionlog: DefaultActionlog,
store: DefaultStore,
})
}
}
func (svc *apigwFilter) FindByID(ctx context.Context, ID uint64) (q *types.ApigwFilter, err error) {
func (svc *apigwFilter) FindByID(ctx context.Context, filterID uint64) (q *types.ApigwFilter, err error) {
var (
rProps = &apigwFilterActionProps{}
r *types.ApigwRoute
)
err = func() error {
if ID == 0 {
if filterID == 0 {
return ApigwFilterErrInvalidID()
}
if !svc.ac.CanSearchApigwFilters(ctx) {
return ApigwFilterErrNotAllowedToRead(rProps)
}
if q, err = store.LookupApigwFilterByID(ctx, svc.store, ID); err != nil {
if q, err = store.LookupApigwFilterByID(ctx, svc.store, filterID); err != nil {
return TemplateErrInvalidID().Wrap(err)
}
rProps.setFilter(q)
// Get route
if r, err = svc.route.FindByID(ctx, q.Route); err != nil {
return err
}
if !svc.ac.CanReadApigwRoute(ctx, r) {
return ApigwRouteErrNotAllowedToRead()
}
return nil
}()
@@ -71,17 +68,17 @@ func (svc *apigwFilter) Create(ctx context.Context, new *types.ApigwFilter) (q *
)
err = func() (err error) {
if !svc.ac.CanCreateApigwFilter(ctx) {
return ApigwFilterErrNotAllowedToCreate(qProps)
}
// Set new values after beforeCreate events are emitted
new.ID = nextID()
new.CreatedAt = *now()
new.CreatedBy = a.GetIdentityFromContext(ctx).Identity()
if r, err = svc.route.FindByID(ctx, new.Route); err != nil {
return ApigwFilterErrNotFound(qProps)
if r, err = store.LookupApigwRouteByID(ctx, svc.store, new.Route); err != nil {
return
}
if !svc.ac.CanUpdateApigwRoute(ctx, r) {
return ApigwRouteErrNotAllowedToUpdate()
}
// check for existing filters if route is async
@@ -148,14 +145,14 @@ func (svc *apigwFilter) Update(ctx context.Context, upd *types.ApigwFilter) (q *
return ApigwFilterErrNotFound(qProps)
}
if !svc.ac.CanUpdateApigwFilter(ctx, qq) {
return ApigwFilterErrNotAllowedToUpdate(qProps)
}
if r, err = svc.route.FindByID(ctx, upd.Route); err != nil {
return err
}
if !svc.ac.CanUpdateApigwRoute(ctx, r) {
return ApigwRouteErrNotAllowedToUpdate()
}
if qq, e = store.LookupApigwFilterByID(ctx, svc.store, upd.ID); e == nil && qq == nil {
return ApigwFilterErrNotFound(qProps)
}
@@ -193,12 +190,14 @@ func (svc *apigwFilter) DeleteByID(ctx context.Context, ID uint64) (err error) {
return ApigwFilterErrNotFound(qProps)
}
if !svc.ac.CanDeleteApigwFilter(ctx, q) {
return ApigwFilterErrNotAllowedToDelete(qProps)
if r, err = store.LookupApigwRouteByID(ctx, svc.store, q.Route); err == store.ErrNotFound {
return ApigwRouteErrNotFound()
} else if err != nil {
return
}
if r, err = svc.route.FindByID(ctx, q.Route); err != nil {
return err
if !svc.ac.CanDeleteApigwRoute(ctx, r) {
return ApigwRouteErrNotAllowedToDelete()
}
qProps.setFilter(q)
@@ -233,12 +232,14 @@ func (svc *apigwFilter) UndeleteByID(ctx context.Context, ID uint64) (err error)
return ApigwFilterErrNotFound(qProps)
}
if !svc.ac.CanDeleteApigwFilter(ctx, q) {
return ApigwFilterErrNotAllowedToDelete(qProps)
if r, err = store.LookupApigwRouteByID(ctx, svc.store, q.Route); err == store.ErrNotFound {
return ApigwRouteErrNotFound()
} else if err != nil {
return
}
if r, err = svc.route.FindByID(ctx, q.Route); err != nil {
return err
if !svc.ac.CanDeleteApigwRoute(ctx, r) {
return ApigwRouteErrNotAllowedToUndelete()
}
qProps.setFilter(q)
@@ -264,18 +265,32 @@ func (svc *apigwFilter) UndeleteByID(ctx context.Context, ID uint64) (err error)
func (svc *apigwFilter) Search(ctx context.Context, filter types.ApigwFilterFilter) (r types.ApigwFilterSet, f types.ApigwFilterFilter, err error) {
var (
aProps = &apigwFilterActionProps{search: &filter}
route *types.ApigwRoute
)
// For each fetched item, store backend will check if it is valid or not
filter.Check = func(res *types.ApigwFilter) (bool, error) {
if !svc.ac.CanReadApigwFilter(ctx, res) {
return false, nil
err = func() error {
// Preload the corresponding API GW route for access control
if filter.RouteID == 0 {
return ApigwRouteErrInvalidID()
}
return true, nil
}
if route, err = store.LookupApigwRouteByID(ctx, svc.store, filter.RouteID); err != nil {
return ApigwRouteErrNotFound()
}
err = func() error {
if !svc.ac.CanReadApigwRoute(ctx, route) {
return ApigwRouteErrNotAllowedToRead()
}
// Prepare the filter checker so we can evaluate access to specific filters
filter.Check = func(res *types.ApigwFilter) (bool, error) {
if !svc.ac.CanReadApigwRoute(ctx, route) {
return false, nil
}
return true, nil
}
// Go!
if r, f, err = store.SearchApigwFilters(ctx, svc.store, filter); err != nil {
return err
}
@@ -292,10 +307,9 @@ func (svc *apigwFilter) DefFilter(ctx context.Context, kind string) (l interface
)
err = func() error {
if !svc.ac.CanSearchApigwFilters(ctx) {
return ApigwFilterErrNotAllowedToRead(qProps)
if !svc.ac.CanSearchApigwRoutes(ctx) {
return ApigwRouteErrNotAllowedToRead()
}
// get the definitions from registry
l = apigw.Service().Funcs(kind)
@@ -312,10 +326,9 @@ func (svc *apigwFilter) DefProxyAuth(ctx context.Context) (l interface{}, err er
)
err = func() error {
if !svc.ac.CanSearchApigwFilters(ctx) {
return ApigwFilterErrNotAllowedToRead(qProps)
if !svc.ac.CanSearchApigwRoutes(ctx) {
return ApigwRouteErrNotAllowedToRead()
}
// get the definitions from registry
l = apigw.Service().ProxyAuthDef()

View File

@@ -435,186 +435,6 @@ func ApigwFilterErrInvalidRoute(mm ...*apigwFilterActionProps) *errors.Error {
return e
}
// ApigwFilterErrNotAllowedToCreate returns "system:filter.notAllowedToCreate" as *errors.Error
//
//
// This function is auto-generated.
//
func ApigwFilterErrNotAllowedToCreate(mm ...*apigwFilterActionProps) *errors.Error {
var p = &apigwFilterActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to create a filter", nil),
errors.Meta("type", "notAllowedToCreate"),
errors.Meta("resource", "system:filter"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(apigwFilterLogMetaKey{}, "failed to create a route; insufficient permissions"),
errors.Meta(apigwFilterPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "apigwFilter.errors.notAllowedToCreate"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// ApigwFilterErrNotAllowedToRead returns "system:filter.notAllowedToRead" as *errors.Error
//
//
// This function is auto-generated.
//
func ApigwFilterErrNotAllowedToRead(mm ...*apigwFilterActionProps) *errors.Error {
var p = &apigwFilterActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to read this filter", nil),
errors.Meta("type", "notAllowedToRead"),
errors.Meta("resource", "system:filter"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(apigwFilterLogMetaKey{}, "failed to read {{filter}}; insufficient permissions"),
errors.Meta(apigwFilterPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "apigwFilter.errors.notAllowedToRead"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// ApigwFilterErrNotAllowedToUpdate returns "system:filter.notAllowedToUpdate" as *errors.Error
//
//
// This function is auto-generated.
//
func ApigwFilterErrNotAllowedToUpdate(mm ...*apigwFilterActionProps) *errors.Error {
var p = &apigwFilterActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to update this filter", nil),
errors.Meta("type", "notAllowedToUpdate"),
errors.Meta("resource", "system:filter"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(apigwFilterLogMetaKey{}, "failed to update {{filter}}; insufficient permissions"),
errors.Meta(apigwFilterPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "apigwFilter.errors.notAllowedToUpdate"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// ApigwFilterErrNotAllowedToDelete returns "system:filter.notAllowedToDelete" as *errors.Error
//
//
// This function is auto-generated.
//
func ApigwFilterErrNotAllowedToDelete(mm ...*apigwFilterActionProps) *errors.Error {
var p = &apigwFilterActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to delete this filter", nil),
errors.Meta("type", "notAllowedToDelete"),
errors.Meta("resource", "system:filter"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(apigwFilterLogMetaKey{}, "failed to delete {{filter}}; insufficient permissions"),
errors.Meta(apigwFilterPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "apigwFilter.errors.notAllowedToDelete"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// ApigwFilterErrNotAllowedToUndelete returns "system:filter.notAllowedToUndelete" as *errors.Error
//
//
// This function is auto-generated.
//
func ApigwFilterErrNotAllowedToUndelete(mm ...*apigwFilterActionProps) *errors.Error {
var p = &apigwFilterActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to undelete this filter", nil),
errors.Meta("type", "notAllowedToUndelete"),
errors.Meta("resource", "system:filter"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(apigwFilterLogMetaKey{}, "failed to undelete {{filter}}; insufficient permissions"),
errors.Meta(apigwFilterPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "apigwFilter.errors.notAllowedToUndelete"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// ApigwFilterErrAsyncRouteTooManyProcessers returns "system:filter.asyncRouteTooManyProcessers" as *errors.Error
//
//

View File

@@ -54,26 +54,6 @@ errors:
message: "invalid route"
severity: warning
- error: notAllowedToCreate
message: "not allowed to create a filter"
log: "failed to create a route; insufficient permissions"
- error: notAllowedToRead
message: "not allowed to read this filter"
log: "failed to read {{filter}}; insufficient permissions"
- error: notAllowedToUpdate
message: "not allowed to update this filter"
log: "failed to update {{filter}}; insufficient permissions"
- error: notAllowedToDelete
message: "not allowed to delete this filter"
log: "failed to delete {{filter}}; insufficient permissions"
- error: notAllowedToUndelete
message: "not allowed to undelete this filter"
log: "failed to undelete {{filter}}; insufficient permissions"
- error: asyncRouteTooManyProcessers
message: "processer already exists for this async route"
log: "failed to add {{filter}}; too many processers, async route"

View File

@@ -30,11 +30,11 @@ type (
)
func Route() *apigwRoute {
return (&apigwRoute{
return &apigwRoute{
ac: DefaultAccessControl,
actionlog: DefaultActionlog,
store: DefaultStore,
})
}
}
func (svc *apigwRoute) FindByID(ctx context.Context, ID uint64) (q *types.ApigwRoute, err error) {
@@ -47,10 +47,6 @@ func (svc *apigwRoute) FindByID(ctx context.Context, ID uint64) (q *types.ApigwR
return ApigwRouteErrInvalidID()
}
if !svc.ac.CanSearchApigwRoutes(ctx) {
return ApigwRouteErrNotAllowedToRead(rProps)
}
if q, err = store.LookupApigwRouteByID(ctx, svc.store, ID); err != nil {
return ApigwRouteErrInvalidID().Wrap(err)
}
@@ -133,7 +129,9 @@ func (svc *apigwRoute) Update(ctx context.Context, upd *types.ApigwRoute) (q *ty
q = upd
// send the signal to reload all route
apigw.Service().Reload(ctx)
if qq.Enabled != upd.Enabled {
apigw.Service().Reload(ctx)
}
return nil
}()
@@ -170,7 +168,9 @@ func (svc *apigwRoute) DeleteByID(ctx context.Context, ID uint64) (err error) {
}
// send the signal to reload all queues
apigw.Service().Reload(ctx)
if q.Enabled {
apigw.Service().Reload(ctx)
}
return nil
}()
@@ -194,7 +194,7 @@ func (svc *apigwRoute) UndeleteByID(ctx context.Context, ID uint64) (err error)
}
if !svc.ac.CanDeleteApigwRoute(ctx, q) {
return ApigwRouteErrNotAllowedToDelete(qProps)
return ApigwRouteErrNotAllowedToUndelete(qProps)
}
qProps.setRoute(q)
@@ -207,7 +207,9 @@ func (svc *apigwRoute) UndeleteByID(ctx context.Context, ID uint64) (err error)
}
// send the signal to reload all queues
apigw.Service().Reload(ctx)
if q.Enabled {
apigw.Service().Reload(ctx)
}
return nil
}()
@@ -230,6 +232,10 @@ func (svc *apigwRoute) Search(ctx context.Context, filter types.ApigwRouteFilter
}
err = func() error {
if !svc.ac.CanSearchApigwRoutes(ctx) {
return ApigwRouteErrNotAllowedToSearch()
}
if r, f, err = store.SearchApigwRoutes(ctx, svc.store, filter); err != nil {
return err
}

View File

@@ -635,6 +635,42 @@ func ApigwRouteErrNotAllowedToRead(mm ...*apigwRouteActionProps) *errors.Error {
return e
}
// ApigwRouteErrNotAllowedToSearch returns "system:apigw-route.notAllowedToSearch" as *errors.Error
//
//
// This function is auto-generated.
//
func ApigwRouteErrNotAllowedToSearch(mm ...*apigwRouteActionProps) *errors.Error {
var p = &apigwRouteActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to list or search routes", nil),
errors.Meta("type", "notAllowedToSearch"),
errors.Meta("resource", "system:apigw-route"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(apigwRouteLogMetaKey{}, "failed to search for routes; insufficient permissions"),
errors.Meta(apigwRoutePropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "apigwRoute.errors.notAllowedToSearch"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// ApigwRouteErrNotAllowedToUpdate returns "system:apigw-route.notAllowedToUpdate" as *errors.Error
//
//

View File

@@ -76,6 +76,10 @@ errors:
message: "not allowed to read this route"
log: "failed to read {{route.endpoint}}; insufficient permissions"
- error: notAllowedToSearch
message: "not allowed to list or search routes"
log: "failed to search for routes; insufficient permissions"
- error: notAllowedToUpdate
message: "not allowed to update this route"
log: "failed to update {{route.endpoint}}; insufficient permissions"

View File

@@ -29,10 +29,8 @@ type (
}
ApigwFilterFilter struct {
RouteID uint64 `json:"routeID,string"`
Endpoint string `json:"endpoint"`
Group string `json:"group"`
Enabled bool `json:"enabled"`
RouteID uint64 `json:"routeID,string"`
Enabled bool `json:"enabled"`
Deleted filter.State `json:"deleted"`

View File

@@ -7,7 +7,6 @@ package types
//
// Definitions file that controls how this file is generated:
// - system.apigw-filter.yaml
// - system.apigw-route.yaml
// - system.application.yaml
// - system.auth-client.yaml
@@ -30,7 +29,6 @@ type (
)
const (
ApigwFilterResourceType = "corteza::system:apigw-filter"
ApigwRouteResourceType = "corteza::system:apigw-route"
ApplicationResourceType = "corteza::system:application"
AuthClientResourceType = "corteza::system:auth-client"
@@ -41,37 +39,6 @@ const (
ComponentResourceType = "corteza::system"
)
// RbacResource returns string representation of RBAC resource for ApigwFilter by calling ApigwFilterRbacResource fn
//
// RBAC resource is in the corteza::system:apigw-filter/... format
//
// This function is auto-generated
func (r ApigwFilter) RbacResource() string {
return ApigwFilterRbacResource(r.ID)
}
// ApigwFilterRbacResource returns string representation of RBAC resource for ApigwFilter
//
// RBAC resource is in the corteza::system:apigw-filter/... format
//
// This function is auto-generated
func ApigwFilterRbacResource(id uint64) string {
cpts := []interface{}{ApigwFilterResourceType}
if id != 0 {
cpts = append(cpts, strconv.FormatUint(id, 10))
} else {
cpts = append(cpts, "*")
}
return fmt.Sprintf(ApigwFilterRbacResourceTpl(), cpts...)
}
// @todo template
func ApigwFilterRbacResourceTpl() string {
return "%s/%s"
}
// RbacResource returns string representation of RBAC resource for ApigwRoute by calling ApigwRouteRbacResource fn
//
// RBAC resource is in the corteza::system:apigw-route/... format

504
tests/system/apigw_test.go Normal file
View File

@@ -0,0 +1,504 @@
package system
import (
"context"
"fmt"
"net/http"
"strconv"
"testing"
"time"
"github.com/cortezaproject/corteza-server/pkg/id"
"github.com/cortezaproject/corteza-server/store"
"github.com/cortezaproject/corteza-server/system/service"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/cortezaproject/corteza-server/tests/helpers"
jsonpath "github.com/steinfletcher/apitest-jsonpath"
)
func (h helper) createRouteWithFilter(s string, fkind string) (*types.ApigwRoute, *types.ApigwFilter) {
r := h.createRoute(&types.ApigwRoute{Endpoint: "/" + s, Method: "GET"})
f := h.createFilters(&types.ApigwFilter{Kind: fkind}, r.ID)
return r, f
}
func (h helper) createRoute(route *types.ApigwRoute) *types.ApigwRoute {
if route.ID == 0 {
route.ID = id.Next()
}
if route.CreatedAt.IsZero() {
route.CreatedAt = time.Now()
}
h.a.NoError(service.DefaultStore.CreateApigwRoute(context.Background(), route))
return route
}
func (h helper) createFilters(f *types.ApigwFilter, routeID uint64) *types.ApigwFilter {
f.Route = routeID
if f.ID == 0 {
f.ID = id.Next()
}
if f.CreatedAt.IsZero() {
f.CreatedAt = time.Now()
}
h.a.NoError(service.DefaultStore.CreateApigwFilter(context.Background(), f))
return f
}
func (h helper) clearRoutes() {
h.noError(store.TruncateApigwFilters(context.Background(), service.DefaultStore))
h.noError(store.TruncateApigwRoutes(context.Background(), service.DefaultStore))
}
func TestApigwRouteRead(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "read")
h.apiInit().
Get(fmt.Sprintf("/apigw/route/%d", r.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Equal(`$.response.routeID`, strconv.FormatUint(r.ID, 10))).
Assert(jsonpath.Equal(`$.response.endpoint`, "/test")).
End()
}
func TestApigwRouteRead_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test", "")
h.apiInit().
Get(fmt.Sprintf("/apigw/route/%d", r.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToRead")).
End()
}
func TestApigwRouteSearch(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
h.createRouteWithFilter("test1", "")
h.createRouteWithFilter("test2", "")
helpers.AllowMe(h, types.ComponentRbacResource(), "apigw-routes.search")
helpers.AllowMe(h, types.ApigwRouteRbacResource(0), "read")
h.apiInit().
Get(fmt.Sprintf("/apigw/route/")).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Len(`$.response.set`, 2)).
Assert(jsonpath.Equal(`$.response.set[0].endpoint`, "/test1")).
Assert(jsonpath.Equal(`$.response.set[1].endpoint`, "/test2")).
End()
}
func TestApigwRouteSearch_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
h.createRouteWithFilter("test1", "")
h.createRouteWithFilter("test2", "")
h.apiInit().
Get(fmt.Sprintf("/apigw/route/")).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToSearch")).
End()
}
func TestApigwRouteSearch_forbidenSpecific(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test1", "")
h.createRouteWithFilter("test2", "")
helpers.AllowMe(h, types.ComponentRbacResource(), "apigw-routes.search")
helpers.AllowMe(h, types.ApigwRouteRbacResource(0), "read")
helpers.DenyMe(h, types.ApigwRouteRbacResource(r.ID), "read")
h.apiInit().
Get(fmt.Sprintf("/apigw/route/")).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Len(`$.response.set`, 1)).
Assert(jsonpath.Equal(`$.response.set[0].endpoint`, "/test2")).
End()
}
func TestApigwRouteCreate(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
helpers.AllowMe(h, types.ComponentRbacResource(), "apigw-route.create")
h.apiInit().
Post(fmt.Sprintf("/apigw/route")).
Header("Accept", "application/json").
FormData("endpoint", "/test").
FormData("method", "GET").
FormData("enabled", "false").
FormData("group", "g1").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Present(`$.response.routeID`)).
Assert(jsonpath.Equal(`$.response.endpoint`, "/test")).
End()
}
func TestApigwRouteCreate_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
h.apiInit().
Post(fmt.Sprintf("/apigw/route")).
Header("Accept", "application/json").
FormData("endpoint", "/test").
FormData("method", "GET").
FormData("enabled", "false").
FormData("group", "g1").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToCreate")).
End()
}
func TestApigwRouteUpdate(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "update")
h.apiInit().
Put(fmt.Sprintf("/apigw/route/%d", r.ID)).
Header("Accept", "application/json").
FormData("endpoint", "/test-edited").
FormData("enabled", "false").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Present(`$.response.routeID`)).
Assert(jsonpath.Equal(`$.response.endpoint`, "/test-edited")).
End()
}
func TestApigwRouteUpdate_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test", "")
h.apiInit().
Put(fmt.Sprintf("/apigw/route/%d", r.ID)).
Header("Accept", "application/json").
FormData("endpoint", "/test-edited").
FormData("enabled", "false").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToUpdate")).
End()
}
func TestApigwRouteDelete(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "delete")
h.apiInit().
Delete(fmt.Sprintf("/apigw/route/%d", r.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
}
func TestApigwRouteDelete_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test", "")
h.apiInit().
Delete(fmt.Sprintf("/apigw/route/%d", r.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToDelete")).
End()
}
func TestApigwRouteUnDelete(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "delete")
h.apiInit().
Post(fmt.Sprintf("/apigw/route/%d/undelete", r.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
}
func TestApigwRouteUnDelete_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test", "")
h.apiInit().
Post(fmt.Sprintf("/apigw/route/%d/undelete", r.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToUndelete")).
End()
}
// Filters
func TestApigwFilterRead(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, f := h.createRouteWithFilter("test", "test")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "read")
h.apiInit().
Get(fmt.Sprintf("/apigw/filter/%d", f.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Equal(`$.response.filterID`, strconv.FormatUint(f.ID, 10))).
Assert(jsonpath.Equal(`$.response.routeID`, strconv.FormatUint(r.ID, 10))).
End()
}
func TestApigwFilterRead_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
_, f := h.createRouteWithFilter("test", "test")
h.apiInit().
Get(fmt.Sprintf("/apigw/filter/%d", f.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToRead")).
End()
}
func TestApigwFilterSearch(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, f := h.createRouteWithFilter("test1", "")
helpers.AllowMe(h, types.ComponentRbacResource(), "apigw-routes.search")
helpers.AllowMe(h, types.ApigwRouteRbacResource(0), "read")
h.apiInit().
Get(fmt.Sprintf("/apigw/filter/")).
Query("routeID", strconv.FormatUint(r.ID, 10)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Len(`$.response.set`, 1)).
Assert(jsonpath.Equal(`$.response.set[0].filterID`, strconv.FormatUint(f.ID, 10))).
Assert(jsonpath.Equal(`$.response.set[0].routeID`, strconv.FormatUint(r.ID, 10))).
End()
}
func TestApigwFilterSearch_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test1", "")
h.apiInit().
Get(fmt.Sprintf("/apigw/filter/")).
Query("routeID", strconv.FormatUint(r.ID, 10)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToRead")).
End()
}
func TestApigwFilterCreate(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test1", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "read")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "update")
h.apiInit().
Put(fmt.Sprintf("/apigw/filter")).
Header("Accept", "application/json").
FormData("routeID", strconv.FormatUint(r.ID, 10)).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Present(`$.response.filterID`)).
Assert(jsonpath.Equal(`$.response.routeID`, strconv.FormatUint(r.ID, 10))).
End()
}
func TestApigwFilterCreate_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, _ := h.createRouteWithFilter("test1", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "read")
h.apiInit().
Put(fmt.Sprintf("/apigw/filter")).
Header("Accept", "application/json").
FormData("routeID", strconv.FormatUint(r.ID, 10)).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToUpdate")).
End()
}
func TestApigwFilterUpdate(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, f := h.createRouteWithFilter("test1", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "read")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "update")
h.apiInit().
Post(fmt.Sprintf("/apigw/filter/%d", f.ID)).
Header("Accept", "application/json").
FormData("routeID", strconv.FormatUint(r.ID, 10)).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Equal(`$.response.filterID`, strconv.FormatUint(f.ID, 10))).
Assert(jsonpath.Equal(`$.response.routeID`, strconv.FormatUint(r.ID, 10))).
End()
}
func TestApigwFilterUpdate_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, f := h.createRouteWithFilter("test1", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "read")
h.apiInit().
Post(fmt.Sprintf("/apigw/filter/%d", f.ID)).
Header("Accept", "application/json").
FormData("routeID", strconv.FormatUint(r.ID, 10)).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToUpdate")).
End()
}
func TestApigwFilterDelete(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, f := h.createRouteWithFilter("test1", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "read")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "delete")
h.apiInit().
Delete(fmt.Sprintf("/apigw/filter/%d", f.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
}
func TestApigwFilterDelete_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
_, f := h.createRouteWithFilter("test1", "")
h.apiInit().
Delete(fmt.Sprintf("/apigw/filter/%d", f.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToDelete")).
End()
}
func TestApigwFilterUnDelete(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, f := h.createRouteWithFilter("test1", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "read")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "delete")
h.apiInit().
Post(fmt.Sprintf("/apigw/filter/%d/undelete", f.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
}
func TestApigwFilterUnDelete_forbiden(t *testing.T) {
h := newHelper(t)
h.clearRoutes()
r, f := h.createRouteWithFilter("test1", "")
helpers.AllowMe(h, types.ApigwRouteRbacResource(r.ID), "read")
h.apiInit().
Post(fmt.Sprintf("/apigw/filter/%d/undelete", f.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("apigwRoute.errors.notAllowedToUndelete")).
End()
}