Merge pull request #2367 from influxdata/fix/issue#2252
Add org admin and member specific permissionspull/10616/head
commit
394673c54b
2
auth.go
2
auth.go
|
@ -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.
|
||||||
|
|
62
authz.go
62
authz.go
|
@ -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
|
||||||
|
}
|
||||||
|
|
133
authz_test.go
133
authz_test.go
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue