github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/utils/keys/policy_test.go (about) 1 /* 2 Copyright 2022 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 keys_test 18 19 import ( 20 "fmt" 21 "slices" 22 "testing" 23 24 "github.com/gravitational/trace" 25 "github.com/stretchr/testify/require" 26 27 "github.com/gravitational/teleport/api/utils/keys" 28 ) 29 30 var ( 31 privateKeyPolicies = []keys.PrivateKeyPolicy{ 32 keys.PrivateKeyPolicyNone, 33 keys.PrivateKeyPolicyHardwareKey, 34 keys.PrivateKeyPolicyHardwareKeyTouch, 35 keys.PrivateKeyPolicyHardwareKeyPIN, 36 keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 37 keys.PrivateKeyPolicyWebSession, 38 } 39 hardwareKeyPolicies = []keys.PrivateKeyPolicy{ 40 keys.PrivateKeyPolicyHardwareKey, 41 keys.PrivateKeyPolicyHardwareKeyTouch, 42 keys.PrivateKeyPolicyHardwareKeyPIN, 43 keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 44 keys.PrivateKeyPolicyWebSession, 45 } 46 hardwareKeyTouchPolicies = []keys.PrivateKeyPolicy{ 47 keys.PrivateKeyPolicyHardwareKeyTouch, 48 keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 49 keys.PrivateKeyPolicyWebSession, 50 } 51 hardwareKeyPINPolicies = []keys.PrivateKeyPolicy{ 52 keys.PrivateKeyPolicyHardwareKeyPIN, 53 keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 54 keys.PrivateKeyPolicyWebSession, 55 } 56 hardwareKeyTouchAndPINPolicies = []keys.PrivateKeyPolicy{ 57 keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 58 keys.PrivateKeyPolicyWebSession, 59 } 60 ) 61 62 func TestIsRequiredPolicyMet(t *testing.T) { 63 privateKeyPolicies := []keys.PrivateKeyPolicy{ 64 keys.PrivateKeyPolicyNone, 65 keys.PrivateKeyPolicyHardwareKey, 66 keys.PrivateKeyPolicyHardwareKeyTouch, 67 keys.PrivateKeyPolicyHardwareKeyPIN, 68 keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 69 } 70 for _, tc := range []struct { 71 requiredPolicy keys.PrivateKeyPolicy 72 satisfyingPolicies []keys.PrivateKeyPolicy 73 }{ 74 { 75 requiredPolicy: keys.PrivateKeyPolicyNone, 76 satisfyingPolicies: privateKeyPolicies, 77 }, { 78 requiredPolicy: keys.PrivateKeyPolicyHardwareKey, 79 satisfyingPolicies: hardwareKeyPolicies, 80 }, { 81 requiredPolicy: keys.PrivateKeyPolicyHardwareKeyTouch, 82 satisfyingPolicies: hardwareKeyTouchPolicies, 83 }, { 84 requiredPolicy: keys.PrivateKeyPolicyHardwareKeyPIN, 85 satisfyingPolicies: hardwareKeyPINPolicies, 86 }, { 87 requiredPolicy: keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 88 satisfyingPolicies: hardwareKeyTouchAndPINPolicies, 89 }, 90 } { 91 t.Run(string(tc.requiredPolicy), func(t *testing.T) { 92 for _, keyPolicy := range privateKeyPolicies { 93 if tc.requiredPolicy.IsSatisfiedBy(keyPolicy) { 94 require.Contains(t, tc.satisfyingPolicies, keyPolicy, "Policy %q does not meet %q but IsRequirePolicyMet(%v, %v) returned true", keyPolicy, tc.requiredPolicy, tc.requiredPolicy, keyPolicy) 95 } else { 96 require.NotContains(t, tc.satisfyingPolicies, keyPolicy, "Policy %q does meet %q but IsRequirePolicyMet(%v, %v) returned false", keyPolicy, tc.requiredPolicy, tc.requiredPolicy, keyPolicy) 97 } 98 } 99 }) 100 } 101 } 102 103 func TestGetPolicyFromSet(t *testing.T) { 104 testCases := []struct { 105 name string 106 policySet []keys.PrivateKeyPolicy 107 wantPolicy keys.PrivateKeyPolicy 108 }{ 109 { 110 name: "none", 111 policySet: []keys.PrivateKeyPolicy{ 112 keys.PrivateKeyPolicyNone, 113 keys.PrivateKeyPolicyNone, 114 }, 115 wantPolicy: keys.PrivateKeyPolicyNone, 116 }, { 117 name: "hardware key policy", 118 policySet: []keys.PrivateKeyPolicy{ 119 keys.PrivateKeyPolicyNone, 120 keys.PrivateKeyPolicyHardwareKey, 121 }, 122 wantPolicy: keys.PrivateKeyPolicyHardwareKey, 123 }, { 124 name: "touch policy", 125 policySet: []keys.PrivateKeyPolicy{ 126 keys.PrivateKeyPolicyNone, 127 keys.PrivateKeyPolicyHardwareKey, 128 keys.PrivateKeyPolicyHardwareKeyTouch, 129 }, 130 wantPolicy: keys.PrivateKeyPolicyHardwareKeyTouch, 131 }, { 132 name: "pin policy", 133 policySet: []keys.PrivateKeyPolicy{ 134 keys.PrivateKeyPolicyNone, 135 keys.PrivateKeyPolicyHardwareKey, 136 keys.PrivateKeyPolicyHardwareKeyPIN, 137 }, 138 wantPolicy: keys.PrivateKeyPolicyHardwareKeyPIN, 139 }, { 140 name: "touch policy and pin policy", 141 policySet: []keys.PrivateKeyPolicy{ 142 keys.PrivateKeyPolicyNone, 143 keys.PrivateKeyPolicyHardwareKey, 144 keys.PrivateKeyPolicyHardwareKeyPIN, 145 keys.PrivateKeyPolicyHardwareKeyTouch, 146 }, 147 wantPolicy: keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 148 }, { 149 name: "touch and pin policy", 150 policySet: []keys.PrivateKeyPolicy{ 151 keys.PrivateKeyPolicyNone, 152 keys.PrivateKeyPolicyHardwareKey, 153 keys.PrivateKeyPolicyHardwareKeyTouch, 154 keys.PrivateKeyPolicyHardwareKeyPIN, 155 keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 156 }, 157 wantPolicy: keys.PrivateKeyPolicyHardwareKeyTouchAndPIN, 158 }, 159 } 160 for _, tc := range testCases { 161 t.Run(tc.name, func(t *testing.T) { 162 requiredPolicy, err := keys.PolicyThatSatisfiesSet(tc.policySet) 163 require.NoError(t, err) 164 require.Equal(t, tc.wantPolicy, requiredPolicy) 165 166 // reversing the policy set shouldn't change the output 167 slices.Reverse(tc.policySet) 168 169 requiredPolicy, err = keys.PolicyThatSatisfiesSet(tc.policySet) 170 require.NoError(t, err) 171 require.Equal(t, tc.wantPolicy, requiredPolicy) 172 }) 173 } 174 } 175 176 // TestParsePrivateKeyPolicyError tests private key policy error parsing and checking. 177 func TestParsePrivateKeyPolicyError(t *testing.T) { 178 type testCase struct { 179 desc string 180 errIn error 181 expectIsKeyPolicy bool 182 expectParseKeyPolicyErr bool 183 expectKeyPolicy keys.PrivateKeyPolicy 184 } 185 186 testCases := []testCase{ 187 { 188 desc: "random error", 189 errIn: trace.BadParameter("random error"), 190 expectIsKeyPolicy: false, 191 expectParseKeyPolicyErr: true, 192 }, { 193 desc: "unknown_key_policy", 194 errIn: keys.NewPrivateKeyPolicyError("unknown_key_policy"), 195 expectIsKeyPolicy: true, 196 expectParseKeyPolicyErr: true, 197 }, { 198 desc: "wrapped policy error", 199 errIn: trace.Wrap(keys.NewPrivateKeyPolicyError(keys.PrivateKeyPolicyHardwareKeyTouch), "wrapped err"), 200 expectIsKeyPolicy: true, 201 expectKeyPolicy: keys.PrivateKeyPolicyHardwareKeyTouch, 202 }, { 203 desc: "policy error string contained in error", 204 errIn: trace.Errorf("ssh: rejected: administratively prohibited (%s)", keys.NewPrivateKeyPolicyError(keys.PrivateKeyPolicyHardwareKeyTouch).Error()), 205 expectIsKeyPolicy: true, 206 expectKeyPolicy: keys.PrivateKeyPolicyHardwareKeyTouch, 207 }, 208 } 209 210 for _, policy := range privateKeyPolicies { 211 testCases = append(testCases, testCase{ 212 desc: fmt.Sprintf("valid key policy: %v", policy), 213 errIn: keys.NewPrivateKeyPolicyError(policy), 214 expectIsKeyPolicy: true, 215 expectKeyPolicy: policy, 216 }) 217 } 218 219 for _, tc := range testCases { 220 t.Run(tc.desc, func(t *testing.T) { 221 require.Equal(t, tc.expectIsKeyPolicy, keys.IsPrivateKeyPolicyError(tc.errIn)) 222 223 keyPolicy, err := keys.ParsePrivateKeyPolicyError(tc.errIn) 224 if tc.expectParseKeyPolicyErr { 225 require.Error(t, err) 226 } else { 227 require.NoError(t, err) 228 require.Equal(t, tc.expectKeyPolicy, keyPolicy) 229 } 230 }) 231 } 232 }