consul/agent/token/store_test.go
John Landa 9eaa8eb026
dns token (#17936)
* dns token

fix whitespace for docs and comments

fix test cases

fix test cases

remove tabs in help text

Add changelog

Peering dns test

Peering dns test

Partial implementation of Peered DNS test

Swap to new topology lib

expose dns port for integration tests on client

remove partial test implementation

remove extra port exposure

remove changelog from the ent pr

Add dns token to set-agent-token switch

Add enterprise golden file

Use builtin/dns template in tests

Update ent dns policy

Update ent dns template test

remove local gen certs

fix templated policy specs

* add changelog

* go mod tidy
2023-09-20 15:50:06 -06:00

338 lines
12 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package token
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestStore_RegularTokens(t *testing.T) {
type tokens struct {
userSource TokenSource
user string
agent string
agentSource TokenSource
recovery string
recoverySource TokenSource
repl string
replSource TokenSource
registration string
registrationSource TokenSource
dns string
dnsSource TokenSource
}
tests := []struct {
name string
set tokens
raw tokens
effective tokens
}{
{
name: "set user - config",
set: tokens{user: "U", userSource: TokenSourceConfig},
raw: tokens{user: "U", userSource: TokenSourceConfig},
effective: tokens{user: "U", agent: "U"},
},
{
name: "set user - api",
set: tokens{user: "U", userSource: TokenSourceAPI},
raw: tokens{user: "U", userSource: TokenSourceAPI},
effective: tokens{user: "U", agent: "U"},
},
{
name: "set agent - config",
set: tokens{agent: "A", agentSource: TokenSourceConfig},
raw: tokens{agent: "A", agentSource: TokenSourceConfig},
effective: tokens{agent: "A"},
},
{
name: "set agent - api",
set: tokens{agent: "A", agentSource: TokenSourceAPI},
raw: tokens{agent: "A", agentSource: TokenSourceAPI},
effective: tokens{agent: "A"},
},
{
name: "set user and agent",
set: tokens{agent: "A", user: "U"},
raw: tokens{agent: "A", user: "U"},
effective: tokens{agent: "A", user: "U"},
},
{
name: "set repl - config",
set: tokens{repl: "R", replSource: TokenSourceConfig},
raw: tokens{repl: "R", replSource: TokenSourceConfig},
effective: tokens{repl: "R"},
},
{
name: "set repl - api",
set: tokens{repl: "R", replSource: TokenSourceAPI},
raw: tokens{repl: "R", replSource: TokenSourceAPI},
effective: tokens{repl: "R"},
},
{
name: "set recovery - config",
set: tokens{recovery: "M", recoverySource: TokenSourceConfig},
raw: tokens{recovery: "M", recoverySource: TokenSourceConfig},
effective: tokens{recovery: "M"},
},
{
name: "set recovery - api",
set: tokens{recovery: "M", recoverySource: TokenSourceAPI},
raw: tokens{recovery: "M", recoverySource: TokenSourceAPI},
effective: tokens{recovery: "M"},
},
{
name: "set registration - config",
set: tokens{registration: "G", registrationSource: TokenSourceConfig},
raw: tokens{registration: "G", registrationSource: TokenSourceConfig},
effective: tokens{registration: "G"},
},
{
name: "set registration - api",
set: tokens{registration: "G", registrationSource: TokenSourceAPI},
raw: tokens{registration: "G", registrationSource: TokenSourceAPI},
effective: tokens{registration: "G"},
},
{
name: "set dns - config",
set: tokens{dns: "D", dnsSource: TokenSourceConfig},
raw: tokens{dns: "D", dnsSource: TokenSourceConfig},
effective: tokens{dns: "D"},
},
{
name: "set dns - api",
set: tokens{dns: "D", dnsSource: TokenSourceAPI},
raw: tokens{dns: "D", dnsSource: TokenSourceAPI},
effective: tokens{dns: "D"},
},
{
name: "set all",
set: tokens{user: "U", agent: "A", repl: "R", recovery: "M", registration: "G", dns: "D"},
raw: tokens{user: "U", agent: "A", repl: "R", recovery: "M", registration: "G", dns: "D"},
effective: tokens{user: "U", agent: "A", repl: "R", recovery: "M", registration: "G", dns: "D"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := new(Store)
if tt.set.user != "" {
require.True(t, s.UpdateUserToken(tt.set.user, tt.set.userSource))
}
if tt.set.agent != "" {
require.True(t, s.UpdateAgentToken(tt.set.agent, tt.set.agentSource))
}
if tt.set.repl != "" {
require.True(t, s.UpdateReplicationToken(tt.set.repl, tt.set.replSource))
}
if tt.set.recovery != "" {
require.True(t, s.UpdateAgentRecoveryToken(tt.set.recovery, tt.set.recoverySource))
}
if tt.set.registration != "" {
require.True(t, s.UpdateConfigFileRegistrationToken(tt.set.registration, tt.set.registrationSource))
}
if tt.set.dns != "" {
require.True(t, s.UpdateDNSToken(tt.set.dns, tt.set.dnsSource))
}
// If they don't change then they return false.
require.False(t, s.UpdateUserToken(tt.set.user, tt.set.userSource))
require.False(t, s.UpdateAgentToken(tt.set.agent, tt.set.agentSource))
require.False(t, s.UpdateReplicationToken(tt.set.repl, tt.set.replSource))
require.False(t, s.UpdateAgentRecoveryToken(tt.set.recovery, tt.set.recoverySource))
require.False(t, s.UpdateConfigFileRegistrationToken(tt.set.registration, tt.set.registrationSource))
require.False(t, s.UpdateDNSToken(tt.set.dns, tt.set.dnsSource))
require.Equal(t, tt.effective.user, s.UserToken())
require.Equal(t, tt.effective.agent, s.AgentToken())
require.Equal(t, tt.effective.recovery, s.AgentRecoveryToken())
require.Equal(t, tt.effective.repl, s.ReplicationToken())
require.Equal(t, tt.effective.registration, s.ConfigFileRegistrationToken())
require.Equal(t, tt.effective.dns, s.DNSToken())
tok, src := s.UserTokenAndSource()
require.Equal(t, tt.raw.user, tok)
require.Equal(t, tt.raw.userSource, src)
tok, src = s.AgentTokenAndSource()
require.Equal(t, tt.raw.agent, tok)
require.Equal(t, tt.raw.agentSource, src)
tok, src = s.AgentRecoveryTokenAndSource()
require.Equal(t, tt.raw.recovery, tok)
require.Equal(t, tt.raw.recoverySource, src)
tok, src = s.ReplicationTokenAndSource()
require.Equal(t, tt.raw.repl, tok)
require.Equal(t, tt.raw.replSource, src)
tok, src = s.ConfigFileRegistrationTokenAndSource()
require.Equal(t, tt.raw.registration, tok)
require.Equal(t, tt.raw.registrationSource, src)
tok, src = s.DNSTokenAndSource()
require.Equal(t, tt.raw.dns, tok)
require.Equal(t, tt.raw.dnsSource, src)
})
}
}
func TestStore_AgentRecoveryToken(t *testing.T) {
s := new(Store)
verify := func(want bool, toks ...string) {
for _, tok := range toks {
require.Equal(t, want, s.IsAgentRecoveryToken(tok))
}
}
verify(false, "", "nope")
s.UpdateAgentRecoveryToken("recovery", TokenSourceConfig)
verify(true, "recovery")
verify(false, "", "nope")
s.UpdateAgentRecoveryToken("another", TokenSourceConfig)
verify(true, "another")
verify(false, "", "nope", "recovery")
s.UpdateAgentRecoveryToken("", TokenSourceConfig)
verify(false, "", "nope", "recovery", "another")
}
func TestStore_Notify(t *testing.T) {
s := new(Store)
newNotification := func(t *testing.T, s *Store, kind TokenKind) Notifier {
n := s.Notify(kind)
require.NotNil(t, n.Ch)
return n
}
requireNotNotified := func(t *testing.T, ch <-chan struct{}) {
require.Empty(t, ch)
}
requireNotifiedOnce := func(t *testing.T, ch <-chan struct{}) {
require.Len(t, ch, 1)
// drain the channel
<-ch
// just to be safe
require.Empty(t, ch)
}
agentNotifier := newNotification(t, s, TokenKindAgent)
userNotifier := newNotification(t, s, TokenKindUser)
agentRecoveryNotifier := newNotification(t, s, TokenKindAgentRecovery)
replicationNotifier := newNotification(t, s, TokenKindReplication)
replicationNotifier2 := newNotification(t, s, TokenKindReplication)
registrationNotifier := newNotification(t, s, TokenKindConfigFileRegistration)
dnsNotifier := newNotification(t, s, TokenKindDNS)
// perform an update of the user token
require.True(t, s.UpdateUserToken("edcae2a2-3b51-4864-b412-c7a568f49cb1", TokenSourceConfig))
// do it again to ensure it doesn't block even though nothing has read from the 1 buffered chan yet
require.True(t, s.UpdateUserToken("47788919-f944-476a-bda5-446d64be1df8", TokenSourceAPI))
// ensure notifications were sent to the user notifier and all other notifiers were not notified.
requireNotNotified(t, agentNotifier.Ch)
requireNotifiedOnce(t, userNotifier.Ch)
requireNotNotified(t, replicationNotifier.Ch)
requireNotNotified(t, agentRecoveryNotifier.Ch)
requireNotNotified(t, replicationNotifier2.Ch)
requireNotNotified(t, registrationNotifier.Ch)
requireNotNotified(t, dnsNotifier.Ch)
// update the agent token which should send a notification to the agent notifier.
require.True(t, s.UpdateAgentToken("5d748ec2-d536-461f-8e2a-1f7eae98d559", TokenSourceAPI))
requireNotifiedOnce(t, agentNotifier.Ch)
requireNotNotified(t, userNotifier.Ch)
requireNotNotified(t, replicationNotifier.Ch)
requireNotNotified(t, agentRecoveryNotifier.Ch)
requireNotNotified(t, replicationNotifier2.Ch)
requireNotNotified(t, registrationNotifier.Ch)
requireNotNotified(t, dnsNotifier.Ch)
// update the agent recovery token which should send a notification to the agent recovery notifier.
require.True(t, s.UpdateAgentRecoveryToken("789badc8-f850-43e1-8742-9b9f484957cc", TokenSourceAPI))
requireNotNotified(t, agentNotifier.Ch)
requireNotNotified(t, userNotifier.Ch)
requireNotNotified(t, replicationNotifier.Ch)
requireNotifiedOnce(t, agentRecoveryNotifier.Ch)
requireNotNotified(t, replicationNotifier2.Ch)
requireNotNotified(t, registrationNotifier.Ch)
requireNotNotified(t, dnsNotifier.Ch)
// update the replication token which should send a notification to the replication notifier.
require.True(t, s.UpdateReplicationToken("789badc8-f850-43e1-8742-9b9f484957cc", TokenSourceAPI))
requireNotNotified(t, agentNotifier.Ch)
requireNotNotified(t, userNotifier.Ch)
requireNotifiedOnce(t, replicationNotifier.Ch)
requireNotNotified(t, agentRecoveryNotifier.Ch)
requireNotifiedOnce(t, replicationNotifier2.Ch)
requireNotNotified(t, registrationNotifier.Ch)
requireNotNotified(t, dnsNotifier.Ch)
s.StopNotify(replicationNotifier2)
// update the replication token which should send a notification to the replication notifier.
require.True(t, s.UpdateReplicationToken("eb0b56b9-fa65-4ae1-902a-c64457c62ac6", TokenSourceAPI))
requireNotNotified(t, agentNotifier.Ch)
requireNotNotified(t, userNotifier.Ch)
requireNotifiedOnce(t, replicationNotifier.Ch)
requireNotNotified(t, agentRecoveryNotifier.Ch)
requireNotNotified(t, replicationNotifier2.Ch)
requireNotNotified(t, registrationNotifier.Ch)
requireNotNotified(t, dnsNotifier.Ch)
// update the config file registration token which should send a notification to the replication notifier.
require.True(t, s.UpdateConfigFileRegistrationToken("82fe7362-7d83-4f43-bb27-c35f1f15083c", TokenSourceAPI))
requireNotNotified(t, agentNotifier.Ch)
requireNotNotified(t, userNotifier.Ch)
requireNotNotified(t, replicationNotifier.Ch)
requireNotNotified(t, agentRecoveryNotifier.Ch)
requireNotNotified(t, replicationNotifier2.Ch)
requireNotifiedOnce(t, registrationNotifier.Ch)
requireNotNotified(t, dnsNotifier.Ch)
// update the dns token which should send a notification to the replication notifier.
require.True(t, s.UpdateDNSToken("ce8e829f-dc45-4ba7-9dd3-1dbbe070f573", TokenSourceAPI))
requireNotNotified(t, agentNotifier.Ch)
requireNotNotified(t, userNotifier.Ch)
requireNotNotified(t, replicationNotifier.Ch)
requireNotNotified(t, agentRecoveryNotifier.Ch)
requireNotNotified(t, replicationNotifier2.Ch)
requireNotNotified(t, registrationNotifier.Ch)
requireNotifiedOnce(t, dnsNotifier.Ch)
// request updates that are not changes
require.False(t, s.UpdateAgentToken("5d748ec2-d536-461f-8e2a-1f7eae98d559", TokenSourceAPI))
require.False(t, s.UpdateAgentRecoveryToken("789badc8-f850-43e1-8742-9b9f484957cc", TokenSourceAPI))
require.False(t, s.UpdateUserToken("47788919-f944-476a-bda5-446d64be1df8", TokenSourceAPI))
require.False(t, s.UpdateReplicationToken("eb0b56b9-fa65-4ae1-902a-c64457c62ac6", TokenSourceAPI))
require.False(t, s.UpdateConfigFileRegistrationToken("82fe7362-7d83-4f43-bb27-c35f1f15083c", TokenSourceAPI))
require.False(t, s.UpdateDNSToken("ce8e829f-dc45-4ba7-9dd3-1dbbe070f573", TokenSourceAPI))
// ensure that notifications were not sent
requireNotNotified(t, agentNotifier.Ch)
requireNotNotified(t, userNotifier.Ch)
requireNotNotified(t, replicationNotifier.Ch)
requireNotNotified(t, agentRecoveryNotifier.Ch)
requireNotNotified(t, registrationNotifier.Ch)
requireNotNotified(t, dnsNotifier.Ch)
}