127 lines
4.0 KiB
Go
127 lines
4.0 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.yuntuo.hk/k2safe/orbit/internal/storage/mysql"
|
|
core "git.yuntuo.hk/k2safe/orbit/model"
|
|
"git.yuntuo.hk/k2safe/orbit/platform/auth"
|
|
)
|
|
|
|
func testOperation(t *testing.T) mysql.CredentialOperation {
|
|
t.Helper()
|
|
ns, err := core.NewID()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
id, err := core.NewID()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
opID, err := core.NewID()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
token, _, err := auth.Issue(ns, id)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expires := time.Now().UTC().Add(time.Hour)
|
|
return mysql.CredentialOperation{Version: 1, OperationID: opID, NamespaceID: ns, CredentialID: id, ExpectedRevision: 1, Action: "ROTATE", Reason: "unit test", Token: token, ExpiresAt: &expires}
|
|
}
|
|
|
|
func TestPrivateOperationFileIsExclusiveAnd0600(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "operation.json")
|
|
op := testOperation(t)
|
|
if err := writePrivateOperation(path, op); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if info.Mode().Perm() != 0600 {
|
|
t.Fatalf("private file mode=%v", info.Mode().Perm())
|
|
}
|
|
read, err := readPrivateOperation(path)
|
|
if err != nil || read.OperationID != op.OperationID || read.Token != op.Token {
|
|
t.Fatalf("private operation round trip: %+v %v", read, err)
|
|
}
|
|
if err := writePrivateOperation(path, op); err == nil {
|
|
t.Fatal("existing private operation was overwritten")
|
|
}
|
|
if err := os.Chmod(path, 0640); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := readPrivateOperation(path); err == nil {
|
|
t.Fatal("group-readable operation was accepted")
|
|
}
|
|
}
|
|
|
|
func TestPrivateOperationFileRejectsUnknownFieldsAndSymlinks(t *testing.T) {
|
|
dir := t.TempDir()
|
|
unknown := filepath.Join(dir, "unknown.json")
|
|
if err := os.WriteFile(unknown, []byte(`{"version":1,"unexpected":true}`), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := readPrivateOperation(unknown); err == nil {
|
|
t.Fatal("unknown operation field was accepted")
|
|
}
|
|
op := testOperation(t)
|
|
target := filepath.Join(dir, "target.json")
|
|
if err := writePrivateOperation(target, op); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
link := filepath.Join(dir, "link.json")
|
|
if err := os.Symlink(target, link); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := readPrivateOperation(link); err == nil {
|
|
t.Fatal("symlink operation file was accepted")
|
|
}
|
|
}
|
|
|
|
func TestPermissionActionList(t *testing.T) {
|
|
actions, err := parseCredentialActions("tasks:read, schedules:manage,schedules:read")
|
|
if err != nil || !reflect.DeepEqual(actions, []string{"schedules:manage", "schedules:read", "tasks:read"}) {
|
|
t.Fatalf("invalid canonical action list: %v %v", actions, err)
|
|
}
|
|
for _, value := range []string{"", " ", "*", "tasks:*", "tasks:read,tasks:read", "tasks:read, tasks:read", "tasks:read,", "schedules:admin"} {
|
|
if _, err := parseCredentialActions(value); err == nil {
|
|
t.Fatalf("accepted invalid action list %q", value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPermissionCommandRejectsLifetimeBeforeDatabaseAccess(t *testing.T) {
|
|
op := testOperation(t)
|
|
for _, flag := range []string{"--valid-for=0", "--grace=0"} {
|
|
err := runCredential([]string{"permissions", "--namespace-id=" + string(op.NamespaceID), "--credential-id=" + string(op.CredentialID), "--expected-revision=1", "--reason=test", "--output=" + filepath.Join(t.TempDir(), "op.json"), "--actions=tasks:read", flag})
|
|
if err == nil || err.Error() != "permission changes preserve validity and overlap; omit --valid-for and --grace" {
|
|
t.Fatalf("lifetime field not rejected: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPrivatePermissionOperationReplaysWithoutToken(t *testing.T) {
|
|
op := testOperation(t)
|
|
op.Version = 3
|
|
op.Action = "SET_PERMISSIONS"
|
|
op.Token = ""
|
|
op.ExpiresAt = nil
|
|
op.Actions = []string{"schedules:manage", "schedules:read", "tasks:read"}
|
|
path := filepath.Join(t.TempDir(), "permissions.json")
|
|
if err := writePrivateOperation(path, op); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
read, err := readPrivateOperation(path)
|
|
if err != nil || !reflect.DeepEqual(read, op) {
|
|
t.Fatalf("permission operation identity changed: %v", err)
|
|
}
|
|
}
|