fix(authorizer): fix auth for authorizations

pull/17383/head
Lorenzo Affetti 2020-03-20 18:40:30 +01:00
parent 1a0cb0b803
commit 77ae0eacb5
No known key found for this signature in database
GPG Key ID: 76FFBBDF6F0ADC4C
3 changed files with 292 additions and 151 deletions

View File

@ -28,11 +28,12 @@ func (s *AuthorizationService) FindAuthorizationByID(ctx context.Context, id inf
if err != nil {
return nil, err
}
if err := authorizeReadAuthorization(ctx, a.UserID); err != nil {
if _, _, err := AuthorizeRead(ctx, influxdb.AuthorizationsResourceType, a.ID, a.OrgID); err != nil {
return nil, err
}
if _, _, err := AuthorizeReadResource(ctx, influxdb.UsersResourceType, a.UserID); err != nil {
return nil, err
}
return a, nil
}
@ -42,11 +43,12 @@ func (s *AuthorizationService) FindAuthorizationByToken(ctx context.Context, t s
if err != nil {
return nil, err
}
if err := authorizeReadAuthorization(ctx, a.UserID); err != nil {
if _, _, err := AuthorizeRead(ctx, influxdb.AuthorizationsResourceType, a.ID, a.OrgID); err != nil {
return nil, err
}
if _, _, err := AuthorizeReadResource(ctx, influxdb.UsersResourceType, a.UserID); err != nil {
return nil, err
}
return a, nil
}
@ -58,36 +60,20 @@ func (s *AuthorizationService) FindAuthorizations(ctx context.Context, filter in
if err != nil {
return nil, 0, err
}
// This filters without allocating
// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
authorizations := as[:0]
for _, a := range as {
err := authorizeReadAuthorization(ctx, a.UserID)
if err != nil && influxdb.ErrorCode(err) != influxdb.EUnauthorized {
return nil, 0, err
}
if influxdb.ErrorCode(err) == influxdb.EUnauthorized {
continue
}
authorizations = append(authorizations, a)
}
return authorizations, len(authorizations), nil
return AuthorizeFindAuthorizations(ctx, as)
}
// CreateAuthorization checks to see if the authorizer on context has write access to the global authorizations resource.
func (s *AuthorizationService) CreateAuthorization(ctx context.Context, a *influxdb.Authorization) error {
if err := authorizeWriteAuthorization(ctx, a.UserID); err != nil {
if _, _, err := AuthorizeCreate(ctx, influxdb.AuthorizationsResourceType, a.OrgID); err != nil {
return err
}
if _, _, err := AuthorizeWriteResource(ctx, influxdb.UsersResourceType, a.UserID); err != nil {
return err
}
if err := VerifyPermissions(ctx, a.Permissions); err != nil {
return err
}
return s.s.CreateAuthorization(ctx, a)
}
@ -97,11 +83,12 @@ func (s *AuthorizationService) UpdateAuthorization(ctx context.Context, id influ
if err != nil {
return nil, err
}
if err := authorizeWriteAuthorization(ctx, a.UserID); err != nil {
if _, _, err := AuthorizeWrite(ctx, influxdb.AuthorizationsResourceType, a.ID, a.OrgID); err != nil {
return nil, err
}
if _, _, err := AuthorizeWriteResource(ctx, influxdb.UsersResourceType, a.UserID); err != nil {
return nil, err
}
return s.s.UpdateAuthorization(ctx, id, upd)
}
@ -111,11 +98,12 @@ func (s *AuthorizationService) DeleteAuthorization(ctx context.Context, id influ
if err != nil {
return err
}
if err := authorizeWriteAuthorization(ctx, a.UserID); err != nil {
if _, _, err := AuthorizeWrite(ctx, influxdb.AuthorizationsResourceType, a.ID, a.OrgID); err != nil {
return err
}
if _, _, err := AuthorizeWriteResource(ctx, influxdb.UsersResourceType, a.UserID); err != nil {
return err
}
return s.s.DeleteAuthorization(ctx, id)
}
@ -130,43 +118,5 @@ func VerifyPermissions(ctx context.Context, ps []influxdb.Permission) error {
}
}
}
return nil
}
func newAuthorizationPermission(a influxdb.Action, id influxdb.ID) (*influxdb.Permission, error) {
p := &influxdb.Permission{
Action: a,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: &id,
},
}
return p, p.Valid()
}
func authorizeReadAuthorization(ctx context.Context, id influxdb.ID) error {
p, err := newAuthorizationPermission(influxdb.ReadAction, id)
if err != nil {
return err
}
if err := IsAllowed(ctx, *p); err != nil {
return err
}
return nil
}
func authorizeWriteAuthorization(ctx context.Context, id influxdb.ID) error {
p, err := newAuthorizationPermission(influxdb.WriteAction, id)
if err != nil {
return err
}
if err := IsAllowed(ctx, *p); err != nil {
return err
}
return nil
}

View File

@ -28,12 +28,8 @@ var authorizationCmpOptions = cmp.Options{
}
func TestAuthorizationService_ReadAuthorization(t *testing.T) {
type fields struct {
AuthorizationService influxdb.AuthorizationService
}
type args struct {
permission influxdb.Permission
id influxdb.ID
permissions []influxdb.Permission
}
type wants struct {
err error
@ -41,32 +37,29 @@ func TestAuthorizationService_ReadAuthorization(t *testing.T) {
}
tests := []struct {
name string
fields fields
args args
wants wants
name string
args args
wants wants
}{
{
name: "authorized to access id",
fields: fields{
AuthorizationService: &mock.AuthorizationService{
FindAuthorizationByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.Authorization, error) {
return &influxdb.Authorization{
ID: id,
UserID: 1,
}, nil
},
},
},
args: args{
permission: influxdb.Permission{
Action: "read",
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(1),
permissions: []influxdb.Permission{
{
Action: influxdb.ReadAction,
Resource: influxdb.Resource{
Type: influxdb.AuthorizationsResourceType,
OrgID: influxdbtesting.IDPtr(1),
},
},
{
Action: influxdb.ReadAction,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(1),
},
},
},
id: 1,
},
wants: wants{
err: nil,
@ -74,31 +67,58 @@ func TestAuthorizationService_ReadAuthorization(t *testing.T) {
{
ID: 10,
UserID: 1,
OrgID: 1,
},
},
},
},
{
name: "unauthorized to access id",
fields: fields{
AuthorizationService: &mock.AuthorizationService{
FindAuthorizationByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.Authorization, error) {
return &influxdb.Authorization{
ID: id,
UserID: 1,
}, nil
name: "unauthorized to access id - wrong org",
args: args{
permissions: []influxdb.Permission{
{
Action: influxdb.ReadAction,
Resource: influxdb.Resource{
Type: influxdb.AuthorizationsResourceType,
OrgID: influxdbtesting.IDPtr(2),
},
},
{
Action: influxdb.ReadAction,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(1),
},
},
},
},
wants: wants{
err: &influxdb.Error{
Msg: "read:orgs/0000000000000001/authorizations/000000000000000a is unauthorized",
Code: influxdb.EUnauthorized,
},
authorizations: []*influxdb.Authorization{},
},
},
{
name: "unauthorized to access id - wrong user",
args: args{
permission: influxdb.Permission{
Action: "read",
Resource: influxdb.Resource{
Type: influxdb.BucketsResourceType,
ID: influxdbtesting.IDPtr(20),
permissions: []influxdb.Permission{
{
Action: influxdb.ReadAction,
Resource: influxdb.Resource{
Type: influxdb.AuthorizationsResourceType,
OrgID: influxdbtesting.IDPtr(1),
},
},
{
Action: influxdb.ReadAction,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(2),
},
},
},
id: 1,
},
wants: wants{
err: &influxdb.Error{
@ -117,12 +137,14 @@ func TestAuthorizationService_ReadAuthorization(t *testing.T) {
return &influxdb.Authorization{
ID: id,
UserID: 1,
OrgID: 1,
}, nil
}
m.FindAuthorizationByTokenFn = func(ctx context.Context, t string) (*influxdb.Authorization, error) {
return &influxdb.Authorization{
ID: 10,
UserID: 1,
OrgID: 1,
}, nil
}
m.FindAuthorizationsFn = func(ctx context.Context, filter influxdb.AuthorizationFilter, opt ...influxdb.FindOptions) ([]*influxdb.Authorization, int, error) {
@ -130,13 +152,14 @@ func TestAuthorizationService_ReadAuthorization(t *testing.T) {
{
ID: 10,
UserID: 1,
OrgID: 1,
},
}, 1, nil
}
s := authorizer.NewAuthorizationService(m)
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}})
ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions})
t.Run("find authorization by id", func(t *testing.T) {
_, err := s.FindAuthorizationByID(ctx, 10)
@ -161,39 +184,35 @@ func TestAuthorizationService_ReadAuthorization(t *testing.T) {
}
func TestAuthorizationService_WriteAuthorization(t *testing.T) {
type fields struct {
AuthorizationService influxdb.AuthorizationService
}
type args struct {
permission influxdb.Permission
userID influxdb.ID
permissions []influxdb.Permission
}
type wants struct {
err error
}
tests := []struct {
name string
fields fields
args args
wants wants
name string
args args
wants wants
}{
{
name: "authorized to create authorization",
fields: fields{
AuthorizationService: &mock.AuthorizationService{
CreateAuthorizationFn: func(ctx context.Context, b *influxdb.Authorization) error {
return nil
},
},
},
name: "authorized to write authorization",
args: args{
userID: 1,
permission: influxdb.Permission{
Action: "write",
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(1),
permissions: []influxdb.Permission{
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.AuthorizationsResourceType,
OrgID: influxdbtesting.IDPtr(1),
},
},
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(1),
},
},
},
},
@ -202,21 +221,49 @@ func TestAuthorizationService_WriteAuthorization(t *testing.T) {
},
},
{
name: "unauthorized to create authorization",
fields: fields{
AuthorizationService: &mock.AuthorizationService{
CreateAuthorizationFn: func(ctx context.Context, b *influxdb.Authorization) error {
return nil
name: "unauthorized to write authorization - wrong org",
args: args{
permissions: []influxdb.Permission{
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.AuthorizationsResourceType,
OrgID: influxdbtesting.IDPtr(2),
},
},
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(1),
},
},
},
},
wants: wants{
err: &influxdb.Error{
Msg: "write:orgs/0000000000000001/authorizations/000000000000000a is unauthorized",
Code: influxdb.EUnauthorized,
},
},
},
{
name: "unauthorized to write authorization - wrong user",
args: args{
userID: 1,
permission: influxdb.Permission{
Action: "write",
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(10),
permissions: []influxdb.Permission{
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.AuthorizationsResourceType,
OrgID: influxdbtesting.IDPtr(1),
},
},
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(2),
},
},
},
},
@ -236,6 +283,7 @@ func TestAuthorizationService_WriteAuthorization(t *testing.T) {
return &influxdb.Authorization{
ID: id,
UserID: 1,
OrgID: 1,
}, nil
}
m.CreateAuthorizationFn = func(ctx context.Context, a *influxdb.Authorization) error {
@ -250,12 +298,7 @@ func TestAuthorizationService_WriteAuthorization(t *testing.T) {
s := authorizer.NewAuthorizationService(m)
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}})
t.Run("create authorization", func(t *testing.T) {
err := s.CreateAuthorization(ctx, &influxdb.Authorization{UserID: tt.args.userID})
influxdbtesting.ErrorsEqual(t, err, tt.wants.err)
})
ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions})
t.Run("update authorization", func(t *testing.T) {
_, err := s.UpdateAuthorization(ctx, 10, &influxdb.AuthorizationUpdate{Status: influxdb.Active.Ptr()})
@ -270,3 +313,126 @@ func TestAuthorizationService_WriteAuthorization(t *testing.T) {
})
}
}
func TestAuthorizationService_CreateAuthorization(t *testing.T) {
type args struct {
permissions []influxdb.Permission
}
type wants struct {
err error
}
tests := []struct {
name string
args args
wants wants
}{
{
name: "authorized to write authorization",
args: args{
permissions: []influxdb.Permission{
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.AuthorizationsResourceType,
OrgID: influxdbtesting.IDPtr(1),
},
},
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(1),
},
},
},
},
wants: wants{
err: nil,
},
},
{
name: "unauthorized to write authorization - wrong org",
args: args{
permissions: []influxdb.Permission{
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.AuthorizationsResourceType,
OrgID: influxdbtesting.IDPtr(2),
},
},
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(1),
},
},
},
},
wants: wants{
err: &influxdb.Error{
Msg: "write:orgs/0000000000000001/authorizations is unauthorized",
Code: influxdb.EUnauthorized,
},
},
},
{
name: "unauthorized to write authorization - wrong user",
args: args{
permissions: []influxdb.Permission{
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.AuthorizationsResourceType,
OrgID: influxdbtesting.IDPtr(1),
},
},
{
Action: influxdb.WriteAction,
Resource: influxdb.Resource{
Type: influxdb.UsersResourceType,
ID: influxdbtesting.IDPtr(2),
},
},
},
},
wants: wants{
err: &influxdb.Error{
Msg: "write:users/0000000000000001 is unauthorized",
Code: influxdb.EUnauthorized,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &mock.AuthorizationService{}
m.FindAuthorizationByIDFn = func(ctx context.Context, id influxdb.ID) (*influxdb.Authorization, error) {
return &influxdb.Authorization{
ID: id,
UserID: 1,
OrgID: 1,
}, nil
}
m.CreateAuthorizationFn = func(ctx context.Context, a *influxdb.Authorization) error {
return nil
}
m.DeleteAuthorizationFn = func(ctx context.Context, id influxdb.ID) error {
return nil
}
m.UpdateAuthorizationFn = func(ctx context.Context, id influxdb.ID, upd *influxdb.AuthorizationUpdate) (*influxdb.Authorization, error) {
return nil, nil
}
s := authorizer.NewAuthorizationService(m)
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{tt.args.permissions})
err := s.CreateAuthorization(ctx, &influxdb.Authorization{OrgID: 1, UserID: 1})
influxdbtesting.ErrorsEqual(t, err, tt.wants.err)
})
}
}

View File

@ -6,6 +6,31 @@ import (
"github.com/influxdata/influxdb"
)
// AuthorizeFindAuthorizations takes the given items and returns only the ones that the user is authorized to read.
func AuthorizeFindAuthorizations(ctx context.Context, rs []*influxdb.Authorization) ([]*influxdb.Authorization, int, error) {
// This filters without allocating
// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
rrs := rs[:0]
for _, r := range rs {
_, _, err := AuthorizeRead(ctx, influxdb.AuthorizationsResourceType, r.ID, r.OrgID)
if err != nil && influxdb.ErrorCode(err) != influxdb.EUnauthorized {
return nil, 0, err
}
if influxdb.ErrorCode(err) == influxdb.EUnauthorized {
continue
}
_, _, err = AuthorizeReadResource(ctx, influxdb.UsersResourceType, r.UserID)
if err != nil && influxdb.ErrorCode(err) != influxdb.EUnauthorized {
return nil, 0, err
}
if influxdb.ErrorCode(err) == influxdb.EUnauthorized {
continue
}
rrs = append(rrs, r)
}
return rrs, len(rrs), nil
}
// AuthorizeFindBuckets takes the given items and returns only the ones that the user is authorized to read.
func AuthorizeFindBuckets(ctx context.Context, rs []*influxdb.Bucket) ([]*influxdb.Bucket, int, error) {
// This filters without allocating