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 allowed(p, a.Permissions)
return PermissionAllowed(p, a.Permissions)
}
// IsActive is a stub for idpe.

View File

@ -29,9 +29,25 @@ type Authorizer interface {
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 {
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
}
}
@ -99,7 +115,17 @@ var AllResources = []Resource{
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) {
switch r {
case AuthorizationsResource: // 0
@ -133,7 +159,7 @@ func (p Permission) String() string {
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 {
if err := p.Resource.Valid(); err != nil {
return &Error{
@ -162,7 +188,7 @@ func (p *Permission) Valid() error {
return nil
}
// NewPermission returns a permission with provided arguments
// NewPermission returns a permission with provided arguments.
func NewPermission(a Action, r Resource) (*Permission, error) {
p := &Permission{
Action: a,
@ -172,7 +198,7 @@ func NewPermission(a Action, r Resource) (*Permission, error) {
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) {
p := &Permission{
Action: a,
@ -183,7 +209,7 @@ func NewPermissionAtID(id ID, a Action, r Resource) (*Permission, error) {
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 {
ps := []Permission{}
for _, r := range AllResources {
@ -194,3 +220,25 @@ func OperPermissions() []Permission {
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"
)
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) {
type fields struct {
Action platform.Action
@ -159,3 +288,7 @@ func validID() *platform.ID {
id := platform.ID(100)
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 {
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{
UserID: u.ID,
Description: fmt.Sprintf("%s's Token", u.Name),
OrgID: o.ID,
Permissions: platform.OperPermissions(),
Permissions: perms,
}
if err = c.CreateAuthorization(ctx, auth); err != nil {
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)
}

View File

@ -92,11 +92,24 @@ func (s *Service) Generate(ctx context.Context, req *platform.OnboardingRequest)
if err = s.CreateBucket(ctx, bucket); err != nil {
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{
UserID: u.ID,
Description: fmt.Sprintf("%s's Token", u.Name),
OrgID: o.ID,
Permissions: platform.OperPermissions(),
Permissions: perms,
}
if err = s.CreateAuthorization(ctx, auth); err != nil {
return nil, err

View File

@ -48,7 +48,7 @@ func (s *Session) Allowed(p Permission) bool {
return false
}
return allowed(p, s.Permissions)
return PermissionAllowed(p, s.Permissions)
}
// 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 {
p, err := platform.NewPermissionAtID(t.ID, platform.WriteAction, platform.TasksResource)
p, err := platform.NewPermissionAtID(t.Organization, platform.WriteAction, platform.TasksResource)
if err != nil {
return err
}

View File

@ -170,7 +170,7 @@ func Generate(
UserID: MustIDBase16(oneID),
Description: "admin's Token",
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 (
oneID = "020f755c3c082000"
twoID = "020f755c3c082001"

View File

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