blob: 57662e3358f7b2300e7e19e0a6920e53558d5760 [file] [log] [blame]
// Copyright 2015 The LUCI Authors.
//
// 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 authdb
import (
"testing"
"go.chromium.org/luci/server/auth/service/protocol"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
func TestValidation(t *testing.T) {
t.Parallel()
validate := func(db *protocol.AuthDB) error {
_, err := NewSnapshotDB(db, "", 0, true)
return err
}
Convey("Works", t, func() {
So(validate(&protocol.AuthDB{}), ShouldBeNil)
So(validate(&protocol.AuthDB{
Groups: []*protocol.AuthGroup{
{Name: "group"},
},
IpWhitelists: []*protocol.AuthIPWhitelist{
{Name: "IP whitelist"},
},
}), ShouldBeNil)
})
Convey("Bad group", t, func() {
So(validate(&protocol.AuthDB{
Groups: []*protocol.AuthGroup{
{
Name: "group",
Members: []string{"bad identity"},
},
},
}), ShouldErrLike, "invalid identity")
})
Convey("Bad IP whitelist", t, func() {
So(validate(&protocol.AuthDB{
IpWhitelists: []*protocol.AuthIPWhitelist{
{
Name: "IP whitelist",
Subnets: []string{"not a subnet"},
},
},
}), ShouldErrLike, "bad IP whitlist")
})
Convey("Bad SecurityConfig", t, func() {
So(validate(&protocol.AuthDB{
SecurityConfig: []byte("not a serialized proto"),
}), ShouldErrLike, "failed to deserialize SecurityConfig")
})
}
func TestValidateAuthGroup(t *testing.T) {
t.Parallel()
Convey("validateAuthGroup works", t, func() {
groups := map[string]*protocol.AuthGroup{
"group1": {
Name: "group1",
Members: []string{"user:abc@example.com"},
Globs: []string{"service:*"},
Nested: []string{"group2"},
},
"group2": {
Name: "group2",
},
}
So(validateAuthGroup("group1", groups), ShouldBeNil)
})
Convey("validateAuthGroup bad identity", t, func() {
groups := map[string]*protocol.AuthGroup{
"group1": {
Name: "group1",
Members: []string{"blah"},
},
}
So(validateAuthGroup("group1", groups), ShouldErrLike, "invalid identity")
})
Convey("validateAuthGroup bad glob", t, func() {
groups := map[string]*protocol.AuthGroup{
"group1": {
Name: "group1",
Globs: []string{"blah"},
},
}
So(validateAuthGroup("group1", groups), ShouldErrLike, "invalid glob")
})
Convey("validateAuthGroup missing nested group", t, func() {
groups := map[string]*protocol.AuthGroup{
"group1": {
Name: "group1",
Nested: []string{"missing"},
},
}
So(validateAuthGroup("group1", groups), ShouldErrLike, "unknown nested group")
})
Convey("validateAuthGroup dependency cycle", t, func() {
groups := map[string]*protocol.AuthGroup{
"group1": {
Name: "group1",
Nested: []string{"group1"},
},
}
So(validateAuthGroup("group1", groups), ShouldErrLike, "dependency cycle found")
})
}
type groupGraph map[string][]string
func TestFindGroupCycle(t *testing.T) {
t.Parallel()
call := func(groups groupGraph) []string {
asProto := make(map[string]*protocol.AuthGroup)
for k, v := range groups {
asProto[k] = &protocol.AuthGroup{
Name: k,
Nested: v,
}
}
return findGroupCycle("start", asProto)
}
Convey("Empty", t, func() {
So(call(groupGraph{"start": nil}), ShouldBeEmpty)
})
Convey("No cycles", t, func() {
So(call(groupGraph{
"start": []string{"A"},
"A": []string{"B"},
"B": []string{"C"},
}), ShouldBeEmpty)
})
Convey("Self reference", t, func() {
So(call(groupGraph{
"start": []string{"start"},
}), ShouldResemble, []string{"start"})
})
Convey("Simple cycle", t, func() {
So(call(groupGraph{
"start": []string{"A"},
"A": []string{"start"},
}), ShouldResemble, []string{"start", "A"})
})
Convey("Long cycle", t, func() {
So(call(groupGraph{
"start": []string{"A"},
"A": []string{"B"},
"B": []string{"C"},
"C": []string{"start"},
}), ShouldResemble, []string{"start", "A", "B", "C"})
})
Convey("Diamond no cycles", t, func() {
So(call(groupGraph{
"start": []string{"A1", "A2"},
"A1": []string{"B"},
"A2": []string{"B"},
"B": nil,
}), ShouldBeEmpty)
})
Convey("Diamond with cycles", t, func() {
So(call(groupGraph{
"start": []string{"A1", "A2"},
"A1": []string{"B"},
"A2": []string{"B"},
"B": []string{"start"},
}), ShouldResemble, []string{"start", "A1", "B"})
})
}