tailscale/ipn/ipnauth/win_test.go

259 lines
8.6 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package ipnauth
import (
"testing"
"tailscale.com/ipn"
)
var (
winServerEnvs = []WindowsEnvironment{
{IsServer: true, IsManaged: false},
{IsServer: true, IsManaged: true},
}
winClientEnvs = []WindowsEnvironment{
{IsServer: false, IsManaged: false},
{IsServer: false, IsManaged: true},
}
winManagedEnvs = []WindowsEnvironment{
{IsServer: false, IsManaged: true},
{IsServer: true, IsManaged: true},
}
winAllEnvs = []WindowsEnvironment{
{IsServer: false, IsManaged: false},
{IsServer: false, IsManaged: true},
{IsServer: true, IsManaged: false},
{IsServer: true, IsManaged: true},
}
)
func TestDeviceAccessWindows(t *testing.T) {
tests := []struct {
name string
requestAccess []DeviceAccess
envs []WindowsEnvironment
tok WindowsToken
wantAllow bool
}{
{
name: "allow-all-access-elevated-admin",
requestAccess: []DeviceAccess{UnrestrictedDeviceAccess},
envs: winAllEnvs,
tok: &testToken{Admin: true, Elevated: true},
wantAllow: true,
},
{
name: "allow-create-profile-non-elevated-admin",
requestAccess: []DeviceAccess{CreateProfile},
envs: winAllEnvs,
tok: &testToken{Admin: true, Elevated: false},
wantAllow: true,
},
{
name: "allow-install-updates-non-elevated-admin",
requestAccess: []DeviceAccess{InstallUpdates},
envs: winAllEnvs,
tok: &testToken{Admin: true, Elevated: false},
wantAllow: true,
},
{
name: "deny-privileged-access-non-elevated-admin",
requestAccess: []DeviceAccess{Debug, DeleteAllProfiles},
envs: winAllEnvs,
tok: &testToken{Admin: true, Elevated: false},
wantAllow: false,
},
{
name: "allow-read-access-user",
requestAccess: []DeviceAccess{ReadDeviceStatus, GenerateBugReport},
envs: winAllEnvs,
tok: &testToken{Admin: false},
wantAllow: true,
},
{
name: "deny-privileged-access-user",
requestAccess: []DeviceAccess{Debug, DeleteAllProfiles},
envs: winAllEnvs,
tok: &testToken{Admin: false},
wantAllow: false,
},
{
name: "allow-create-profile-non-server-user",
requestAccess: []DeviceAccess{CreateProfile},
envs: winClientEnvs,
tok: &testToken{Admin: false},
wantAllow: true,
},
{
name: "deny-create-profile-server-user",
requestAccess: []DeviceAccess{CreateProfile},
envs: winServerEnvs,
tok: &testToken{Admin: false},
wantAllow: false,
},
{
name: "allow-install-updates-non-server-user",
requestAccess: []DeviceAccess{InstallUpdates},
envs: winClientEnvs,
tok: &testToken{Admin: false},
wantAllow: true,
},
{
name: "deny-install-updates-server-user",
requestAccess: []DeviceAccess{InstallUpdates},
envs: winServerEnvs,
tok: &testToken{Admin: false},
wantAllow: false,
},
}
for _, tt := range tests {
for _, env := range tt.envs {
user := newWindowsIdentity(tt.tok, env)
for _, access := range tt.requestAccess {
testName := tt.name + "-" + env.String() + "-" + access.String()
t.Run(testName, func(t *testing.T) {
if res := user.CheckAccess(access); res.Allowed() != tt.wantAllow {
t.Errorf("got result: %v, want allow: %v", res, tt.wantAllow)
}
})
}
}
}
}
func TestProfileAccessWindows(t *testing.T) {
tests := []struct {
name string
tok WindowsToken
profile ipn.LoginProfile
prefs ipn.Prefs
envs []WindowsEnvironment
requestAccess []ProfileAccess
wantAllow bool
}{
{
name: "allow-users-access-to-own-profiles",
tok: &testToken{Admin: false, SID: "User1"},
profile: ipn.LoginProfile{LocalUserID: "User1"},
envs: winAllEnvs,
requestAccess: []ProfileAccess{UnrestrictedProfileAccess & ^(ServePath)}, // ServePath requires elevated admin rights
wantAllow: true,
},
{
name: "allow-users-disconnect-access-to-others-profiles-on-clients",
tok: &testToken{Admin: false, SID: "User1"},
profile: ipn.LoginProfile{LocalUserID: "User2"},
envs: winClientEnvs,
requestAccess: []ProfileAccess{Disconnect},
wantAllow: true,
},
{
name: "allow-users-access-to-others-unattended-profiles-on-unmanaged-clients",
tok: &testToken{Admin: false, SID: "User1"},
profile: ipn.LoginProfile{LocalUserID: "User2"},
prefs: ipn.Prefs{ForceDaemon: true},
envs: []WindowsEnvironment{{IsServer: false, IsManaged: false}},
requestAccess: []ProfileAccess{ReadProfileInfo, Connect, Disconnect, ListPeers, ReadPrefs, ChangeExitNode},
wantAllow: true,
},
{
name: "allow-users-read-access-to-others-unattended-profiles-on-managed",
tok: &testToken{Admin: false, SID: "User1"},
profile: ipn.LoginProfile{LocalUserID: "User2"},
prefs: ipn.Prefs{ForceDaemon: true},
envs: winManagedEnvs,
requestAccess: []ProfileAccess{ReadProfileInfo, ListPeers},
wantAllow: true,
},
{
name: "allow-users-read-access-to-others-unattended-profiles-on-servers",
tok: &testToken{Admin: false, SID: "User1"},
profile: ipn.LoginProfile{LocalUserID: "User2"},
prefs: ipn.Prefs{ForceDaemon: true},
envs: winServerEnvs,
requestAccess: []ProfileAccess{ReadProfileInfo, ListPeers},
wantAllow: true,
},
{
name: "deny-users-access-to-non-unattended-others-profiles",
tok: &testToken{Admin: false, SID: "User1"},
profile: ipn.LoginProfile{LocalUserID: "User2"},
envs: winAllEnvs,
requestAccess: []ProfileAccess{ReadProfileInfo, Connect, ListPeers, ReadPrefs, ChangePrefs, ChangeExitNode},
wantAllow: false,
},
{
name: "allow-elevated-admins-access-to-others-profiles",
tok: &testToken{Admin: true, Elevated: true, SID: "Admin1"},
profile: ipn.LoginProfile{LocalUserID: "User1"},
envs: winAllEnvs,
requestAccess: []ProfileAccess{UnrestrictedProfileAccess & ^ReadPrivateKeys}, // ReadPrivateKeys is never allowed to others' profiles.
wantAllow: true,
},
{
name: "allow-non-elevated-admins-access-to-shared-profiles",
tok: &testToken{Admin: true, Elevated: true, SID: "Admin1"},
profile: ipn.LoginProfile{LocalUserID: ""},
envs: winManagedEnvs,
requestAccess: []ProfileAccess{UnrestrictedProfileAccess & ^(ReadPrivateKeys | ServePath)},
wantAllow: true,
},
{
name: "allow-non-elevated-admins-access-to-unattended-profiles",
tok: &testToken{Admin: true, Elevated: true, SID: "Admin1"},
profile: ipn.LoginProfile{LocalUserID: ""},
prefs: ipn.Prefs{ForceDaemon: true},
envs: winManagedEnvs,
requestAccess: []ProfileAccess{UnrestrictedProfileAccess & ^(ReadPrivateKeys | ServePath)},
wantAllow: true,
},
{
name: "deny-non-elevated-admins-access-to-others-profiles",
tok: &testToken{Admin: true, Elevated: false, SID: "Admin1"},
profile: ipn.LoginProfile{LocalUserID: "User1"},
envs: winAllEnvs,
requestAccess: []ProfileAccess{ReadProfileInfo, Connect, ListPeers, ReadPrefs, ChangePrefs, ChangeExitNode},
wantAllow: false,
},
{
name: "allow-elevated-admins-serve-path-for-own-profiles",
tok: &testToken{Admin: true, Elevated: true, SID: "Admin1"},
profile: ipn.LoginProfile{LocalUserID: "Admin1"},
envs: winAllEnvs,
requestAccess: []ProfileAccess{ServePath},
wantAllow: true,
},
{
name: "deny-non-elevated-admins-serve-path-for-own-profiles",
tok: &testToken{Admin: true, Elevated: false, SID: "Admin1"},
profile: ipn.LoginProfile{LocalUserID: "Admin1"},
envs: winAllEnvs,
requestAccess: []ProfileAccess{ServePath},
wantAllow: false,
},
}
for _, tt := range tests {
for _, env := range tt.envs {
user := newWindowsIdentity(tt.tok, env)
for _, access := range tt.requestAccess {
testName := tt.name + "-" + env.String() + "-" + access.String()
t.Run(testName, func(t *testing.T) {
res := user.CheckProfileAccess(tt.profile.View(), ipn.PrefsGetterFor(tt.prefs.View()), access)
if res.Allowed() != tt.wantAllow {
t.Errorf("got result: %v, want allow: %v", res, tt.wantAllow)
}
})
}
}
}
}