1// Copyright 2016-2018 VMware, Inc. All Rights Reserved.
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 rbac
16
17import (
18	"context"
19	"testing"
20	"time"
21
22	"github.com/stretchr/testify/require"
23
24	"github.com/vmware/govmomi/simulator"
25	"github.com/vmware/govmomi/vim25/types"
26	"github.com/vmware/vic/pkg/vsphere/session"
27	"github.com/vmware/vic/pkg/vsphere/test"
28	"github.com/vmware/vic/pkg/vsphere/test/env"
29)
30
31var role1 = types.AuthorizationRole{
32	Name: "vcenter",
33	Privilege: []string{
34		"Datastore.Config",
35	},
36}
37
38var role2 = types.AuthorizationRole{
39	Name: "datacenter",
40	Privilege: []string{
41		"Datastore.Config",
42		"Datastore.FileManagement",
43		"VirtualMachine.Config.AddNewDisk",
44		"VirtualMachine.Config.AdvancedConfig",
45		"VirtualMachine.Config.RemoveDisk",
46		"VirtualMachine.Inventory.Create",
47		"VirtualMachine.Inventory.Delete",
48	},
49}
50
51var role3 = types.AuthorizationRole{
52	Name: "cluster",
53	Privilege: []string{
54		"Datastore.AllocateSpace",
55		"Datastore.Browse",
56		"Datastore.Config",
57		"Datastore.DeleteFile",
58		"Datastore.FileManagement",
59		"Host.Config.SystemManagement",
60	},
61}
62
63var readOnlyRole = types.AuthorizationRole{
64	Name: "readonly",
65	Privilege: []string{
66		sysAnonPriv,
67		sysReadPriv,
68		sysViewPriv,
69	},
70}
71
72var dcReadOnlyConfig = Config{
73	Resources: []Resource{
74		{
75			Type:      Datacenter,
76			Propagate: true,
77			Role:      readOnlyRole,
78		},
79	},
80}
81
82// Configuration for the ops-user
83var testRBACConfig = Config{
84	Resources: []Resource{
85		{
86			Type:      VCenter,
87			Propagate: false,
88			Role:      role1,
89		},
90		{
91			Type:      Datacenter,
92			Propagate: true,
93			Role:      role2,
94		},
95		{
96			Type:      Cluster,
97			Propagate: true,
98			Role:      role3,
99		},
100	},
101}
102
103var (
104	testRolePrefix = "test-role-prefix"
105	testUser       = "test-user"
106)
107
108func TestReadPermsOnDC(t *testing.T) {
109	ctx := context.Background()
110
111	// Create the VPX model and server.
112	m := simulator.VPX()
113	defer m.Remove()
114	err := m.Create()
115	require.NoError(t, err, "Cannot create VPX simulator")
116
117	server := m.Service.NewServer()
118	defer server.Close()
119
120	s, err := test.SessionWithVPX(ctx, server.URL.String())
121	require.NoError(t, err, "Cannot initialize the VPX session")
122
123	// Initialize the AuthzManager.
124	am := NewAuthzManager(ctx, s.Vim25())
125	am.InitConfig(testUser, testRolePrefix, &dcReadOnlyConfig)
126
127	_, err = am.createOrRepairRoles(ctx)
128	require.NoError(t, err, "Cannot create the read-only role")
129
130	// Test that ReadPermsOnDC returns an error when a non-existent entity ref is supplied.
131	// TODO(anchal): govmomi simulator's RetrieveEntityPermissions func assumes a validated
132	// moref. This test case requires an update to govmomi.
133	// fakeRef := types.ManagedObjectReference{
134	// 	Type:  "VirtualMachine",
135	// 	Value: "foo",
136	// }
137	// hasPrivs, err := am.ReadPermsOnDC(ctx, fakeRef)
138	// require.Error(t, err, "Received no error from ReadPermsOnDC")
139
140	// Test that ReadPermsOnDC returns false when no permissions have been set on an object.
141	dcRef := s.Datacenter.Reference()
142	hasPrivs, err := am.ReadPermsOnDC(ctx, dcRef)
143	require.NoError(t, err, "Received unexpected error from ReadPermsOnDC")
144	require.False(t, hasPrivs, "Expected ReadPermsOnDC to return false")
145
146	// Test that ReadPermsOnDC returns false when a subset of read-only privileges is
147	// assigned to an entity.
148	clusterRef := s.Cluster.Reference()
149	clusterPerms := []types.Permission{
150		{
151			Principal: am.Principal,
152			// RoleId -3 is for the View role, which has only System.Anonymous
153			// and System.View privileges.
154			RoleId: int32(-3),
155		},
156	}
157	err = am.authzManager.SetEntityPermissions(ctx, clusterRef, clusterPerms)
158	require.NoError(t, err, "Cannot set permissions on cluster ref")
159
160	hasPrivs, err = am.ReadPermsOnDC(ctx, clusterRef)
161	require.NoError(t, err, "Received unexpected error from ReadPermsOnDC")
162	require.False(t, hasPrivs, "Expected ReadPermsOnDC to return false")
163
164	// Test that ReadPermsOnDC returns false when the permissions are assigned to a
165	// user who does not match the ops-user (am.Principal).
166	fakePrincipal := "foo@vsphere.local"
167	dcPerms := []types.Permission{
168		{
169			Principal: fakePrincipal,
170			RoleId:    readOnlyRole.RoleId,
171		},
172	}
173	err = am.authzManager.SetEntityPermissions(ctx, dcRef, dcPerms)
174	require.NoError(t, err, "Cannot set permissions on dc ref")
175
176	hasPrivs, err = am.ReadPermsOnDC(ctx, dcRef)
177	require.NoError(t, err, "Received unexpected error from ReadPermsOnDC")
178	require.False(t, hasPrivs, "Expected ReadPermsOnDC to return false")
179
180	// Test that ReadPermsOnDC returns true when read-only permissions are assigned to
181	// the ops-user.
182	dcPerms = []types.Permission{
183		{
184			Principal: am.Principal,
185			RoleId:    readOnlyRole.RoleId,
186		},
187	}
188	err = am.authzManager.SetEntityPermissions(ctx, dcRef, dcPerms)
189	require.NoError(t, err, "Cannot set permissions on dc ref")
190
191	hasPrivs, err = am.ReadPermsOnDC(ctx, dcRef)
192	require.NoError(t, err, "Received unexpected error from ReadPermsOnDC")
193	require.True(t, hasPrivs, "Expected ReadPermsOnDC to return true")
194}
195
196func TestRolesSimulatorVPX(t *testing.T) {
197	ctx := context.Background()
198	m := simulator.VPX()
199	defer m.Remove()
200
201	err := m.Create()
202	require.NoError(t, err, "Cannot create VPX Simulator")
203
204	s := m.Service.NewServer()
205	defer s.Close()
206
207	config := &session.Config{
208		Service:   s.URL.String(),
209		Insecure:  true,
210		Keepalive: time.Duration(5) * time.Minute,
211	}
212
213	sess, err := session.NewSession(config).Connect(ctx)
214	require.NoError(t, err, "Cannot connect to VPX Simulator")
215
216	am := NewAuthzManager(ctx, sess.Vim25())
217	am.InitConfig(testUser, testRolePrefix, &testRBACConfig)
218
219	var testRoleNames = []string{
220		"datacenter",
221		"cluster",
222	}
223
224	var testRolePrivileges = []string{
225		"VirtualMachine.Config.AddNewDisk",
226		"Host.Config.SystemManagement",
227	}
228
229	DoTestRoles(ctx, t, am, testRoleNames, testRolePrivileges)
230}
231
232func TestRolesVCenter(t *testing.T) {
233	ctx := context.Background()
234
235	config := &session.Config{
236		Service:   env.URL(t),
237		Insecure:  true,
238		Keepalive: time.Duration(5) * time.Minute,
239	}
240
241	sess, err := session.NewSession(config).Connect(ctx)
242	if err != nil {
243		t.SkipNow()
244	}
245
246	am := NewAuthzManager(ctx, sess.Vim25())
247	am.InitConfig(testUser, testRolePrefix, &testRBACConfig)
248
249	var testRoleNames = []string{
250		"datacenter",
251		"cluster",
252	}
253
254	var testRolePrivileges = []string{
255		"VirtualMachine.Config.AddNewDisk",
256		"Host.Config.SystemManagement",
257	}
258
259	DoTestRoles(ctx, t, am, testRoleNames, testRolePrivileges)
260}
261
262func TestAdminSimulatorVPX(t *testing.T) {
263	ctx := context.Background()
264	m := simulator.VPX()
265	defer m.Remove()
266
267	err := m.Create()
268	require.NoError(t, err, "Cannot create VPX Simulator")
269
270	s := m.Service.NewServer()
271	defer s.Close()
272
273	config := &session.Config{
274		Service:   s.URL.String(),
275		Insecure:  true,
276		Keepalive: time.Duration(5) * time.Minute,
277	}
278
279	sess, err := session.NewSession(config).Connect(ctx)
280	require.NoError(t, err, "Cannot connect to VPX Simulator")
281
282	am := NewAuthzManager(ctx, sess.Vim25())
283	am.InitConfig("admin", "test-role-prefix", &testRBACConfig)
284
285	// Unfortunately the Sim does not have support for looking up group membership
286	// therefore we can only test the presence of the Admin role
287
288	res, err := am.PrincipalHasRole(ctx, "Admin")
289	require.NoError(t, err, "Failed to verify Admin Privileges")
290	require.True(t, res, "User Administrator@vsphere.local should have an Admin role")
291
292	// Negative test, principal does not have that role
293	res, err = am.PrincipalHasRole(ctx, "NoAccess")
294	require.NoError(t, err, "Failed to verify Admin Privileges")
295	require.False(t, res, "User Administrator@vsphere.local should have an NoAccess role")
296
297	// Check regular user
298	am.Principal = "nouser@vshpere.local"
299	res, err = am.PrincipalHasRole(ctx, "Admin")
300	require.NoError(t, err, "Failed to verify Admin Privileges")
301	require.False(t, res, "User nouser@vsphere.local should not have an Admin role")
302}
303
304func TestAdminVCenter(t *testing.T) {
305	ctx := context.Background()
306
307	config := &session.Config{
308		Service:   env.URL(t),
309		Insecure:  true,
310		Keepalive: time.Duration(5) * time.Minute,
311	}
312
313	sess, err := session.NewSession(config).Connect(ctx)
314	if err != nil {
315		t.SkipNow()
316	}
317
318	am := NewAuthzManager(ctx, sess.Vim25())
319	am.InitConfig("Administrator@vsphere.local", "test-role-prefix", &testRBACConfig)
320
321	res, err := am.PrincipalBelongsToGroup(ctx, "Administrators")
322	require.NoError(t, err, "Failed to verify Admin Privileges")
323	require.True(t, res, "User Administrator@vsphere.local should be a member of Administrators")
324
325	res, err = am.PrincipalHasRole(ctx, "Admin")
326	require.NoError(t, err, "Failed to verify Admin Privileges")
327	require.True(t, res, "User Administrator@vsphere.local should have an Admin role")
328
329	// Negative test, principal does not belong
330	res, err = am.PrincipalBelongsToGroup(ctx, "TestUsers")
331	require.NoError(t, err, "Failed to verify Admin Privileges")
332	require.False(t, res, "User Administrator@vsphere.local should not be a member of TestUsers")
333
334	// Negative test, principal does not have that role
335	res, err = am.PrincipalHasRole(ctx, "NoAccess")
336	require.NoError(t, err, "Failed to verify Admin Privileges")
337	require.False(t, res, "User Administrator@vsphere.local should have an NoAccess role")
338
339	// Check regular user
340	am.Principal = "nouser@vshpere.local"
341	res, err = am.PrincipalHasRole(ctx, "Admin")
342	require.NoError(t, err, "Failed to verify Admin Privileges")
343	require.False(t, res, "User nouser@vsphere.local should not have an Admin role")
344
345	// Check regular user
346	am.Principal = "nouser"
347	res, err = am.PrincipalHasRole(ctx, "Admin")
348	require.NoError(t, err, "Failed to verify Admin Privileges")
349	require.False(t, res, "User nouser@vsphere.local should not have an Admin role")
350}
351