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)
		return out, false, err
	}
	u, err := s.CreateUser(user)
	return u, true, err
}
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)
package auth
import (
	"encoding/json"
	"fmt"
	"net/http"
	"path"
	"reflect"
	"sort"
	"strings"
	"time"
	etcderr "github.com/coreos/etcd/error"
	"github.com/coreos/etcd/etcdserver"
	"github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/pkg/types"
	"github.com/coreos/pkg/capnslog"
	"golang.org/x/crypto/bcrypt"
	"golang.org/x/net/context"
)
const (
	StorePermsPrefix = "/2"
	RootRoleName = "root"
	GuestRoleName = "guest"
)
var (
	plog = capnslog.NewPackageLogger("github.com/coreos/etcd/etcdserver", "auth")
)
var rootRole = Role{
	Role: RootRoleName,
	Permissions: Permissions{
		KV: RWPermission{
			Read:  []string{"/*"},
			Write: []string{"/*"},
		},
	},
}
var guestRole = Role{
	Role: GuestRoleName,
	Permissions: Permissions{
		KV: RWPermission{
			Read:  []string{"/*"},
			Write: []string{"/*"},
		},
	},
}
type doer interface {
	Do(context.Context, etcdserverpb.Request) (etcdserver.Response, error)
}
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
	PasswordStore
}
type PasswordStore interface {
	CheckPassword(user User, password string) bool
	HashPassword(password string) (string, error)
}
type store struct {
	server      doer
	timeout     time.Duration
	ensuredOnce bool
	PasswordStore
}
type User struct {
	User     string   `json:"user"`
	Password string   `json:"password,omitempty"`
	Roles    []string `json:"roles"`
	Grant    []string `json:"grant,omitempty"`
	Revoke   []string `json:"revoke,omitempty"`
}
type Role struct {
	Role        string       `json:"role"`
	Permissions Permissions  `json:"permissions"`
	Grant       *Permissions `json:"grant,omitempty"`
	Revoke      *Permissions `json:"revoke,omitempty"`
}
type Permissions struct {
	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 {
	Read  []string `json:"read"`
	Write []string `json:"write"`
}
type Error struct {
	Status int
	Errmsg string
}
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{Status: hs, Errmsg: fmt.Sprintf("auth: "+s, v...)}
}
func NewStore(server doer, timeout time.Duration) Store {
	s := &store{
		server:        server,
		timeout:       timeout,
		PasswordStore: passwordStore{},
	}
	return s
}
type passwordStore struct{}
func (_ passwordStore) CheckPassword(user User, password string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
	return err == nil
}
func (_ passwordStore) HashPassword(password string) (string, error) {
	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	return string(hash), err
}
func (s *store) AllUsers() ([]string, error) {
	resp, err := s.requestResource("/users/", false)
	if err != nil {
		if e, ok := err.(*etcderr.Error); ok {
			if e.ErrorCode == etcderr.EcodeKeyNotFound {
				return []string{}, nil
			}
		}
		return nil, err
	}
	var nodes []string
	for _, n := range resp.Event.Node.Nodes {
		_, user := path.Split(n.Key)
		nodes = append(nodes, user)
	}
	sort.Strings(nodes)
	return nodes, nil
}
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 {
			if e.ErrorCode == etcderr.EcodeKeyNotFound {
				return User{}, authErr(http.StatusNotFound, "User %s does not exist.", name)
			}
		}
		return User{}, err
	}
	var u User
	err = json.Unmarshal([]byte(*resp.Event.Node.Value), &u)
	if err != nil {
		return u, err
	}
	if u.User == "root" {
		u = attachRootRole(u)
	}
	return u, nil
}