Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions api/types/accesslist/accesslist.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,22 @@ type Owner struct {
MembershipKind string `json:"membership_kind" yaml:"membership_kind"`
}

// IsMembershipKindUser returns true if the owner is of kind user.
// All types expect "MEMBERSHIP_KIND_LIST" are treated as "MEMBERSHIP_KIND_USER".
func (o *Owner) IsMembershipKindUser() bool {
return isMembershipKindUser(o.MembershipKind)
}

func isMembershipKindUser(membershipKind string) bool {
switch membershipKind {
case MembershipKindUnspecified, MembershipKindUser, "":
return true
default:
// In case if MembershipKind was extended.
return false
}
}

// Audit describes the audit configuration for an access list.
type Audit struct {
// NextAuditDate is the date that the next audit should be performed.
Expand Down
6 changes: 6 additions & 0 deletions api/types/accesslist/member.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,9 @@ func (a *AccessListMember) Clone() *AccessListMember {
func (a *AccessListMember) IsExpired(t time.Time) bool {
return !a.Spec.Expires.IsZero() && !t.Before(a.Spec.Expires)
}

// IsUser returns true if the membership kind is User
// All types expect "MEMBERSHIP_KIND_LIST" are treated as "MEMBERSHIP_KIND_USER".
func (a *AccessListMember) IsUser() bool {
return isMembershipKindUser(a.Spec.MembershipKind)
}
10 changes: 10 additions & 0 deletions lib/accesslists/hierarchy.go
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,11 @@ func (s *Hierarchy) validMembership(ctx context.Context, list *accesslist.Access
}
return false, trace.Wrap(err)
}
// Only user membership are valid. It can happen that username overlaps with the access list name.
// So we need to ensure the membership kind always is verified.
if !m.IsUser() {
return false, nil
}
if m.IsExpired(s.Clock.Now()) || !UserMeetsRequirements(user, list.GetMembershipRequires()) {
return false, nil
}
Expand Down Expand Up @@ -620,6 +625,11 @@ func (s *Hierarchy) validDirectOwner(user types.User, acl *accesslist.AccessList
return false
}
for _, v := range acl.Spec.Owners {
// Only user membership are valid. It can happen that username overlaps with the access list name.
// So we need to ensure the membership kind is verified as user.
if !v.IsMembershipKindUser() {
continue
}
if v.Name == user.GetName() {
return true
}
Expand Down
22 changes: 22 additions & 0 deletions lib/accesslists/hierarchy_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,28 @@ func TestGetHierarchyForUser(t *testing.T) {
kind: accesslists.RelationshipKindOwner,
want: []string{"level2", "root"},
},
{
name: "user is excluded from owners when user is not an owner and username overlaps with owning Access List name",
state: state{
mustMakeAccessList("root", withOwnerList("level1")): {},
mustMakeAccessList("level1"): {},
},
user: makeUser("level1"),
start: "root",
kind: accesslists.RelationshipKindOwner,
want: nil,
},
{
name: "member/access list name and username overlaps",
state: state{
mustMakeAccessList("root"): {mustCreateMember("level1", withACLMemKind())},
mustMakeAccessList("level1"): {},
},
user: makeUser("level1"),
start: "root",
kind: accesslists.RelationshipKindMember,
want: nil,
},
}

for _, tt := range tests {
Expand Down
Loading