138 lines
3.9 KiB
Go
138 lines
3.9 KiB
Go
//go:build windows
|
|
|
|
package authconfig
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"path/filepath"
|
|
"runtime"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/aritmolab/thothii/tools/tht/internal/safeio"
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
func TestLoadRejectsPermissiveWindowsDirectoryAuthAndUsersDACLs(t *testing.T) {
|
|
for name, makePermissive := range map[string]func(t *testing.T, directory string){
|
|
"directory": func(t *testing.T, directory string) {
|
|
setPermissiveAuthDACL(t, directory)
|
|
},
|
|
"auth file": func(t *testing.T, directory string) {
|
|
setPermissiveAuthDACL(t, filepath.Join(directory, "auth.yaml"))
|
|
},
|
|
"users file": func(t *testing.T, directory string) {
|
|
setPermissiveAuthDACL(t, filepath.Join(directory, "users.yaml"))
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
directory := writePrivateWindowsAuthFiles(t)
|
|
makePermissive(t, directory)
|
|
if _, _, err := Load(directory); !errors.Is(err, safeio.ErrUnsafeFile) {
|
|
t.Fatalf("Load() error = %v, want ErrUnsafeFile", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMutateUsersCreatesAndRejectsPermissiveWindowsLockDACL(t *testing.T) {
|
|
directory := writePrivateWindowsAuthFiles(t)
|
|
if err := MutateUsers(directory, func(*Registry) error { return nil }); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
lockPath := filepath.Join(directory, lockFileName)
|
|
if err := safeio.ValidatePrivateRegular(lockPath); err != nil {
|
|
t.Fatalf("lock privacy error = %v", err)
|
|
}
|
|
setPermissiveAuthDACL(t, lockPath)
|
|
if err := MutateUsers(directory, func(*Registry) error { return nil }); !errors.Is(err, safeio.ErrUnsafeFile) {
|
|
t.Fatalf("MutateUsers() error = %v, want ErrUnsafeFile", err)
|
|
}
|
|
}
|
|
|
|
func TestMutateUsersConcurrentWindowsLockCreationNeverObservesDefaultDACL(t *testing.T) {
|
|
users := adminUserYAML("admin", "Admin", true, "admin")
|
|
for index := 0; index < 32; index++ {
|
|
users += userYAML(index)
|
|
}
|
|
directory := writePrivateWindowsAuthFiles(t, registryYAML(users))
|
|
|
|
var group sync.WaitGroup
|
|
var ready sync.WaitGroup
|
|
start := make(chan struct{})
|
|
errors := make(chan error, 32)
|
|
for index := 0; index < 32; index++ {
|
|
index := index
|
|
group.Add(1)
|
|
ready.Add(1)
|
|
go func() {
|
|
defer group.Done()
|
|
ready.Done()
|
|
<-start
|
|
errors <- MutateUsers(directory, func(registry *Registry) error {
|
|
registry.Users[index+1].DisplayName = fmt.Sprintf("Windows Updated %d", index)
|
|
return nil
|
|
})
|
|
}()
|
|
}
|
|
ready.Wait()
|
|
close(start)
|
|
group.Wait()
|
|
close(errors)
|
|
for err := range errors {
|
|
if err != nil {
|
|
t.Fatalf("MutateUsers() concurrent lock creation error = %v", err)
|
|
}
|
|
}
|
|
if err := safeio.ValidatePrivateRegular(filepath.Join(directory, lockFileName)); err != nil {
|
|
t.Fatalf("concurrently created lock DACL error = %v", err)
|
|
}
|
|
}
|
|
|
|
func writePrivateWindowsAuthFiles(t *testing.T, users ...string) string {
|
|
t.Helper()
|
|
registry := registryYAML(adminUserYAML("admin", "Admin", true, "admin"))
|
|
if len(users) > 0 {
|
|
registry = users[0]
|
|
}
|
|
directory := writeAuthFiles(t, defaultAuthYAML, registry)
|
|
if err := safeio.ProtectPrivateDirectory(directory); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, name := range []string{"auth.yaml", "users.yaml"} {
|
|
if err := safeio.ProtectPrivateRegular(filepath.Join(directory, name)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
return directory
|
|
}
|
|
|
|
func setPermissiveAuthDACL(t *testing.T, path string) {
|
|
t.Helper()
|
|
world, err := windows.StringToSid("S-1-1-0")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var pinner runtime.Pinner
|
|
pinner.Pin(world)
|
|
defer pinner.Unpin()
|
|
acl, err := windows.ACLFromEntries([]windows.EXPLICIT_ACCESS{{
|
|
AccessPermissions: windows.GENERIC_READ | windows.GENERIC_WRITE,
|
|
AccessMode: windows.GRANT_ACCESS,
|
|
Trustee: windows.TRUSTEE{
|
|
TrusteeForm: windows.TRUSTEE_IS_SID,
|
|
TrusteeType: windows.TRUSTEE_IS_GROUP,
|
|
TrusteeValue: windows.TrusteeValueFromSID(world),
|
|
},
|
|
}}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := windows.SetNamedSecurityInfo(path, windows.SE_FILE_OBJECT,
|
|
windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION,
|
|
nil, nil, acl, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|