etcdhttp: Improve test coverage surrounding auth

This commit is contained in:
Barak Michener
2015-07-01 15:10:16 -04:00
parent 219ed1695b
commit dd1a8fe330
6 changed files with 596 additions and 143 deletions

View File

@ -51,7 +51,7 @@ var (
var rootRole = Role{
Role: RootRoleName,
Permissions: Permissions{
KV: rwPermission{
KV: RWPermission{
Read: []string{"*"},
Write: []string{"*"},
},
@ -61,7 +61,7 @@ var rootRole = Role{
var guestRole = Role{
Role: GuestRoleName,
Permissions: Permissions{
KV: rwPermission{
KV: RWPermission{
Read: []string{"*"},
Write: []string{"*"},
},
@ -72,7 +72,24 @@ type doer interface {
Do(context.Context, etcdserverpb.Request) (etcdserver.Response, error)
}
type Store struct {
type Store interface {
AllUsers() ([]string, error)
GetUser(name string) (User, error)
CreateOrUpdateUser(user User) (out User, created bool, err error)
CreateUser(user User) (User, error)
DeleteUser(name string) error
UpdateUser(user User) (User, error)
AllRoles() ([]string, error)
GetRole(name string) (Role, error)
CreateRole(role Role) error
DeleteRole(name string) error
UpdateRole(role Role) (Role, error)
AuthEnabled() bool
EnableAuth() error
DisableAuth() error
}
type store struct {
server doer
timeout time.Duration
ensuredOnce bool
@ -94,39 +111,39 @@ type Role struct {
}
type Permissions struct {
KV rwPermission `json:"kv"`
KV RWPermission `json:"kv"`
}
func (p *Permissions) IsEmpty() bool {
return p == nil || (len(p.KV.Read) == 0 && len(p.KV.Write) == 0)
}
type rwPermission struct {
type RWPermission struct {
Read []string `json:"read"`
Write []string `json:"write"`
}
type Error struct {
httpStatus int
errmsg string
Status int
Errmsg string
}
func (ae Error) Error() string { return ae.errmsg }
func (ae Error) HTTPStatus() int { return ae.httpStatus }
func (ae Error) Error() string { return ae.Errmsg }
func (ae Error) HTTPStatus() int { return ae.Status }
func authErr(hs int, s string, v ...interface{}) Error {
return Error{httpStatus: hs, errmsg: fmt.Sprintf("auth: "+s, v...)}
return Error{Status: hs, Errmsg: fmt.Sprintf("auth: "+s, v...)}
}
func NewStore(server doer, timeout time.Duration) *Store {
s := &Store{
func NewStore(server doer, timeout time.Duration) Store {
s := &store{
server: server,
timeout: timeout,
}
return s
}
func (s *Store) AllUsers() ([]string, error) {
func (s *store) AllUsers() ([]string, error) {
resp, err := s.requestResource("/users/", false)
if err != nil {
if e, ok := err.(*etcderr.Error); ok {
@ -145,7 +162,7 @@ func (s *Store) AllUsers() ([]string, error) {
return nodes, nil
}
func (s *Store) GetUser(name string) (User, error) {
func (s *store) GetUser(name string) (User, error) {
resp, err := s.requestResource("/users/"+name, false)
if err != nil {
if e, ok := err.(*etcderr.Error); ok {
@ -170,7 +187,7 @@ func (s *Store) GetUser(name string) (User, error) {
// CreateOrUpdateUser should be only used for creating the new user or when you are not
// sure if it is a create or update. (When only password is passed in, we are not sure
// if it is a update or create)
func (s *Store) CreateOrUpdateUser(user User) (out User, created bool, err error) {
func (s *store) CreateOrUpdateUser(user User) (out User, created bool, err error) {
_, err = s.GetUser(user.User)
if err == nil {
out, err := s.UpdateUser(user)
@ -180,7 +197,7 @@ func (s *Store) CreateOrUpdateUser(user User) (out User, created bool, err error
return u, true, err
}
func (s *Store) CreateUser(user User) (User, error) {
func (s *store) CreateUser(user User) (User, error) {
// Attach root role to root user.
if user.User == "root" {
user = attachRootRole(user)
@ -192,7 +209,7 @@ func (s *Store) CreateUser(user User) (User, error) {
return u, err
}
func (s *Store) createUserInternal(user User) (User, error) {
func (s *store) createUserInternal(user User) (User, error) {
if user.Password == "" {
return user, authErr(http.StatusBadRequest, "Cannot create user %s with an empty password", user.User)
}
@ -213,7 +230,7 @@ func (s *Store) createUserInternal(user User) (User, error) {
return user, err
}
func (s *Store) DeleteUser(name string) error {
func (s *store) DeleteUser(name string) error {
if s.AuthEnabled() && name == "root" {
return authErr(http.StatusForbidden, "Cannot delete root user while auth is enabled.")
}
@ -230,7 +247,7 @@ func (s *Store) DeleteUser(name string) error {
return nil
}
func (s *Store) UpdateUser(user User) (User, error) {
func (s *store) UpdateUser(user User) (User, error) {
old, err := s.GetUser(user.User)
if err != nil {
if e, ok := err.(*etcderr.Error); ok {
@ -254,7 +271,7 @@ func (s *Store) UpdateUser(user User) (User, error) {
return newUser, err
}
func (s *Store) AllRoles() ([]string, error) {
func (s *store) AllRoles() ([]string, error) {
nodes := []string{RootRoleName}
resp, err := s.requestResource("/roles/", false)
if err != nil {
@ -273,7 +290,7 @@ func (s *Store) AllRoles() ([]string, error) {
return nodes, nil
}
func (s *Store) GetRole(name string) (Role, error) {
func (s *store) GetRole(name string) (Role, error) {
if name == RootRoleName {
return rootRole, nil
}
@ -295,7 +312,7 @@ func (s *Store) GetRole(name string) (Role, error) {
return r, nil
}
func (s *Store) CreateRole(role Role) error {
func (s *store) CreateRole(role Role) error {
if role.Role == RootRoleName {
return authErr(http.StatusForbidden, "Cannot modify role %s: is root role.", role.Role)
}
@ -313,7 +330,7 @@ func (s *Store) CreateRole(role Role) error {
return err
}
func (s *Store) DeleteRole(name string) error {
func (s *store) DeleteRole(name string) error {
if name == RootRoleName {
return authErr(http.StatusForbidden, "Cannot modify role %s: is root role.", name)
}
@ -331,7 +348,7 @@ func (s *Store) DeleteRole(name string) error {
return err
}
func (s *Store) UpdateRole(role Role) (Role, error) {
func (s *store) UpdateRole(role Role) (Role, error) {
if role.Role == RootRoleName {
return Role{}, authErr(http.StatusForbidden, "Cannot modify role %s: is root role.", role.Role)
}
@ -358,11 +375,11 @@ func (s *Store) UpdateRole(role Role) (Role, error) {
return newRole, err
}
func (s *Store) AuthEnabled() bool {
func (s *store) AuthEnabled() bool {
return s.detectAuth()
}
func (s *Store) EnableAuth() error {
func (s *store) EnableAuth() error {
if s.AuthEnabled() {
return authErr(http.StatusConflict, "already enabled")
}
@ -388,7 +405,7 @@ func (s *Store) EnableAuth() error {
return err
}
func (s *Store) DisableAuth() error {
func (s *store) DisableAuth() error {
if !s.AuthEnabled() {
return authErr(http.StatusConflict, "already disabled")
}
@ -505,8 +522,8 @@ func (p Permissions) Revoke(n *Permissions) (Permissions, error) {
// Grant adds a set of permissions to the permission object on which it is called,
// returning a new permission object.
func (rw rwPermission) Grant(n rwPermission) (rwPermission, error) {
var out rwPermission
func (rw RWPermission) Grant(n RWPermission) (RWPermission, error) {
var out RWPermission
currentRead := types.NewUnsafeSet(rw.Read...)
for _, r := range n.Read {
if currentRead.Contains(r) {
@ -530,8 +547,8 @@ func (rw rwPermission) Grant(n rwPermission) (rwPermission, error) {
// Revoke removes a set of permissions to the permission object on which it is called,
// returning a new permission object.
func (rw rwPermission) Revoke(n rwPermission) (rwPermission, error) {
var out rwPermission
func (rw RWPermission) Revoke(n RWPermission) (RWPermission, error) {
var out RWPermission
currentRead := types.NewUnsafeSet(rw.Read...)
for _, r := range n.Read {
if !currentRead.Contains(r) {
@ -555,7 +572,7 @@ func (rw rwPermission) Revoke(n rwPermission) (rwPermission, error) {
return out, nil
}
func (rw rwPermission) HasAccess(key string, write bool) bool {
func (rw RWPermission) HasAccess(key string, write bool) bool {
var list []string
if write {
list = rw.Write
@ -571,7 +588,7 @@ func (rw rwPermission) HasAccess(key string, write bool) bool {
return false
}
func (rw rwPermission) HasRecursiveAccess(key string, write bool) bool {
func (rw RWPermission) HasRecursiveAccess(key string, write bool) bool {
list := rw.Read
if write {
list = rw.Write