mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-03 16:59:22 +02:00
authenticate/proxy: add user impersonation, refresh, dashboard (#123)
proxy: Add user dashboard. [GH-123] proxy/authenticate: Add manual refresh of their session. [GH-73] authorize: Add administrator (super user) account support. [GH-110] internal/policy: Allow administrators to impersonate other users. [GH-110]
This commit is contained in:
parent
dc2eb9668c
commit
66b4c2d3cd
42 changed files with 1644 additions and 1006 deletions
|
@ -49,17 +49,17 @@ func New(opts *config.Options) (*Authorize, error) {
|
|||
|
||||
return &Authorize{
|
||||
SharedKey: string(sharedKey),
|
||||
identityAccess: NewIdentityWhitelist(opts.Policies),
|
||||
identityAccess: NewIdentityWhitelist(opts.Policies, opts.Administrators),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewIdentityWhitelist returns an indentity validator.
|
||||
// todo(bdd) : a radix-tree implementation is probably more efficient
|
||||
func NewIdentityWhitelist(policies []policy.Policy, admins []string) IdentityValidator {
|
||||
return newIdentityWhitelistMap(policies, admins)
|
||||
}
|
||||
|
||||
// ValidIdentity returns if an identity is authorized to access a route resource.
|
||||
func (a *Authorize) ValidIdentity(route string, identity *Identity) bool {
|
||||
return a.identityAccess.Valid(route, identity)
|
||||
}
|
||||
|
||||
// NewIdentityWhitelist returns an indentity validator.
|
||||
// todo(bdd) : a radix-tree implementation is probably more efficient
|
||||
func NewIdentityWhitelist(policies []policy.Policy) IdentityValidator {
|
||||
return newIdentityWhitelistMap(policies)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,24 @@ import (
|
|||
|
||||
// Authorize validates the user identity, device, and context of a request for
|
||||
// a given route. Currently only checks identity.
|
||||
func (a *Authorize) Authorize(ctx context.Context, in *pb.AuthorizeRequest) (*pb.AuthorizeReply, error) {
|
||||
ok := a.ValidIdentity(in.Route, &Identity{in.User, in.Email, in.Groups})
|
||||
func (a *Authorize) Authorize(ctx context.Context, in *pb.Identity) (*pb.AuthorizeReply, error) {
|
||||
ok := a.ValidIdentity(in.Route,
|
||||
&Identity{
|
||||
User: in.User,
|
||||
Email: in.Email,
|
||||
Groups: in.Groups,
|
||||
ImpersonateEmail: in.ImpersonateEmail,
|
||||
ImpersonateGroups: in.ImpersonateGroups,
|
||||
})
|
||||
return &pb.AuthorizeReply{IsValid: ok}, nil
|
||||
}
|
||||
|
||||
// IsAdmin validates the user is an administrative user.
|
||||
func (a *Authorize) IsAdmin(ctx context.Context, in *pb.Identity) (*pb.IsAdminReply, error) {
|
||||
ok := a.identityAccess.IsAdmin(
|
||||
&Identity{
|
||||
Email: in.Email,
|
||||
Groups: in.Groups,
|
||||
})
|
||||
return &pb.IsAdminReply{IsAdmin: ok}, nil
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@ func TestAuthorize_Authorize(t *testing.T) {
|
|||
name string
|
||||
SharedKey string
|
||||
identityAccess IdentityValidator
|
||||
in *pb.AuthorizeRequest
|
||||
in *pb.Identity
|
||||
want *pb.AuthorizeReply
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid authorization request", "gXK6ggrlIW2HyKyUF9rUO4azrDgxhDPWqw9y+lJU7B8=", &MockIdentityValidator{ValidResponse: true}, &pb.AuthorizeRequest{Route: "http://pomerium.io", User: "user@pomerium.io"}, &pb.AuthorizeReply{IsValid: true}, false},
|
||||
{"invalid authorization request", "gXK6ggrlIW2HyKyUF9rUO4azrDgxhDPWqw9y+lJU7B8=", &MockIdentityValidator{ValidResponse: false}, &pb.AuthorizeRequest{Route: "http://pomerium.io", User: "user@pomerium.io"}, &pb.AuthorizeReply{IsValid: false}, false},
|
||||
{"valid authorization request", "gXK6ggrlIW2HyKyUF9rUO4azrDgxhDPWqw9y+lJU7B8=", &MockIdentityValidator{ValidResponse: true}, &pb.Identity{Route: "http://pomerium.io", User: "user@pomerium.io"}, &pb.AuthorizeReply{IsValid: true}, false},
|
||||
{"invalid authorization request", "gXK6ggrlIW2HyKyUF9rUO4azrDgxhDPWqw9y+lJU7B8=", &MockIdentityValidator{ValidResponse: false}, &pb.Identity{Route: "http://pomerium.io", User: "user@pomerium.io"}, &pb.AuthorizeReply{IsValid: false}, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -37,3 +37,33 @@ func TestAuthorize_Authorize(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthorize_IsAdmin(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
identityAccess IdentityValidator
|
||||
in *pb.Identity
|
||||
want *pb.IsAdminReply
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid authorization request", &MockIdentityValidator{IsAdminResponse: true}, &pb.Identity{Route: "http://pomerium.io", User: "user@pomerium.io"}, &pb.IsAdminReply{IsAdmin: true}, false},
|
||||
{"invalid authorization request", &MockIdentityValidator{IsAdminResponse: false}, &pb.Identity{Route: "http://pomerium.io", User: "user@pomerium.io"}, &pb.IsAdminReply{IsAdmin: false}, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &Authorize{
|
||||
SharedKey: "gXK6ggrlIW2HyKyUF9rUO4azrDgxhDPWqw9y",
|
||||
identityAccess: tt.identityAccess,
|
||||
}
|
||||
got, err := a.IsAdmin(context.Background(), tt.in)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Authorize.IsAdmin() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Authorize.IsAdmin() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,26 @@ type Identity struct {
|
|||
User string
|
||||
Email string
|
||||
Groups []string
|
||||
// Impersonation
|
||||
ImpersonateEmail string
|
||||
ImpersonateGroups []string
|
||||
}
|
||||
|
||||
// EmailDomain returns the domain of the identity's email.
|
||||
func (i *Identity) EmailDomain() string {
|
||||
if i.Email == "" {
|
||||
// IsImpersonating returns whether the user is trying to impersonate another
|
||||
// user email or group.
|
||||
func (i *Identity) IsImpersonating() bool {
|
||||
if i.ImpersonateEmail != "" || len(i.ImpersonateGroups) != 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// EmailDomain returns the domain portion of an email.
|
||||
func EmailDomain(email string) string {
|
||||
if email == "" {
|
||||
return ""
|
||||
}
|
||||
comp := strings.Split(i.Email, "@")
|
||||
comp := strings.Split(email, "@")
|
||||
if len(comp) != 2 || comp[0] == "" {
|
||||
return ""
|
||||
}
|
||||
|
@ -32,96 +44,141 @@ func (i *Identity) EmailDomain() string {
|
|||
// to a given route.
|
||||
type IdentityValidator interface {
|
||||
Valid(string, *Identity) bool
|
||||
IsAdmin(*Identity) bool
|
||||
}
|
||||
|
||||
type identityWhitelist struct {
|
||||
type whitelist struct {
|
||||
sync.RWMutex
|
||||
m map[string]bool
|
||||
access map[string]bool
|
||||
admins map[string]bool
|
||||
}
|
||||
|
||||
// newIdentityWhitelistMap takes a slice of policies and creates a hashmap of identity
|
||||
// authorizations per-route for each allowed group, domain, and email.
|
||||
func newIdentityWhitelistMap(policies []policy.Policy) *identityWhitelist {
|
||||
var im identityWhitelist
|
||||
im.m = make(map[string]bool, len(policies)*3)
|
||||
func newIdentityWhitelistMap(policies []policy.Policy, admins []string) *whitelist {
|
||||
var wl whitelist
|
||||
wl.access = make(map[string]bool, len(policies)*3)
|
||||
for _, p := range policies {
|
||||
for _, group := range p.AllowedGroups {
|
||||
wl.PutGroup(p.From, group)
|
||||
log.Debug().Str("route", p.From).Str("group", group).Msg("add group")
|
||||
im.PutGroup(p.From, group)
|
||||
}
|
||||
for _, domain := range p.AllowedDomains {
|
||||
im.PutDomain(p.From, domain)
|
||||
log.Debug().Str("route", p.From).Str("group", domain).Msg("add domain")
|
||||
|
||||
wl.PutDomain(p.From, domain)
|
||||
log.Debug().Str("route", p.From).Str("domain", domain).Msg("add domain")
|
||||
}
|
||||
for _, email := range p.AllowedEmails {
|
||||
im.PutEmail(p.From, email)
|
||||
log.Debug().Str("route", p.From).Str("group", email).Msg("add email")
|
||||
wl.PutEmail(p.From, email)
|
||||
log.Debug().Str("route", p.From).Str("email", email).Msg("add email")
|
||||
}
|
||||
}
|
||||
return &im
|
||||
|
||||
wl.admins = make(map[string]bool, len(admins))
|
||||
for _, admin := range admins {
|
||||
wl.PutAdmin(admin)
|
||||
log.Debug().Str("admin", admin).Msg("add administrator")
|
||||
}
|
||||
return &wl
|
||||
}
|
||||
|
||||
// Valid reports whether an identity has valid access for a given route.
|
||||
func (m *identityWhitelist) Valid(route string, i *Identity) bool {
|
||||
if ok := m.Domain(route, i.EmailDomain()); ok {
|
||||
func (wl *whitelist) Valid(route string, i *Identity) bool {
|
||||
email := i.Email
|
||||
domain := EmailDomain(email)
|
||||
groups := i.Groups
|
||||
|
||||
// if user is admin, and wants to impersonate, override values
|
||||
if wl.IsAdmin(i) && i.IsImpersonating() {
|
||||
email = i.ImpersonateEmail
|
||||
domain = EmailDomain(email)
|
||||
groups = i.ImpersonateGroups
|
||||
}
|
||||
|
||||
if ok := wl.Email(route, email); ok {
|
||||
return ok
|
||||
}
|
||||
if ok := m.Email(route, i.Email); ok {
|
||||
if ok := wl.Domain(route, domain); ok {
|
||||
return ok
|
||||
}
|
||||
for _, group := range i.Groups {
|
||||
if ok := m.Group(route, group); ok {
|
||||
for _, group := range groups {
|
||||
if ok := wl.Group(route, group); ok {
|
||||
return ok
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (wl *whitelist) IsAdmin(i *Identity) bool {
|
||||
if ok := wl.Admin(i.Email); ok {
|
||||
return ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Group retrieves per-route access given a group name.
|
||||
func (m *identityWhitelist) Group(route, group string) bool {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
return m.m[fmt.Sprintf("%s|group:%s", route, group)]
|
||||
func (wl *whitelist) Group(route, group string) bool {
|
||||
wl.RLock()
|
||||
defer wl.RUnlock()
|
||||
return wl.access[fmt.Sprintf("%s|group:%s", route, group)]
|
||||
}
|
||||
|
||||
// PutGroup adds an access entry for a route given a group name.
|
||||
func (m *identityWhitelist) PutGroup(route, group string) {
|
||||
m.Lock()
|
||||
m.m[fmt.Sprintf("%s|group:%s", route, group)] = true
|
||||
m.Unlock()
|
||||
func (wl *whitelist) PutGroup(route, group string) {
|
||||
wl.Lock()
|
||||
wl.access[fmt.Sprintf("%s|group:%s", route, group)] = true
|
||||
wl.Unlock()
|
||||
}
|
||||
|
||||
// Domain retrieves per-route access given a domain name.
|
||||
func (m *identityWhitelist) Domain(route, domain string) bool {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
return m.m[fmt.Sprintf("%s|domain:%s", route, domain)]
|
||||
func (wl *whitelist) Domain(route, domain string) bool {
|
||||
wl.RLock()
|
||||
defer wl.RUnlock()
|
||||
return wl.access[fmt.Sprintf("%s|domain:%s", route, domain)]
|
||||
}
|
||||
|
||||
// PutDomain adds an access entry for a route given a domain name.
|
||||
func (m *identityWhitelist) PutDomain(route, domain string) {
|
||||
m.Lock()
|
||||
m.m[fmt.Sprintf("%s|domain:%s", route, domain)] = true
|
||||
m.Unlock()
|
||||
func (wl *whitelist) PutDomain(route, domain string) {
|
||||
wl.Lock()
|
||||
wl.access[fmt.Sprintf("%s|domain:%s", route, domain)] = true
|
||||
wl.Unlock()
|
||||
}
|
||||
|
||||
// Email retrieves per-route access given a user's email.
|
||||
func (m *identityWhitelist) Email(route, email string) bool {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
return m.m[fmt.Sprintf("%s|email:%s", route, email)]
|
||||
func (wl *whitelist) Email(route, email string) bool {
|
||||
wl.RLock()
|
||||
defer wl.RUnlock()
|
||||
return wl.access[fmt.Sprintf("%s|email:%s", route, email)]
|
||||
}
|
||||
|
||||
// PutEmail adds an access entry for a route given a user's email.
|
||||
func (m *identityWhitelist) PutEmail(route, email string) {
|
||||
m.Lock()
|
||||
m.m[fmt.Sprintf("%s|email:%s", route, email)] = true
|
||||
m.Unlock()
|
||||
func (wl *whitelist) PutEmail(route, email string) {
|
||||
wl.Lock()
|
||||
wl.access[fmt.Sprintf("%s|email:%s", route, email)] = true
|
||||
wl.Unlock()
|
||||
}
|
||||
|
||||
// PutEmail adds an admin entry
|
||||
func (wl *whitelist) PutAdmin(admin string) {
|
||||
wl.Lock()
|
||||
wl.admins[admin] = true
|
||||
wl.Unlock()
|
||||
}
|
||||
|
||||
// Admin checks if the email matches an admin
|
||||
func (wl *whitelist) Admin(admin string) bool {
|
||||
wl.RLock()
|
||||
defer wl.RUnlock()
|
||||
return wl.admins[admin]
|
||||
}
|
||||
|
||||
// MockIdentityValidator is a mock implementation of IdentityValidator
|
||||
type MockIdentityValidator struct{ ValidResponse bool }
|
||||
type MockIdentityValidator struct {
|
||||
ValidResponse bool
|
||||
IsAdminResponse bool
|
||||
}
|
||||
|
||||
// Valid is a mock implementation IdentityValidator's Valid method
|
||||
// Valid is a mock implementation IdentityValidator's Valid method
|
||||
func (mv *MockIdentityValidator) Valid(u string, i *Identity) bool { return mv.ValidResponse }
|
||||
|
||||
// IsAdmin is a mock implementation IdentityValidator's IsAdmin method
|
||||
func (mv *MockIdentityValidator) IsAdmin(i *Identity) bool { return mv.IsAdminResponse }
|
||||
|
|
|
@ -21,8 +21,7 @@ func TestIdentity_EmailDomain(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
i := &Identity{Email: tt.Email}
|
||||
if got := i.EmailDomain(); got != tt.want {
|
||||
if got := EmailDomain(tt.Email); got != tt.want {
|
||||
t.Errorf("Identity.EmailDomain() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@ -36,25 +35,39 @@ func Test_IdentityWhitelistMap(t *testing.T) {
|
|||
policies []policy.Policy
|
||||
route string
|
||||
Identity *Identity
|
||||
admins []string
|
||||
want bool
|
||||
}{
|
||||
{"valid domain", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "user@example.com"}, true},
|
||||
{"invalid domain prepend", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "a@1example.com"}, false},
|
||||
{"invalid domain postpend", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "user@example.com2"}, false},
|
||||
{"valid group", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{"admin"}}, true},
|
||||
{"invalid group", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{"everyone"}}, false},
|
||||
{"invalid empty", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{""}}, false},
|
||||
{"valid group multiple", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{"everyone", "admin"}}, true},
|
||||
{"invalid group multiple", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{"everyones", "sadmin"}}, false},
|
||||
{"valid user email", []policy.Policy{{From: "example.com", AllowedEmails: []string{"user@example.com"}}}, "example.com", &Identity{Email: "user@example.com"}, true},
|
||||
{"invalid user email", []policy.Policy{{From: "example.com", AllowedEmails: []string{"user@example.com"}}}, "example.com", &Identity{Email: "user2@example.com"}, false},
|
||||
{"empty everything", []policy.Policy{{From: "example.com"}}, "example.com", &Identity{Email: "user2@example.com"}, false},
|
||||
{"valid domain", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "user@example.com"}, nil, true},
|
||||
{"valid domain with admins", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "user@example.com"}, []string{"admin@example.com"}, true},
|
||||
{"invalid domain prepend", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "a@1example.com"}, nil, false},
|
||||
{"invalid domain postpend", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "user@example.com2"}, nil, false},
|
||||
{"valid group", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{"admin"}}, nil, true},
|
||||
{"invalid group", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{"everyone"}}, nil, false},
|
||||
{"invalid empty", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{""}}, nil, false},
|
||||
{"valid group multiple", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{"everyone", "admin"}}, nil, true},
|
||||
{"invalid group multiple", []policy.Policy{{From: "example.com", AllowedGroups: []string{"admin"}}}, "example.com", &Identity{Email: "user@example.com", Groups: []string{"everyones", "sadmin"}}, nil, false},
|
||||
{"valid user email", []policy.Policy{{From: "example.com", AllowedEmails: []string{"user@example.com"}}}, "example.com", &Identity{Email: "user@example.com"}, nil, true},
|
||||
{"invalid user email", []policy.Policy{{From: "example.com", AllowedEmails: []string{"user@example.com"}}}, "example.com", &Identity{Email: "user2@example.com"}, nil, false},
|
||||
{"empty everything", []policy.Policy{{From: "example.com"}}, "example.com", &Identity{Email: "user2@example.com"}, nil, false},
|
||||
// impersonation related
|
||||
{"admin not impersonating allowed", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "admin@example.com"}, []string{"admin@example.com"}, true},
|
||||
{"admin not impersonating denied", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "admin@admin-domain.com"}, []string{"admin@admin-domain.com"}, false},
|
||||
{"impersonating match domain", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "admin@admin-domain.com", ImpersonateEmail: "user@example.com"}, []string{"admin@admin-domain.com"}, true},
|
||||
{"impersonating does not match domain", []policy.Policy{{From: "example.com", AllowedDomains: []string{"example.com"}}}, "example.com", &Identity{Email: "admin@admin-domain.com", ImpersonateEmail: "user@not-example.com"}, []string{"admin@admin-domain.com"}, false},
|
||||
{"impersonating match email", []policy.Policy{{From: "example.com", AllowedEmails: []string{"user@example.com"}}}, "example.com", &Identity{Email: "admin@admin-domain.com", ImpersonateEmail: "user@example.com"}, []string{"admin@admin-domain.com"}, true},
|
||||
{"impersonating does not match email", []policy.Policy{{From: "example.com", AllowedEmails: []string{"user@example.com"}}}, "example.com", &Identity{Email: "admin@admin-domain.com", ImpersonateEmail: "user@not-example.com"}, []string{"admin@admin-domain.com"}, false},
|
||||
{"impersonating match groups", []policy.Policy{{From: "example.com", AllowedGroups: []string{"support"}}}, "example.com", &Identity{Email: "admin@admin-domain.com", ImpersonateGroups: []string{"support"}}, []string{"admin@admin-domain.com"}, true},
|
||||
{"impersonating match many groups", []policy.Policy{{From: "example.com", AllowedGroups: []string{"support"}}}, "example.com", &Identity{Email: "admin@admin-domain.com", ImpersonateGroups: []string{"a", "b", "c", "support"}}, []string{"admin@admin-domain.com"}, true},
|
||||
{"impersonating does not match groups", []policy.Policy{{From: "example.com", AllowedGroups: []string{"support"}}}, "example.com", &Identity{Email: "admin@admin-domain.com", ImpersonateGroups: []string{"not support"}}, []string{"admin@admin-domain.com"}, false},
|
||||
{"impersonating does not match many groups", []policy.Policy{{From: "example.com", AllowedGroups: []string{"support"}}}, "example.com", &Identity{Email: "admin@admin-domain.com", ImpersonateGroups: []string{"not support", "b", "c"}}, []string{"admin@admin-domain.com"}, false},
|
||||
{"impersonating does not match empty groups", []policy.Policy{{From: "example.com", AllowedGroups: []string{"support"}}}, "example.com", &Identity{Email: "admin@admin-domain.com", ImpersonateGroups: []string{""}}, []string{"admin@admin-domain.com"}, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
wl := NewIdentityWhitelist(tt.policies)
|
||||
wl := NewIdentityWhitelist(tt.policies, tt.admins)
|
||||
if got := wl.Valid(tt.route, tt.Identity); got != tt.want {
|
||||
t.Errorf("IdentityACLMap.Allowed() = %v, want %v", got, tt.want)
|
||||
t.Errorf("wl.Valid() = %v, want %v", got, tt.want)
|
||||
}
|
||||
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue