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(&lt).Elem().Field(i).SetString("nonempty")
   133  		require.False(t, lt.IsEmpty(), "field name: %v", field.Name)
   134  	}
   135  }