etcdhttp: fix access check for multiple roles in auth

Check access for multiple roles should go through all roles.
This commit is contained in:
Yicheng Qin 2015-08-04 14:07:39 -07:00
parent ff5c3469c1
commit 18169e896c
2 changed files with 101 additions and 48 deletions

View File

@ -97,9 +97,12 @@ func hasKeyPrefixAccess(sec auth.Store, r *http.Request, key string, recursive b
continue continue
} }
if recursive { if recursive {
return role.HasRecursiveAccess(key, writeAccess) if role.HasRecursiveAccess(key, writeAccess) {
return true
}
} else if role.HasKeyAccess(key, writeAccess) {
return true
} }
return role.HasKeyAccess(key, writeAccess)
} }
plog.Warningf("auth: invalid access for user %s on key %s.", username, key) plog.Warningf("auth: invalid access for user %s on key %s.", username, key)
return false return false

View File

@ -38,7 +38,7 @@ func mustJSONRequest(t *testing.T, method string, p string, body string) *http.R
type mockAuthStore struct { type mockAuthStore struct {
user *auth.User user *auth.User
role *auth.Role roles map[string]*auth.Role
err error err error
enabled bool enabled bool
} }
@ -59,13 +59,15 @@ func (s *mockAuthStore) UpdateUser(user auth.User) (auth.User, error) { return *
func (s *mockAuthStore) AllRoles() ([]string, error) { func (s *mockAuthStore) AllRoles() ([]string, error) {
return []string{"awesome", "guest", "root"}, s.err return []string{"awesome", "guest", "root"}, s.err
} }
func (s *mockAuthStore) GetRole(name string) (auth.Role, error) { return *s.role, s.err } func (s *mockAuthStore) GetRole(name string) (auth.Role, error) { return *s.roles[name], s.err }
func (s *mockAuthStore) CreateRole(role auth.Role) error { return s.err } func (s *mockAuthStore) CreateRole(role auth.Role) error { return s.err }
func (s *mockAuthStore) DeleteRole(name string) error { return s.err } func (s *mockAuthStore) DeleteRole(name string) error { return s.err }
func (s *mockAuthStore) UpdateRole(role auth.Role) (auth.Role, error) { return *s.role, s.err } func (s *mockAuthStore) UpdateRole(role auth.Role) (auth.Role, error) {
func (s *mockAuthStore) AuthEnabled() bool { return s.enabled } return *s.roles[role.Role], s.err
func (s *mockAuthStore) EnableAuth() error { return s.err } }
func (s *mockAuthStore) DisableAuth() error { return s.err } func (s *mockAuthStore) AuthEnabled() bool { return s.enabled }
func (s *mockAuthStore) EnableAuth() error { return s.err }
func (s *mockAuthStore) DisableAuth() error { return s.err }
func TestAuthFlow(t *testing.T) { func TestAuthFlow(t *testing.T) {
enableMapMu.Lock() enableMapMu.Lock()
@ -159,8 +161,10 @@ func TestAuthFlow(t *testing.T) {
{ {
req: mustJSONRequest(t, "GET", "roles/manager", ""), req: mustJSONRequest(t, "GET", "roles/manager", ""),
store: mockAuthStore{ store: mockAuthStore{
role: &auth.Role{ roles: map[string]*auth.Role{
Role: "manager", "manager": {
Role: "manager",
},
}, },
}, },
wcode: http.StatusOK, wcode: http.StatusOK,
@ -181,8 +185,10 @@ func TestAuthFlow(t *testing.T) {
{ {
req: mustJSONRequest(t, "PUT", "roles/manager", `{"role":"manager","revoke":{"kv":{"read":["foo"],"write":[]}}}`), req: mustJSONRequest(t, "PUT", "roles/manager", `{"role":"manager","revoke":{"kv":{"read":["foo"],"write":[]}}}`),
store: mockAuthStore{ store: mockAuthStore{
role: &auth.Role{ roles: map[string]*auth.Role{
Role: "manager", "manager": {
Role: "manager",
},
}, },
}, },
wcode: http.StatusOK, wcode: http.StatusOK,
@ -223,8 +229,10 @@ func TestAuthFlow(t *testing.T) {
Password: goodPassword, Password: goodPassword,
Roles: []string{"root"}, Roles: []string{"root"},
}, },
role: &auth.Role{ roles: map[string]*auth.Role{
Role: "root", "root": {
Role: "root",
},
}, },
}, },
wcode: http.StatusOK, wcode: http.StatusOK,
@ -279,8 +287,10 @@ func TestPrefixAccess(t *testing.T) {
Password: goodPassword, Password: goodPassword,
Roles: []string{"root"}, Roles: []string{"root"},
}, },
role: &auth.Role{ roles: map[string]*auth.Role{
Role: "root", "root": {
Role: "root",
},
}, },
enabled: true, enabled: true,
}, },
@ -297,12 +307,14 @@ func TestPrefixAccess(t *testing.T) {
Password: goodPassword, Password: goodPassword,
Roles: []string{"foorole"}, Roles: []string{"foorole"},
}, },
role: &auth.Role{ roles: map[string]*auth.Role{
Role: "foorole", "foorole": {
Permissions: auth.Permissions{ Role: "foorole",
KV: auth.RWPermission{ Permissions: auth.Permissions{
Read: []string{"/foo"}, KV: auth.RWPermission{
Write: []string{"/foo"}, Read: []string{"/foo"},
Write: []string{"/foo"},
},
}, },
}, },
}, },
@ -321,12 +333,14 @@ func TestPrefixAccess(t *testing.T) {
Password: goodPassword, Password: goodPassword,
Roles: []string{"foorole"}, Roles: []string{"foorole"},
}, },
role: &auth.Role{ roles: map[string]*auth.Role{
Role: "foorole", "foorole": {
Permissions: auth.Permissions{ Role: "foorole",
KV: auth.RWPermission{ Permissions: auth.Permissions{
Read: []string{"/foo*"}, KV: auth.RWPermission{
Write: []string{"/foo*"}, Read: []string{"/foo*"},
Write: []string{"/foo*"},
},
}, },
}, },
}, },
@ -345,12 +359,14 @@ func TestPrefixAccess(t *testing.T) {
Password: goodPassword, Password: goodPassword,
Roles: []string{"foorole"}, Roles: []string{"foorole"},
}, },
role: &auth.Role{ roles: map[string]*auth.Role{
Role: "foorole", "foorole": {
Permissions: auth.Permissions{ Role: "foorole",
KV: auth.RWPermission{ Permissions: auth.Permissions{
Read: []string{"/foo*"}, KV: auth.RWPermission{
Write: []string{"/foo*"}, Read: []string{"/foo*"},
Write: []string{"/foo*"},
},
}, },
}, },
}, },
@ -381,12 +397,14 @@ func TestPrefixAccess(t *testing.T) {
Password: goodPassword, Password: goodPassword,
Roles: []string{"foorole"}, Roles: []string{"foorole"},
}, },
role: &auth.Role{ roles: map[string]*auth.Role{
Role: "guest", "guest": {
Permissions: auth.Permissions{ Role: "guest",
KV: auth.RWPermission{ Permissions: auth.Permissions{
Read: []string{"/foo*"}, KV: auth.RWPermission{
Write: []string{"/foo*"}, Read: []string{"/foo*"},
Write: []string{"/foo*"},
},
}, },
}, },
}, },
@ -405,12 +423,14 @@ func TestPrefixAccess(t *testing.T) {
Password: goodPassword, Password: goodPassword,
Roles: []string{"foorole"}, Roles: []string{"foorole"},
}, },
role: &auth.Role{ roles: map[string]*auth.Role{
Role: "guest", "guest": {
Permissions: auth.Permissions{ Role: "guest",
KV: auth.RWPermission{ Permissions: auth.Permissions{
Read: []string{"/foo*"}, KV: auth.RWPermission{
Write: []string{"/foo*"}, Read: []string{"/foo*"},
Write: []string{"/foo*"},
},
}, },
}, },
}, },
@ -420,6 +440,36 @@ func TestPrefixAccess(t *testing.T) {
hasKeyPrefixAccess: false, hasKeyPrefixAccess: false,
hasRecursiveAccess: false, hasRecursiveAccess: false,
}, },
// check access for multiple roles
{
key: "/foo",
req: mustAuthRequest("GET", "user", "good"),
store: &mockAuthStore{
user: &auth.User{
User: "user",
Password: goodPassword,
Roles: []string{"role1", "role2"},
},
roles: map[string]*auth.Role{
"role1": {
Role: "role1",
},
"role2": {
Role: "role2",
Permissions: auth.Permissions{
KV: auth.RWPermission{
Read: []string{"/foo"},
Write: []string{"/foo"},
},
},
},
},
enabled: true,
},
hasRoot: false,
hasKeyPrefixAccess: true,
hasRecursiveAccess: false,
},
} }
for i, tt := range table { for i, tt := range table {