1// Copyright 2019 Istio Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package trustdomain
16
17import (
18	"reflect"
19	"testing"
20)
21
22func TestReplaceTrustDomainAliases(t *testing.T) {
23	testCases := []struct {
24		name              string
25		trustDomainBundle Bundle
26		principals        []string
27		expect            []string
28	}{
29		{
30			name:              "No trust domain aliases (no change in trust domain)",
31			trustDomainBundle: NewBundle("cluster.local", nil),
32			principals:        []string{"cluster.local/ns/foo/sa/bar"},
33			expect:            []string{"cluster.local/ns/foo/sa/bar"},
34		},
35		{
36			name:              "Principal with *",
37			trustDomainBundle: NewBundle("cluster.local", nil),
38			principals:        []string{"*"},
39			expect:            []string{"*"},
40		},
41		{
42			name:              "Principal with * prefix",
43			trustDomainBundle: NewBundle("cluster.local", nil),
44			principals:        []string{"*/ns/foo/sa/bar"},
45			expect:            []string{"*/ns/foo/sa/bar"},
46		},
47		{
48			name:              "One trust domain alias, one principal",
49			trustDomainBundle: NewBundle("td2", []string{"td1"}),
50			principals:        []string{"td1/ns/foo/sa/bar"},
51			expect:            []string{"td2/ns/foo/sa/bar", "td1/ns/foo/sa/bar"},
52		},
53		{
54			name:              "One trust domain alias, two principals",
55			trustDomainBundle: NewBundle("td1", []string{"cluster.local"}),
56			principals:        []string{"cluster.local/ns/foo/sa/bar", "cluster.local/ns/yyy/sa/zzz"},
57			expect:            []string{"td1/ns/foo/sa/bar", "cluster.local/ns/foo/sa/bar", "td1/ns/yyy/sa/zzz", "cluster.local/ns/yyy/sa/zzz"},
58		},
59		{
60			name:              "One trust domain alias, principals with * as-is",
61			trustDomainBundle: NewBundle("td1", []string{"cluster.local"}),
62			principals:        []string{"*/ns/foo/sa/bar", "*sa/zzz", "*"},
63			expect:            []string{"*/ns/foo/sa/bar", "*sa/zzz", "*"},
64		},
65		{
66			name:              "Two trust domain aliases, two principals",
67			trustDomainBundle: NewBundle("td2", []string{"td1", "cluster.local"}),
68			principals:        []string{"cluster.local/ns/foo/sa/bar", "td1/ns/yyy/sa/zzz"},
69			expect: []string{"td2/ns/foo/sa/bar", "td1/ns/foo/sa/bar", "cluster.local/ns/foo/sa/bar",
70				"td2/ns/yyy/sa/zzz", "td1/ns/yyy/sa/zzz", "cluster.local/ns/yyy/sa/zzz"},
71		},
72		{
73			name:              "Two trust domain aliases with * prefix in trust domain",
74			trustDomainBundle: NewBundle("td2", []string{"foo-td1", "cluster.local"}),
75			principals:        []string{"*-td1/ns/foo/sa/bar"},
76			expect:            []string{"td2/ns/foo/sa/bar", "*-td1/ns/foo/sa/bar", "cluster.local/ns/foo/sa/bar"},
77		},
78		{
79			name:              "Principals not match any trust domains",
80			trustDomainBundle: NewBundle("td1", []string{"td2"}),
81			principals:        []string{"some-td/ns/foo/sa/bar"},
82			expect:            []string{"some-td/ns/foo/sa/bar"},
83		},
84		{
85			name:              "Principals match one alias",
86			trustDomainBundle: NewBundle("td1", []string{"td2", "some-td"}),
87			principals:        []string{"some-td/ns/foo/sa/bar"},
88			expect:            []string{"td1/ns/foo/sa/bar", "td2/ns/foo/sa/bar", "some-td/ns/foo/sa/bar"},
89		},
90		{
91			name:              "One principal match one alias",
92			trustDomainBundle: NewBundle("new-td", []string{"td2", "td3"}),
93			principals:        []string{"td1/ns/some-ns/sa/some-sa", "td2/ns/foo/sa/bar"},
94			expect: []string{"td1/ns/some-ns/sa/some-sa", "new-td/ns/foo/sa/bar",
95				"td2/ns/foo/sa/bar", "td3/ns/foo/sa/bar"},
96		},
97		{
98			name:              "Trust domain is empty string",
99			trustDomainBundle: NewBundle("new-td", []string{"td2", "td3"}),
100			principals:        []string{"/ns/some-ns/sa/some-sa"},
101			expect:            []string{"/ns/some-ns/sa/some-sa"},
102		},
103		{
104			name:              "No duplicated principals for prefix",
105			trustDomainBundle: NewBundle("new-td", []string{"old-td"}),
106			principals:        []string{"*-td/ns/some-ns/sa/some-sa"},
107			// Rather than output *-td/ns/some-ns/sa/some-sa once for each trust domain.
108			expect: []string{"*-td/ns/some-ns/sa/some-sa"},
109		},
110	}
111
112	for _, tc := range testCases {
113		got := tc.trustDomainBundle.ReplaceTrustDomainAliases(tc.principals)
114		if !reflect.DeepEqual(got, tc.expect) {
115			t.Errorf("%s failed. Expect: %s. Got: %s", tc.name, tc.expect, got)
116		}
117	}
118}
119
120func TestReplaceTrustDomainInPrincipal(t *testing.T) {
121	cases := []struct {
122		trustDomainIn string
123		principal     string
124		out           string
125	}{
126		{principal: "spiffe://cluster.local/ns/foo/sa/bar", out: ""},
127		{principal: "sa/test-sa/ns/default", out: ""},
128		{trustDomainIn: "td", principal: "cluster.local/ns/foo/sa/bar", out: "td/ns/foo/sa/bar"},
129		{trustDomainIn: "abc", principal: "xyz/ns/foo/sa/bar", out: "abc/ns/foo/sa/bar"},
130	}
131
132	for _, c := range cases {
133		got := replaceTrustDomainInPrincipal(c.trustDomainIn, c.principal)
134		if got != c.out {
135			t.Errorf("expect %s, but got %s", c.out, got)
136		}
137	}
138}
139
140func TestGetTrustDomainFromSpiffeIdentity(t *testing.T) {
141	cases := []struct {
142		principal string
143		out       string
144	}{
145		{principal: "spiffe://cluster.local/ns/foo/sa/bar", out: ""},
146		{principal: "sa/test-sa/ns/default", out: ""},
147		{principal: "cluster.local/ns/foo/sa/bar", out: "cluster.local"},
148		{principal: "xyz/ns/foo/sa/bar", out: "xyz"},
149	}
150
151	for _, c := range cases {
152		got, _ := getTrustDomainFromSpiffeIdentity(c.principal)
153		if got != c.out {
154			t.Errorf("expect %s, but got %s", c.out, got)
155		}
156	}
157}
158
159func TestIsTrustDomainBeingEnforced(t *testing.T) {
160	cases := []struct {
161		principal string
162		want      bool
163	}{
164		{principal: "cluster.local/ns/foo/sa/bar", want: true},
165		{principal: "*/ns/foo/sa/bar", want: false},
166		{principal: "*-td/ns/foo/sa/bar", want: true},
167		{principal: "*/sa/bar", want: false},
168		{principal: "*", want: false},
169		{principal: "/ns/foo/sa/bar", want: true},
170	}
171
172	for _, c := range cases {
173		got := isTrustDomainBeingEnforced(c.principal)
174		if got != c.want {
175			t.Errorf("expect %v, but got %v", c.want, got)
176		}
177	}
178}
179