Merge pull request #2367 from influxdata/fix/issue#2252

Add org admin and member specific permissions
pull/10616/head
Michael Desa 2019-01-09 17:54:20 -05:00 committed by GitHub
commit 394673c54b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 246 additions and 14 deletions

View File

@ -30,7 +30,7 @@ func (a *Authorization) Allowed(p Permission) bool {
return false return false
} }
return allowed(p, a.Permissions) return PermissionAllowed(p, a.Permissions)
} }
// IsActive is a stub for idpe. // IsActive is a stub for idpe.

View File

@ -29,9 +29,25 @@ type Authorizer interface {
Kind() string Kind() string
} }
func allowed(p Permission, ps []Permission) bool { // PermissionAllowed
func PermissionAllowed(p Permission, ps []Permission) bool {
pID := ID(0)
if p.ID != nil {
pID = *p.ID
if !pID.Valid() {
return false
}
}
for _, perm := range ps { for _, perm := range ps {
if perm.Action == p.Action && perm.Resource == p.Resource { permID := ID(0)
if perm.ID != nil {
permID = *perm.ID
if !permID.Valid() {
return false
}
}
if perm.Action == p.Action && perm.Resource == p.Resource && permID == pID {
return true return true
} }
} }
@ -99,7 +115,17 @@ var AllResources = []Resource{
UsersResource, // 7 UsersResource, // 7
} }
// Valid checks if the resource is a member of the Resource enum // OrgResources is the list of all known resource types that belong to an organization.
var OrgResources = []Resource{
BucketsResource, // 1
DashboardsResource, // 2
SourcesResource, // 4
TasksResource, // 5
TelegrafsResource, // 6
UsersResource, // 7
}
// Valid checks if the resource is a member of the Resource enum.
func (r Resource) Valid() (err error) { func (r Resource) Valid() (err error) {
switch r { switch r {
case AuthorizationsResource: // 0 case AuthorizationsResource: // 0
@ -133,7 +159,7 @@ func (p Permission) String() string {
return str return str
} }
// Valid checks if there the resource and action provided is known // Valid checks if there the resource and action provided is known.
func (p *Permission) Valid() error { func (p *Permission) Valid() error {
if err := p.Resource.Valid(); err != nil { if err := p.Resource.Valid(); err != nil {
return &Error{ return &Error{
@ -162,7 +188,7 @@ func (p *Permission) Valid() error {
return nil return nil
} }
// NewPermission returns a permission with provided arguments // NewPermission returns a permission with provided arguments.
func NewPermission(a Action, r Resource) (*Permission, error) { func NewPermission(a Action, r Resource) (*Permission, error) {
p := &Permission{ p := &Permission{
Action: a, Action: a,
@ -172,7 +198,7 @@ func NewPermission(a Action, r Resource) (*Permission, error) {
return p, p.Valid() return p, p.Valid()
} }
// NewPermissionAtID creates a permission with the provided arguments // NewPermissionAtID creates a permission with the provided arguments.
func NewPermissionAtID(id ID, a Action, r Resource) (*Permission, error) { func NewPermissionAtID(id ID, a Action, r Resource) (*Permission, error) {
p := &Permission{ p := &Permission{
Action: a, Action: a,
@ -183,7 +209,7 @@ func NewPermissionAtID(id ID, a Action, r Resource) (*Permission, error) {
return p, p.Valid() return p, p.Valid()
} }
// OperPermissions are the default permissions for those who setup the application // OperPermissions are the default permissions for those who setup the application.
func OperPermissions() []Permission { func OperPermissions() []Permission {
ps := []Permission{} ps := []Permission{}
for _, r := range AllResources { for _, r := range AllResources {
@ -194,3 +220,25 @@ func OperPermissions() []Permission {
return ps return ps
} }
// OrgAdminPermissions are the default permissions for org admins.
func OrgAdminPermissions(orgID ID) []Permission {
ps := []Permission{}
for _, r := range OrgResources {
for _, a := range actions {
ps = append(ps, Permission{ID: &orgID, Action: a, Resource: r})
}
}
return ps
}
// OrgMemberPermissions are the default permissions for org members.
func OrgMemberPermissions(orgID ID) []Permission {
ps := []Permission{}
for _, r := range OrgResources {
ps = append(ps, Permission{ID: &orgID, Action: ReadAction, Resource: r})
}
return ps
}

View File

@ -6,6 +6,135 @@ import (
"github.com/influxdata/platform" "github.com/influxdata/platform"
) )
func TestAuthorizer_PermissionAllowed(t *testing.T) {
tests := []struct {
name string
permission platform.Permission
permissions []platform.Permission
allowed bool
}{
{
name: "bad resource id in permission",
permission: platform.Permission{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(0),
},
permissions: []platform.Permission{
{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(1),
},
},
allowed: false,
},
{
name: "bad resource id in permissions",
permission: platform.Permission{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(1),
},
permissions: []platform.Permission{
{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(0),
},
},
allowed: false,
},
{
name: "matching action resource and ID",
permission: platform.Permission{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(1),
},
permissions: []platform.Permission{
{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(1),
},
},
allowed: true,
},
{
name: "matching action resource no ID",
permission: platform.Permission{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
},
permissions: []platform.Permission{
{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
},
},
allowed: true,
},
{
name: "matching action resource differing ID",
permission: platform.Permission{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(1),
},
permissions: []platform.Permission{
{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(2),
},
},
allowed: false,
},
{
name: "differing action same resource",
permission: platform.Permission{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(1),
},
permissions: []platform.Permission{
{
Action: platform.ReadAction,
Resource: platform.BucketsResource,
ID: IDPtr(1),
},
},
allowed: false,
},
{
name: "same action differing resource",
permission: platform.Permission{
Action: platform.WriteAction,
Resource: platform.BucketsResource,
ID: IDPtr(1),
},
permissions: []platform.Permission{
{
Action: platform.WriteAction,
Resource: platform.TasksResource,
ID: IDPtr(1),
},
},
allowed: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
allowed := platform.PermissionAllowed(tt.permission, tt.permissions)
if allowed != tt.allowed {
t.Errorf("got allowed = %v, expected allowed = %v", allowed, tt.allowed)
}
})
}
}
func TestPermission_Valid(t *testing.T) { func TestPermission_Valid(t *testing.T) {
type fields struct { type fields struct {
Action platform.Action Action platform.Action
@ -159,3 +288,7 @@ func validID() *platform.ID {
id := platform.ID(100) id := platform.ID(100)
return &id return &id
} }
func IDPtr(id platform.ID) *platform.ID {
return &id
}

View File

@ -117,11 +117,24 @@ func (c *Client) Generate(ctx context.Context, req *platform.OnboardingRequest)
if err = c.CreateBucket(ctx, bucket); err != nil { if err = c.CreateBucket(ctx, bucket); err != nil {
return nil, err return nil, err
} }
perms := platform.OperPermissions()
perms = append(perms, platform.OrgAdminPermissions(o.ID)...)
writeBucketPerm, err := platform.NewPermissionAtID(bucket.ID, platform.WriteAction, platform.BucketsResource)
if err != nil {
return nil, err
}
readBucketPerm, err := platform.NewPermissionAtID(bucket.ID, platform.ReadAction, platform.BucketsResource)
if err != nil {
return nil, err
}
perms = append(perms, *writeBucketPerm, *readBucketPerm)
auth := &platform.Authorization{ auth := &platform.Authorization{
UserID: u.ID, UserID: u.ID,
Description: fmt.Sprintf("%s's Token", u.Name), Description: fmt.Sprintf("%s's Token", u.Name),
OrgID: o.ID, OrgID: o.ID,
Permissions: platform.OperPermissions(), Permissions: perms,
} }
if err = c.CreateAuthorization(ctx, auth); err != nil { if err = c.CreateAuthorization(ctx, auth); err != nil {
return nil, err return nil, err

View File

@ -28,6 +28,6 @@ func initOnboardingService(f platformtesting.OnboardingFields, t *testing.T) (pl
} }
} }
func TestGenerate(t *testing.T) { func TestOnboardingService_Generate(t *testing.T) {
platformtesting.Generate(initOnboardingService, t) platformtesting.Generate(initOnboardingService, t)
} }

View File

@ -92,11 +92,24 @@ func (s *Service) Generate(ctx context.Context, req *platform.OnboardingRequest)
if err = s.CreateBucket(ctx, bucket); err != nil { if err = s.CreateBucket(ctx, bucket); err != nil {
return nil, err return nil, err
} }
perms := platform.OperPermissions()
perms = append(perms, platform.OrgAdminPermissions(o.ID)...)
writeBucketPerm, err := platform.NewPermissionAtID(bucket.ID, platform.WriteAction, platform.BucketsResource)
if err != nil {
return nil, err
}
readBucketPerm, err := platform.NewPermissionAtID(bucket.ID, platform.ReadAction, platform.BucketsResource)
if err != nil {
return nil, err
}
perms = append(perms, *writeBucketPerm, *readBucketPerm)
auth := &platform.Authorization{ auth := &platform.Authorization{
UserID: u.ID, UserID: u.ID,
Description: fmt.Sprintf("%s's Token", u.Name), Description: fmt.Sprintf("%s's Token", u.Name),
OrgID: o.ID, OrgID: o.ID,
Permissions: platform.OperPermissions(), Permissions: perms,
} }
if err = s.CreateAuthorization(ctx, auth); err != nil { if err = s.CreateAuthorization(ctx, auth); err != nil {
return nil, err return nil, err

View File

@ -48,7 +48,7 @@ func (s *Session) Allowed(p Permission) bool {
return false return false
} }
return allowed(p, s.Permissions) return PermissionAllowed(p, s.Permissions)
} }
// Kind returns session and is used for auditing. // Kind returns session and is used for auditing.

View File

@ -37,7 +37,7 @@ func NewValidator(ts platform.TaskService, bs platform.BucketService) platform.T
} }
func (ts *taskServiceValidator) CreateTask(ctx context.Context, t *platform.Task) error { func (ts *taskServiceValidator) CreateTask(ctx context.Context, t *platform.Task) error {
p, err := platform.NewPermissionAtID(t.ID, platform.WriteAction, platform.TasksResource) p, err := platform.NewPermissionAtID(t.Organization, platform.WriteAction, platform.TasksResource)
if err != nil { if err != nil {
return err return err
} }

View File

@ -170,7 +170,7 @@ func Generate(
UserID: MustIDBase16(oneID), UserID: MustIDBase16(oneID),
Description: "admin's Token", Description: "admin's Token",
OrgID: MustIDBase16(twoID), OrgID: MustIDBase16(twoID),
Permissions: platform.OperPermissions(), Permissions: mustGeneratePermissions(MustIDBase16(twoID), MustIDBase16(threeID)),
}, },
}, },
}, },
@ -203,6 +203,22 @@ func Generate(
} }
func mustGeneratePermissions(orgID, bucketID platform.ID) []platform.Permission {
perms := platform.OperPermissions()
perms = append(perms, platform.OrgAdminPermissions(orgID)...)
writeBucketPerm, err := platform.NewPermissionAtID(bucketID, platform.WriteAction, platform.BucketsResource)
if err != nil {
panic(err)
}
readBucketPerm, err := platform.NewPermissionAtID(bucketID, platform.ReadAction, platform.BucketsResource)
if err != nil {
panic(err)
}
perms = append(perms, *writeBucketPerm, *readBucketPerm)
return perms
}
const ( const (
oneID = "020f755c3c082000" oneID = "020f755c3c082000"
twoID = "020f755c3c082001" twoID = "020f755c3c082001"

View File

@ -97,6 +97,11 @@ func (m *UserResourceMapping) ownerPerms() ([]Permission, error) {
} }
ps = append(ps, *p) ps = append(ps, *p)
if m.Resource == OrgsResource {
ps = append(ps, OrgAdminPermissions(m.ResourceID)...)
}
} }
return ps, nil return ps, nil
@ -111,6 +116,10 @@ func (m *UserResourceMapping) memberPerms() ([]Permission, error) {
} }
ps = append(ps, *p) ps = append(ps, *p)
if m.Resource == OrgsResource {
ps = append(ps, OrgMemberPermissions(m.ResourceID)...)
}
} }
return ps, nil return ps, nil