etcd/etcdserver/security/security_test.go

270 lines
6.5 KiB
Go

// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package security
import (
"reflect"
"testing"
"time"
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/crypto/bcrypt"
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
"github.com/coreos/etcd/etcdserver"
"github.com/coreos/etcd/etcdserver/etcdserverpb"
"github.com/coreos/etcd/store"
)
func TestMergeUser(t *testing.T) {
tbl := []struct {
input User
merge User
expect User
iserr bool
}{
{
User{User: "foo"},
User{User: "bar"},
User{},
true,
},
{
User{User: "foo"},
User{User: "foo"},
User{User: "foo", Roles: []string{}},
false,
},
{
User{User: "foo"},
User{User: "foo", Grant: []string{"role1"}},
User{User: "foo", Roles: []string{"role1"}},
false,
},
{
User{User: "foo", Roles: []string{"role1"}},
User{User: "foo", Grant: []string{"role1"}},
User{},
true,
},
{
User{User: "foo", Roles: []string{"role1"}},
User{User: "foo", Revoke: []string{"role2"}},
User{},
true,
},
{
User{User: "foo", Roles: []string{"role1"}},
User{User: "foo", Grant: []string{"role2"}},
User{User: "foo", Roles: []string{"role1", "role2"}},
false,
},
{
User{User: "foo"},
User{User: "foo", Password: "bar"},
User{User: "foo", Roles: []string{}, Password: "$2a$10$aUPOdbOGNawaVSusg3g2wuC3AH6XxIr9/Ms4VgDvzrAVOJPYzZILa"},
false,
},
}
for i, tt := range tbl {
out, err := tt.input.Merge(tt.merge)
if err != nil && !tt.iserr {
t.Fatalf("Got unexpected error on item %d", i)
}
if !tt.iserr {
err := bcrypt.CompareHashAndPassword([]byte(out.Password), []byte(tt.merge.Password))
if err == nil {
tt.expect.Password = out.Password
}
if !reflect.DeepEqual(out, tt.expect) {
t.Errorf("Unequal merge expectation on item %d: got: %#v, expect: %#v", i, out, tt.expect)
}
}
}
}
func TestMergeRole(t *testing.T) {
tbl := []struct {
input Role
merge Role
expect Role
iserr bool
}{
{
Role{Role: "foo"},
Role{Role: "bar"},
Role{},
true,
},
{
Role{Role: "foo"},
Role{Role: "foo", Grant: Permissions{KV: rwPermission{Read: []string{"/foodir"}, Write: []string{"/foodir"}}}},
Role{Role: "foo", Permissions: Permissions{KV: rwPermission{Read: []string{"/foodir"}, Write: []string{"/foodir"}}}},
false,
},
{
Role{Role: "foo", Permissions: Permissions{KV: rwPermission{Read: []string{"/foodir"}, Write: []string{"/foodir"}}}},
Role{Role: "foo", Revoke: Permissions{KV: rwPermission{Read: []string{"/foodir"}, Write: []string{"/foodir"}}}},
Role{Role: "foo", Permissions: Permissions{KV: rwPermission{Read: []string{}, Write: []string{}}}},
false,
},
{
Role{Role: "foo", Permissions: Permissions{KV: rwPermission{Read: []string{"/bardir"}}}},
Role{Role: "foo", Revoke: Permissions{KV: rwPermission{Read: []string{"/foodir"}}}},
Role{},
true,
},
}
for i, tt := range tbl {
out, err := tt.input.Merge(tt.merge)
if err != nil && !tt.iserr {
t.Fatalf("Got unexpected error on item %d", i)
}
if !tt.iserr {
if !reflect.DeepEqual(out, tt.expect) {
t.Errorf("Unequal merge expectation on item %d: got: %#v, expect: %#v", i, out, tt.expect)
}
}
}
}
type testDoer struct {
get etcdserver.Response
}
func (td *testDoer) Do(_ context.Context, req etcdserverpb.Request) (etcdserver.Response, error) {
if req.Method == "GET" {
return td.get, nil
}
return etcdserver.Response{}, nil
}
func TestAllUsers(t *testing.T) {
d := &testDoer{
etcdserver.Response{
Event: &store.Event{
Action: store.Get,
Node: &store.NodeExtern{
Nodes: store.NodeExterns{
&store.NodeExtern{
Key: StorePermsPrefix + "/users/cat",
},
&store.NodeExtern{
Key: StorePermsPrefix + "/users/dog",
},
},
},
},
},
}
expected := []string{"cat", "dog"}
s := NewStore(d, time.Second)
users, err := s.AllUsers()
if err != nil {
t.Error("Unexpected error", err)
}
if !reflect.DeepEqual(users, expected) {
t.Error("AllUsers doesn't match given store. Got", users, "expected", expected)
}
}
func TestGetAndDeleteUser(t *testing.T) {
data := `{"user": "cat", "roles" : ["animal"]}`
d := &testDoer{
etcdserver.Response{
Event: &store.Event{
Action: store.Get,
Node: &store.NodeExtern{
Key: StorePermsPrefix + "/users/cat",
Value: &data,
},
},
},
}
expected := User{User: "cat", Roles: []string{"animal"}}
s := NewStore(d, time.Second)
out, err := s.GetUser("cat")
if err != nil {
t.Error("Unexpected error", err)
}
if !reflect.DeepEqual(out, expected) {
t.Error("GetUser doesn't match given store. Got", out, "expected", expected)
}
err = s.DeleteUser("cat")
if err != nil {
t.Error("Unexpected error", err)
}
}
func TestAllRoles(t *testing.T) {
d := &testDoer{
etcdserver.Response{
Event: &store.Event{
Action: store.Get,
Node: &store.NodeExtern{
Nodes: store.NodeExterns{
&store.NodeExtern{
Key: StorePermsPrefix + "/roles/animal",
},
&store.NodeExtern{
Key: StorePermsPrefix + "/roles/human",
},
},
},
},
},
}
expected := []string{"animal", "human"}
s := NewStore(d, time.Second)
out, err := s.AllRoles()
if err != nil {
t.Error("Unexpected error", err)
}
if !reflect.DeepEqual(out, expected) {
t.Error("AllUsers doesn't match given store. Got", out, "expected", expected)
}
}
func TestGetAndDeleteRole(t *testing.T) {
data := `{"role": "animal"}`
d := &testDoer{
etcdserver.Response{
Event: &store.Event{
Action: store.Get,
Node: &store.NodeExtern{
Key: StorePermsPrefix + "/roles/animal",
Value: &data,
},
},
},
}
expected := Role{Role: "animal"}
s := NewStore(d, time.Second)
out, err := s.GetRole("animal")
if err != nil {
t.Error("Unexpected error", err)
}
if !reflect.DeepEqual(out, expected) {
t.Error("GetRole doesn't match given store. Got", out, "expected", expected)
}
err = s.DeleteRole("animal")
if err != nil {
t.Error("Unexpected error", err)
}
}