mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-26 02:30:57 +00:00
259 lines
8.6 KiB
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)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|