mirror of
https://github.com/hanzoai/pubsub.git
synced 2026-10-30 15:06:26 +00:00
249 lines
5.7 KiB
Go
249 lines
5.7 KiB
Go
// Copyright 2024 The NATS Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//go:build windows
|
|
|
|
package server
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nats-io/nats.go"
|
|
)
|
|
|
|
// The tests in this file are not complete, but are a start to test the TPM
|
|
// with default settings. For a complete test we would need to use a TPM
|
|
// configured with an owner password and a SRK password. This is not
|
|
// typically the default or setup in CI/CD environments.
|
|
|
|
var jsTPMConfigPassword = `
|
|
listen: 127.0.0.1:-1
|
|
jetstream: {
|
|
store_dir: %q
|
|
tpm {
|
|
keys_file: %q
|
|
encryption_password: "s3cr3t!"
|
|
}
|
|
}`
|
|
|
|
var jsTPMConfigBadPassword = `
|
|
listen: 127.0.0.1:-1
|
|
jetstream: {
|
|
store_dir: %q
|
|
tpm {
|
|
keys_file: %q
|
|
encryption_password: "garbage"
|
|
}
|
|
}`
|
|
|
|
var jsTPMConfigPasswordPcr = `
|
|
listen: 127.0.0.1:-1
|
|
jetstream: {
|
|
store_dir: %q
|
|
tpm {
|
|
keys_file: %q
|
|
encryption_password: "s3cr3t!"
|
|
pcr: %d
|
|
}
|
|
}`
|
|
|
|
var jsTPMConfigAllFields = `
|
|
listen: 127.0.0.1:-1
|
|
jetstream: {
|
|
store_dir: %q
|
|
tpm {
|
|
keys_file: %q
|
|
encryption_password: "s3cr3t!"
|
|
pcr: %d
|
|
srk_password: %q
|
|
cipher: "aes"
|
|
}
|
|
}`
|
|
|
|
var jsTPMConfigInvalidBothOptionsSet = `
|
|
listen: 127.0.0.1:-1
|
|
jetstream: {
|
|
store_dir: %q
|
|
encryption_key: "foo"
|
|
tpm {
|
|
keys_file: "bar.json"
|
|
encryption_password: "s3cr3t!"
|
|
}
|
|
}`
|
|
|
|
func getTPMFileName(t *testing.T) string {
|
|
return t.TempDir() + "/" + t.Name() + "/jskeys.json"
|
|
}
|
|
|
|
func checkSendMessage(t *testing.T, s *Server) {
|
|
nc, js := jsClientConnect(t, s)
|
|
defer nc.Close()
|
|
|
|
_, err := js.AddStream(&nats.StreamConfig{
|
|
Name: "tpm_test",
|
|
Subjects: []string{"tpm_test"},
|
|
})
|
|
require_NoError(t, err)
|
|
|
|
_, err = js.Publish("tpm_test", []byte("hello"))
|
|
require_NoError(t, err)
|
|
}
|
|
|
|
func checkReceiveMessage(t *testing.T, s *Server) {
|
|
// reconnect and get the message
|
|
nc, js := jsClientConnect(t, s)
|
|
defer nc.Close()
|
|
|
|
// get the message
|
|
sub, err := js.PullSubscribe("tpm_test", "cls")
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
m := fetchMsgs(t, sub, 1, 5*time.Second)
|
|
if m == nil {
|
|
t.Fatalf("Did not receive the message")
|
|
}
|
|
if len(m) != 1 {
|
|
t.Fatalf("Expected 1 message, got %d", len(m))
|
|
}
|
|
}
|
|
|
|
func TestJetStreamTPMBasic(t *testing.T) {
|
|
fileName := getTPMFileName(t)
|
|
cf := createConfFile(t, []byte(fmt.Sprintf(jsTPMConfigPassword, t.TempDir(), fileName)))
|
|
|
|
s, _ := RunServerWithConfig(cf)
|
|
defer s.Shutdown()
|
|
|
|
// Note, actual encryption is tested elsewhere. This just tests that the key is generated.
|
|
key := s.opts.JetStreamKey
|
|
if !strings.HasPrefix(key, "SU") {
|
|
t.Fatalf("expected a TPM key to be generated. Key = %q", key)
|
|
}
|
|
|
|
if _, err := os.Stat(fileName); err != nil {
|
|
t.Fatalf("keys file was not created")
|
|
}
|
|
|
|
checkSendMessage(t, s)
|
|
|
|
// restart the server.
|
|
s.Shutdown()
|
|
s, _ = RunServerWithConfig(cf)
|
|
if s.Running() == false {
|
|
t.Fatalf("Server should be running")
|
|
}
|
|
defer s.Shutdown()
|
|
|
|
// double check we're encrypted with the same key.
|
|
if s.opts.JetStreamKey != key {
|
|
t.Fatalf("expected same key")
|
|
}
|
|
checkReceiveMessage(t, s)
|
|
}
|
|
|
|
// Warning: Running this test too frequently will considerably slow down
|
|
// these tests and eventually lock out the TPM.
|
|
//
|
|
// Depending on the environment this varies from 10 failures per day with
|
|
// a 24 hour lockout (Dell) to 32 failures per day with a 10
|
|
// minute healing time (decrementing one failure every 10 minutes).
|
|
func TestJetStreamTPMKeyBadPassword(t *testing.T) {
|
|
fileName := getTPMFileName(t)
|
|
cf := createConfFile(t, []byte(fmt.Sprintf(jsTPMConfigPassword,
|
|
t.TempDir(), fileName)))
|
|
|
|
s, _ := RunServerWithConfig(cf)
|
|
defer s.Shutdown()
|
|
|
|
checkSendMessage(t, s)
|
|
s.Shutdown()
|
|
|
|
// restart the server.
|
|
defer func() {
|
|
r := recover()
|
|
if r == nil {
|
|
t.Fatalf("Expected server panic, unexpected start.")
|
|
}
|
|
}()
|
|
cf2 := createConfFile(t, []byte(fmt.Sprintf(jsTPMConfigBadPassword,
|
|
t.TempDir(), fileName)))
|
|
s, _ = RunServerWithConfig(cf2)
|
|
time.Sleep(3 * time.Second)
|
|
if s.Running() {
|
|
s.Shutdown()
|
|
t.Fatalf("Server should NOT be running")
|
|
}
|
|
}
|
|
|
|
func TestJetStreamTPMKeyWithPCR(t *testing.T) {
|
|
cf := createConfFile(t, []byte(fmt.Sprintf(jsTPMConfigPasswordPcr,
|
|
t.TempDir(), getTPMFileName(t), 18)))
|
|
|
|
s, _ := RunServerWithConfig(cf)
|
|
defer s.Shutdown()
|
|
|
|
checkSendMessage(t, s)
|
|
s.Shutdown()
|
|
|
|
// restart the server
|
|
s, _ = RunServerWithConfig(cf)
|
|
if !s.Running() {
|
|
t.Fatalf("Server should be running")
|
|
}
|
|
}
|
|
|
|
func TestJetStreamTPMAll(t *testing.T) {
|
|
fileName := getTPMFileName(t)
|
|
|
|
// TODO: When the CI/CD environment supports updating the TPM,
|
|
// expand this test with the SRK password.
|
|
cf := createConfFile(t, []byte(fmt.Sprintf(jsTPMConfigAllFields,
|
|
getTPMFileName(t), fileName, 19, "")))
|
|
|
|
s, _ := RunServerWithConfig(cf)
|
|
defer s.Shutdown()
|
|
|
|
checkSendMessage(t, s)
|
|
s.Shutdown()
|
|
|
|
// restart the server.
|
|
s, _ = RunServerWithConfig(cf)
|
|
if s.Running() == false {
|
|
t.Fatalf("Server should be running")
|
|
}
|
|
defer s.Shutdown()
|
|
checkReceiveMessage(t, s)
|
|
}
|
|
|
|
func TestJetStreamInvalidConfig(t *testing.T) {
|
|
cf := createConfFile(t, []byte(fmt.Sprintf(jsTPMConfigInvalidBothOptionsSet,
|
|
getTPMFileName(t))))
|
|
|
|
defer func() {
|
|
r := recover()
|
|
if r == nil {
|
|
t.Fatalf("Expected server panic, unexpected start.")
|
|
}
|
|
}()
|
|
s, _ := RunServerWithConfig(cf)
|
|
if s.Running() == true {
|
|
s.Shutdown()
|
|
t.Fatalf("Server should NOT be running")
|
|
}
|
|
}
|