github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/lock_test.go (about) 1 /* 2 Copyright 2021 Gravitational, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package types 18 19 import ( 20 "reflect" 21 "strings" 22 "testing" 23 24 "github.com/google/go-cmp/cmp" 25 "github.com/stretchr/testify/require" 26 ) 27 28 func TestLockTargetMapConversions(t *testing.T) { 29 lt := LockTarget{ 30 User: "user@sso.tld", 31 Node: "node-uuid", 32 MFADevice: "mfa-device-uuid", 33 } 34 m := map[string]string{ 35 "user": "user@sso.tld", 36 "node": "node-uuid", 37 "mfa_device": "mfa-device-uuid", 38 } 39 40 ltMap, err := lt.IntoMap() 41 require.NoError(t, err) 42 require.Empty(t, cmp.Diff(m, ltMap)) 43 44 lt2 := LockTarget{} 45 err = lt2.FromMap(m) 46 require.NoError(t, err) 47 require.Empty(t, cmp.Diff(lt, lt2)) 48 } 49 50 func TestLockTargetMatch(t *testing.T) { 51 target := LockTarget{ 52 User: "user@sso.tld", 53 Node: "node-uuid", 54 MFADevice: "mfa-device-uuid", 55 } 56 lock, err := NewLock("some-lock", LockSpecV2{Target: target}) 57 require.NoError(t, err) 58 59 require.True(t, target.Match(lock)) 60 61 target.Node = "node-uuid-2" 62 require.False(t, target.Match(lock)) 63 64 target.Node = "" 65 require.True(t, target.Match(lock)) 66 67 disjointTarget := LockTarget{ 68 Login: "root", 69 } 70 require.False(t, disjointTarget.Match(lock)) 71 72 // Empty target should match no lock. 73 emptyTarget := LockTarget{} 74 require.False(t, emptyTarget.Match(lock)) 75 // Test that we still support old locks with only Node field set and that 76 // it only applies to nodes. 77 // For Nodes, LockTarget Node and ServerID fields are both set at the same 78 // time. 79 targetNode := LockTarget{ 80 ServerID: "node-uuid", 81 Node: "node-uuid", 82 } 83 // Create a lock with only Node field set (old lock). 84 lockNode, err := NewLock("some-lock", LockSpecV2{ 85 Target: LockTarget{ 86 Node: "node-uuid", 87 }, 88 }, 89 ) 90 require.NoError(t, err) 91 // Test that the old lock with only Node field set matches a target generated 92 // from a Node identity (Node and ServerID fields set) 93 require.True(t, targetNode.Match(lockNode)) 94 95 // Old locks with Node field should not match new lock targets with ServerID field 96 // set but Node field unset. 97 targetServerID := LockTarget{ 98 ServerID: "node-uuid", 99 } 100 101 require.False(t, targetServerID.Match(lockNode)) 102 103 // Test if locks with ServerID apply to nodes and other locks with ServerID. 104 lockServerID, err := NewLock("some-lock", LockSpecV2{ 105 Target: LockTarget{ 106 ServerID: "node-uuid", 107 }, 108 }, 109 ) 110 require.NoError(t, err) 111 // Test that a lock with ServerID field set matches a target generated from a 112 // Node identity (Node and ServerID fields set) 113 require.True(t, targetNode.Match(lockServerID)) 114 // Test that a lock with ServerID field set matches any target with ServerID. 115 require.True(t, targetServerID.Match(lockServerID)) 116 } 117 118 // TestLockTargetIsEmpty checks that the implementation of [LockTarget.IsEmpty] 119 // is correct by filling one field at a time and expecting IsEmpty to return 120 // false. Only the public fields that don't start with `XXX_` are checked (as 121 // those are gogoproto-internal fields). 122 func TestLockTargetIsEmpty(t *testing.T) { 123 require.True(t, (LockTarget{}).IsEmpty()) 124 125 for i, field := range reflect.VisibleFields(reflect.TypeOf(LockTarget{})) { 126 if strings.HasPrefix(field.Name, "XXX_") { 127 continue 128 } 129 130 var lt LockTarget 131 // if we add non-string fields to LockTarget we need a type switch here 132 reflect.ValueOf(<).Elem().Field(i).SetString("nonempty") 133 require.False(t, lt.IsEmpty(), "field name: %v", field.Name) 134 } 135 }