refact(bsr): Use JSON for session meta and summary data

The session metadata is provided all at once when a new bsr is opened.
While the session recording metadata records metadata about a recording
while the recording is happening, notably it records each time a new
connection occurs.

The nested structure of the session metadata does not lend itself to the
append-only syntax of the recording meta file. In addition we do not
want to mix different kinds of metadata together. Thus the session
metadata is now written to a separate file in the BSR, and is written as
JSON which better handles the nested structure and allows for simpler
encoding/decoding.

Similarly the summary files are intended to be written to as containers
close and have been switched to JSON.
This commit is contained in:
Timothy Messier committed 2023-05-31 12:18:23 +00:00
1 parent 7dc15f1f39
commit 78ea1a9f3a
50 files changed
+738 -1718

No files matched your search

+53 -570
View File
@@ -4,13 +4,11 @@
package bsr
import (
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"strconv"
"strings"
"github.com/hashicorp/boundary/internal/bsr/internal/checksum"
"github.com/hashicorp/boundary/internal/bsr/internal/is"
@@ -21,11 +19,12 @@ import (
)
const (
bsrFile = "%s.bsr"
connectionFile = "%s.connection"
channelFile = "%s.channel"
messagesFile = "messages-%s.data"
requestsFile = "requests-%s.data"
bsrFile = "%s.bsr"
connectionFile = "%s.connection"
channelFile = "%s.channel"
messagesFile = "messages-%s.data"
requestsFile = "requests-%s.data"
sessionMetaFile = "session-meta.json"
bsrPubKeyFile = "bsrKey.pub"
wrappedBsrKeyFile = "wrappedBsrKey"
@@ -34,479 +33,38 @@ const (
pubKeySelfSignatureFile = "pubKeySelfSignature.sign"
)
// decodeSessionMeta will populate a SessionMeta for an opened BSR Session
// TODO Unmarshal without brute force
func decodeSessionMeta(ctx context.Context, r io.Reader) (*SessionMeta, error) {
const op = "bsr.decodeSessionMeta"
switch {
case r == nil:
return nil, fmt.Errorf("%s: missing session meta file: %w", op, ErrInvalidParameter)
}
connections := make(map[string]bool)
s := &SessionMeta{}
user := &User{Scope: Scope{}}
target := &Target{Scope: Scope{}}
worker := &Worker{}
sHost := &StaticHost{Catalog: StaticHostCatalog{}}
dHost := &DynamicHost{Catalog: DynamicHostCatalog{}}
staticCredStore := make(map[string]StaticCredentialStore)
scStoreToJsonCreds := make(map[string]StaticJsonCredential)
scStoreToUPCreds := make(map[string]StaticUsernamePasswordCredential)
scStoreToSshCreds := make(map[string]StaticSshPrivateKeyCredential)
vaultCredStore := make(map[string]VaultCredentialStore)
vsStoreToVaultLib := make(map[string]VaultLibrary)
vsStoreToVaultSshCertLib := make(map[string]VaultSshCertLibrary)
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
if len(l) == 0 {
continue
}
k, v, ok := strings.Cut(l, ":")
if !ok {
return nil, fmt.Errorf("%s: session meta file contains invalid entry; expecting k: v pair:%s", op, l)
}
v = strings.TrimSpace(v)
switch {
case k == "id":
s.Id = v
case k == "protocol":
s.Protocol = Protocol(v)
// User
case k == "user_publicId":
user.PublicId = v
case k == "user_name":
user.Name = v
case k == "user_description":
user.Description = v
case k == "user_scope_publicId":
user.Scope.PublicId = v
case k == "user_scope_name":
user.Scope.Name = v
case k == "user_scope_description":
user.Scope.Description = v
case k == "user_scope_type":
user.Scope.Type = v
case k == "user_scope_parentId":
user.Scope.ParentId = v
case k == "user_scope_primaryAuthMethod":
user.Scope.PrimaryAuthMethodId = v
// Target
case k == "target_publicId":
target.PublicId = v
case k == "target_name":
target.Name = v
case k == "target_description":
target.Description = v
case k == "target_defaultPort":
dp, err := strconv.Atoi(v)
if err != nil {
return nil, err
}
target.DefaultPort = uint32(dp)
case k == "target_sessionMaxSeconds":
sms, err := strconv.Atoi(v)
if err != nil {
return nil, err
}
target.SessionMaxSeconds = uint32(sms)
case k == "target_sessionConnectionLimit":
scl, err := strconv.Atoi(v)
if err != nil {
return nil, err
}
target.SessionConnectionLimit = int32(scl)
case k == "target_workerFilter":
target.WorkerFilter = v
case k == "target_egressWorkerFilter":
target.EgressWorkerFilter = v
case k == "target_ingressWorkerFilter":
target.IngressWorkerFilter = v
case k == "target_scope_publicId":
target.Scope.PublicId = v
case k == "target_scope_name":
target.Scope.Name = v
case k == "target_scope_description":
target.Scope.Description = v
case k == "target_scope_type":
target.Scope.Type = v
case k == "target_scope_parentId":
target.Scope.ParentId = v
case k == "target_scope_primaryAuthMethod":
target.Scope.PrimaryAuthMethodId = v
// Worker
case k == "worker_publicId":
worker.PublicId = v
case k == "worker_version":
worker.Version = v
case k == "worker_sha":
worker.Sha = v
// Static Host
case k == "staticHost_publicId":
sHost.PublicId = v
case k == "staticHost_name":
sHost.Name = v
case k == "staticHost_description":
sHost.Description = v
case k == "staticHost_address":
sHost.Address = v
case k == "staticHostCatalog_publicId":
sHost.Catalog.PublicId = v
case k == "staticHostCatalog_projectId":
sHost.Catalog.ProjectId = v
case k == "staticHostCatalog_name":
sHost.Catalog.Name = v
case k == "staticHostCatalog_description":
sHost.Catalog.Description = v
// Dynamic Host
case k == "dynamicHost_publicId":
dHost.PublicId = v
case k == "dynamicHost_name":
dHost.Name = v
case k == "dynamicHost_description":
dHost.Description = v
case k == "dynamicHost_externalId":
dHost.ExternalId = v
case k == "dynamicHostCatalog_publicId":
dHost.Catalog.PublicId = v
case k == "dynamicHostCatalog_projectId":
dHost.Catalog.ProjectId = v
case k == "dynamicHostCatalog_name":
dHost.Catalog.Name = v
case k == "dynamicHostCatalog_description":
dHost.Catalog.Description = v
case k == "dynamicHostCatalog_pluginId":
dHost.Catalog.PluginId = v
case k == "dynamicHostCatalog_attributes":
dHost.Catalog.Attributes = v
// Static Credential Store
case strings.Contains(k, "staticCredentialStore_"):
idx := strings.Index(k, "_staticCredentialStore")
if idx == -1 {
break
}
sId := k[:idx]
scs, ok := staticCredStore[sId]
if !ok {
scs = StaticCredentialStore{
PublicId: sId,
}
}
switch {
case strings.Contains(k, "staticJsonCredential"):
idxEnd := strings.Index(k, "_staticJsonCredential")
idxStart := strings.Index(k, "_credential_") + len("_credential_")
if idxStart == -1 || idxEnd == -1 {
break
}
credId := k[idxStart:idxEnd]
// credstoreid - staticJsonCredentialid in the map
mapId := fmt.Sprintf("%s-%s", sId, credId)
c, ok := scStoreToJsonCreds[mapId]
if !ok {
c = StaticJsonCredential{
PublicId: credId,
}
}
switch {
case strings.Contains(k, "_projectId"):
c.ProjectId = v
case strings.Contains(k, "_name"):
c.Name = v
case strings.Contains(k, "_description"):
c.Description = v
case strings.Contains(k, "_objectHmac"):
c.ObjectHmac = []byte(v)
}
scStoreToJsonCreds[mapId] = c
case strings.Contains(k, "staticUsernamePasswordCredential"):
idxEnd := strings.Index(k, "_staticJUsernamePasswordCredential")
idxStart := strings.Index(k, "_credential_") + len("_credential_")
if idxStart == -1 || idxEnd == -1 {
break
}
credId := k[idxStart:idxEnd]
// credstoreid - UsernamePasswordCredentialid in the map
mapId := fmt.Sprintf("%s-%s", sId, credId)
c, ok := scStoreToUPCreds[mapId]
if !ok {
c = StaticUsernamePasswordCredential{
PublicId: credId,
}
}
switch {
case strings.Contains(k, "_projectId"):
c.ProjectId = v
case strings.Contains(k, "_name"):
c.Name = v
case strings.Contains(k, "_description"):
c.Description = v
case strings.Contains(k, "_passwordHmac"):
c.PasswordHmac = []byte(v)
}
scStoreToUPCreds[mapId] = c
case strings.Contains(k, "staticSshPrivateKeyCredential"):
idxEnd := strings.Index(k, "_staticSshPrivateKeyCredential")
idxStart := strings.Index(k, "_credential_") + len("_credential_")
if idxStart == -1 || idxEnd == -1 {
break
}
credId := k[idxStart:idxEnd]
// credstoreid - staticSshPrivateKeyid in the map
mapId := fmt.Sprintf("%s-%s", sId, credId)
c, ok := scStoreToSshCreds[mapId]
if !ok {
c = StaticSshPrivateKeyCredential{
PublicId: credId,
}
}
switch {
case strings.Contains(k, "_projectId"):
c.ProjectId = v
case strings.Contains(k, "_name"):
c.Name = v
case strings.Contains(k, "_description"):
c.Description = v
case strings.Contains(k, "_privateKeyHmac"):
c.PrivateKeyHmac = []byte(v)
case strings.Contains(k, "_privateKeyPassphraseHmac"):
c.PrivateKeyPassphraseHmac = []byte(v)
}
scStoreToSshCreds[mapId] = c
case strings.Contains(k, "_projectId"):
scs.ProjectId = v
case strings.Contains(k, "_name"):
scs.Name = v
case strings.Contains(k, "_description"):
scs.Description = v
}
staticCredStore[sId] = scs
// Vault Credential Store
case strings.Contains(k, "vaultCredentialStore_"):
idx := strings.Index(k, "_vaultCredentialStore")
if idx == -1 {
break
}
vId := k[:idx]
vcs, ok := vaultCredStore[vId]
if !ok {
vcs = VaultCredentialStore{
PublicId: vId,
}
}
switch {
case strings.Contains(k, "vaultLibrary"):
idxEnd := strings.Index(k, "_vaultLibrary")
idxStart := strings.Index(k, "_credential_") + len("_credential_")
if idxStart == -1 || idxEnd == -1 {
break
}
credId := k[idxStart:idxEnd]
// credstoreid - vaultLibraryid in the map
mapId := fmt.Sprintf("%s-%s", vId, credId)
c, ok := vsStoreToVaultLib[mapId]
if !ok {
c = VaultLibrary{
PublicId: credId,
}
}
switch {
case strings.Contains(k, "_projectId"):
c.ProjectId = v
case strings.Contains(k, "_name"):
c.Name = v
case strings.Contains(k, "_description"):
c.Description = v
case strings.Contains(k, "_vaultPath"):
c.VaultPath = v
case strings.Contains(k, "_httpMethod"):
c.HttpMethod = v
case strings.Contains(k, "_httpRequestBody"):
c.HttpRequestBody = []byte(v)
case strings.Contains(k, "_credentialType"):
c.CredentialType = v
}
vsStoreToVaultLib[mapId] = c
case strings.Contains(k, "vaultSshCertLibrary"):
idxEnd := strings.Index(k, "_vaultSshCertLibrary")
idxStart := strings.Index(k, "_credential_") + len("_credential_")
if idxStart == -1 || idxEnd == -1 {
break
}
credId := k[idxStart:idxEnd]
// credstoreid - vaultSshCertLibraryid in the map
mapId := fmt.Sprintf("%s-%s", vId, credId)
c, ok := vsStoreToVaultSshCertLib[mapId]
if !ok {
c = VaultSshCertLibrary{
PublicId: credId,
}
}
switch {
case strings.Contains(k, "_projectId"):
c.ProjectId = v
case strings.Contains(k, "_username"):
c.Username = v
case strings.Contains(k, "_name"):
c.Name = v
case strings.Contains(k, "_description"):
c.Description = v
case strings.Contains(k, "_vaultPath"):
c.VaultPath = v
case strings.Contains(k, "_keyType"):
c.KeyType = v
case strings.Contains(k, "_keyBits"):
var err error
c.KeyBits, err = strconv.Atoi(v)
if err != nil {
return nil, err
}
case strings.Contains(k, "_ttl"):
c.Ttl = v
case strings.Contains(k, "_criticalOptions"):
c.CriticalOptions = []byte(v)
case strings.Contains(k, "_extensions"):
c.Extensions = []byte(v)
case strings.Contains(k, "_credentialType"):
c.CredentialType = v
}
vsStoreToVaultSshCertLib[mapId] = c
case strings.Contains(k, "_projectId"):
vcs.ProjectId = v
case strings.Contains(k, "_namespace"):
vcs.Namespace = v
case strings.Contains(k, "_name"):
vcs.Name = v
case strings.Contains(k, "_description"):
vcs.Description = v
case strings.Contains(k, "_vaultAddress"):
vcs.VaultAddress = v
case strings.Contains(k, "_tlsServerName"):
vcs.TlsServerName = v
case strings.Contains(k, "_tlsSkipVerify"):
var err error
vcs.TlsSkipVerify, err = strconv.ParseBool(v)
if err != nil {
return nil, err
}
case strings.Contains(k, "_workerFilter"):
vcs.WorkerFilter = v
}
vaultCredStore[vId] = vcs
// connections
case k == "connection":
connections[v] = true
}
}
s.Target = target
s.Worker = worker
s.User = user
if sHost.PublicId != "" {
s.StaticHost = sHost
}
if dHost.PublicId != "" {
s.DynamicHost = dHost
}
for k, v := range scStoreToJsonCreds {
scId, _, ok := strings.Cut(k, "-")
if ok {
staticCred := staticCredStore[scId]
staticCred.Credentials = append(staticCred.Credentials, v)
staticCredStore[scId] = staticCred
}
}
for k, v := range scStoreToUPCreds {
scId, _, ok := strings.Cut(k, "-")
if ok {
staticCred := staticCredStore[scId]
staticCred.Credentials = append(staticCred.Credentials, v)
staticCredStore[scId] = staticCred
}
}
for k, v := range scStoreToSshCreds {
scId, _, ok := strings.Cut(k, "-")
if ok {
staticCred := staticCredStore[scId]
staticCred.Credentials = append(staticCred.Credentials, v)
staticCredStore[scId] = staticCred
}
}
scStores := make([]StaticCredentialStore, 0)
for _, v := range staticCredStore {
scStores = append(scStores, v)
}
for k, v := range vsStoreToVaultSshCertLib {
vlId, _, ok := strings.Cut(k, "-")
if ok {
vaultLib := vaultCredStore[vlId]
vaultLib.CredentialLibraries = append(vaultLib.CredentialLibraries, v)
vaultCredStore[vlId] = vaultLib
}
}
for k, v := range vsStoreToVaultLib {
vlId, _, ok := strings.Cut(k, "-")
if ok {
vaultLib := vaultCredStore[vlId]
vaultLib.CredentialLibraries = append(vaultLib.CredentialLibraries, v)
vaultCredStore[vlId] = vaultLib
}
}
vcStores := make([]VaultCredentialStore, 0)
for _, v := range vaultCredStore {
vcStores = append(vcStores, v)
}
s.StaticCredentialStore = scStores
s.VaultCredentialStore = vcStores
s.connections = connections
return s, nil
}
// Session is the top level container in a bsr that contains the files for
// a recorded session.
type Session struct {
*container
multiplexed bool
Meta *SessionMeta
Meta *SessionRecordingMeta
SessionMeta *SessionMeta
}
// NewSession creates a Session container for a given session id.
func NewSession(ctx context.Context, meta *SessionMeta, f storage.FS, keys *kms.Keys, options ...Option) (*Session, error) {
func NewSession(ctx context.Context, meta *SessionRecordingMeta, sessionMeta *SessionMeta, f storage.FS, keys *kms.Keys, options ...Option) (*Session, error) {
const op = "bsr.NewSession"
switch {
case is.Nil(meta):
return nil, fmt.Errorf("%s: missing meta: %w", op, ErrInvalidParameter)
case is.Nil(sessionMeta):
return nil, fmt.Errorf("%s: missing session meta: %w", op, ErrInvalidParameter)
case meta.Id == "":
return nil, fmt.Errorf("%s: missing session id: %w", op, ErrInvalidParameter)
case is.Nil(meta.StaticHost) && is.Nil(meta.DynamicHost):
case is.Nil(sessionMeta.StaticHost) && is.Nil(sessionMeta.DynamicHost):
return nil, fmt.Errorf("%s: missing session host information: %w", op, ErrInvalidParameter)
case !is.Nil(meta.StaticHost) && !is.Nil(meta.DynamicHost):
return nil, fmt.Errorf("%s: meta cannot contain both static and dynamic host information: %w", op, ErrInvalidParameter)
case len(meta.StaticCredentialStore) == 0 && len(meta.VaultCredentialStore) == 0:
case !is.Nil(sessionMeta.StaticHost) && !is.Nil(sessionMeta.DynamicHost):
return nil, fmt.Errorf("%s: sessionMeta cannot contain both static and dynamic host information: %w", op, ErrInvalidParameter)
case len(sessionMeta.StaticCredentialStore) == 0 && len(sessionMeta.VaultCredentialStore) == 0:
return nil, fmt.Errorf("%s: missing credential information: %w", op, ErrInvalidParameter)
case is.Nil(meta.User):
case is.Nil(sessionMeta.User):
return nil, fmt.Errorf("%s: missing session user: %w", op, ErrInvalidParameter)
case is.Nil(meta.Target):
case is.Nil(sessionMeta.Target):
return nil, fmt.Errorf("%s: missing session target: %w", op, ErrInvalidParameter)
case is.Nil(meta.Worker):
case is.Nil(sessionMeta.Worker):
return nil, fmt.Errorf("%s: missing session worker: %w", op, ErrInvalidParameter)
case is.Nil(f):
return nil, fmt.Errorf("%s: missing storage fs: %w", op, ErrInvalidParameter)
@@ -532,6 +90,23 @@ func NewSession(ctx context.Context, meta *SessionMeta, f storage.FS, keys *kms.
return nil, errors.Join(err, fmt.Errorf("%s: %w", op, ErrBsrKeyPersistenceFailure))
}
sm, err := nc.create(ctx, sessionMetaFile)
if err != nil {
return nil, err
}
smw, err := checksum.NewFile(ctx, sm, nc.checksums)
if err != nil {
return nil, err
}
enc := json.NewEncoder(smw)
if err := enc.Encode(sessionMeta); err != nil {
smw.Close()
return nil, err
}
if err := smw.Close(); err != nil {
return nil, err
}
err = meta.writeMeta(ctx, nc)
if err != nil {
return nil, err
@@ -541,6 +116,7 @@ func NewSession(ctx context.Context, meta *SessionMeta, f storage.FS, keys *kms.
container: nc,
multiplexed: opts.withSupportsMultiplex,
Meta: meta,
SessionMeta: sessionMeta,
}, nil
}
@@ -618,12 +194,12 @@ func OpenSession(ctx context.Context, sessionRecordingId string, f storage.FS, k
return nil, err
}
// Load and verify session metadata
// Load and verify recording metadata
sha256Reader, err := crypto.NewSha256SumReader(ctx, cc.metaFile)
if err != nil {
return nil, fmt.Errorf("%s: %w", op, err)
}
sm, err := decodeSessionMeta(ctx, sha256Reader)
meta, err := decodeSessionRecordingMeta(ctx, sha256Reader)
if err != nil {
return nil, err
}
@@ -632,9 +208,15 @@ func OpenSession(ctx context.Context, sessionRecordingId string, f storage.FS, k
return nil, err
}
sessionMeta := &SessionMeta{}
if err := cc.decodeJsonFile(ctx, sessionMetaFile, sessionMeta); err != nil {
return nil, err
}
session := &Session{
container: cc,
Meta: sm,
container: cc,
Meta: meta,
SessionMeta: sessionMeta,
}
return session, nil
@@ -645,66 +227,17 @@ func (s *Session) Close(ctx context.Context) error {
return s.container.close(ctx)
}
// ConnectionMeta contains metadata about a connection in a BSR.
type ConnectionMeta struct {
Id string
channels map[string]bool
}
func (c ConnectionMeta) isValid() bool {
switch {
case c.Id == "":
return false
default:
return true
}
}
// Connection is a container in a bsr for a specific connection in a session
// container. It contains the files for the recorded connection.
type Connection struct {
*container
multiplexed bool
Meta *ConnectionMeta
}
// decodeConnectionMeta will populate the ConnectionMeta for a BSR Connection
// TODO Unmarshal without brute force
func decodeConnectionMeta(ctx context.Context, r io.Reader) (*ConnectionMeta, error) {
const op = "bsr.decodeConnectionMeta"
switch {
case r == nil:
return nil, fmt.Errorf("%s: missing connection meta file: %w", op, ErrInvalidParameter)
}
c := &ConnectionMeta{}
channels := make(map[string]bool)
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
if len(l) == 0 {
continue
}
k, v, ok := strings.Cut(l, ":")
if !ok {
return nil, fmt.Errorf("%s: connection meta file contains invalid entry; expecting k: v pair:%s", op, l)
}
v = strings.TrimSpace(v)
switch {
case k == "id":
c.Id = v
case k == "channel":
channels[v] = true
}
}
c.channels = channels
return c, nil
Meta *ConnectionRecordingMeta
}
// NewConnection creates a Connection container for a given connection id.
func (s *Session) NewConnection(ctx context.Context, meta *ConnectionMeta) (*Connection, error) {
func (s *Session) NewConnection(ctx context.Context, meta *ConnectionRecordingMeta) (*Connection, error) {
const op = "bsr.(Session).NewConnection"
switch {
@@ -770,7 +303,7 @@ func (s *Session) OpenConnection(ctx context.Context, connId string) (*Connectio
if err != nil {
return nil, fmt.Errorf("%s: %w", op, err)
}
sm, err := decodeConnectionMeta(ctx, sha256Reader)
sm, err := decodeConnectionRecordingMeta(ctx, sha256Reader)
if err != nil {
return nil, err
}
@@ -787,58 +320,8 @@ func (s *Session) OpenConnection(ctx context.Context, connId string) (*Connectio
return connection, nil
}
// ChannelMeta contains metadata about a channel in a BSR.
type ChannelMeta struct {
Id string
Type string
}
func (c ChannelMeta) isValid() bool {
switch {
case c.Id == "":
return false
case c.Type == "":
return false
default:
return true
}
}
// decodeChannelMeta will populate the ChannelMeta for a BSR Channel
// TODO Unmarshal without brute force
func decodeChannelMeta(ctx context.Context, r io.Reader) (*ChannelMeta, error) {
const op = "bsr.decodeChannelMeta"
switch {
case r == nil:
return nil, fmt.Errorf("%s: missing channel meta file: %w", op, ErrInvalidParameter)
}
c := &ChannelMeta{}
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
if len(l) == 0 {
continue
}
k, v, ok := strings.Cut(l, ":")
if !ok {
return nil, fmt.Errorf("%s: channel meta file contains invalid entry; expecting k: v pair:%s", op, l)
}
v = strings.TrimSpace(v)
switch {
case k == "id":
c.Id = v
case k == "channelType":
c.Type = v
}
}
return c, nil
}
// NewChannel creates a Channel container for a given channel id.
func (c *Connection) NewChannel(ctx context.Context, meta *ChannelMeta) (*Channel, error) {
func (c *Connection) NewChannel(ctx context.Context, meta *ChannelRecordingMeta) (*Channel, error) {
const op = "bsr.(Connection).NewChannel"
if !c.multiplexed {
@@ -908,7 +391,7 @@ func (c *Connection) OpenChannel(ctx context.Context, chanId string) (*Channel,
if err != nil {
return nil, fmt.Errorf("%s: %w", op, err)
}
sm, err := decodeChannelMeta(ctx, sha256Reader)
sm, err := decodeChannelRecordingMeta(ctx, sha256Reader)
if err != nil {
return nil, err
}
@@ -979,7 +462,7 @@ func (c *Connection) Close(ctx context.Context) error {
type Channel struct {
*container
Meta *ChannelMeta
Meta *ChannelRecordingMeta
}
// Close closes the Channel container.
+47 -27
View File
@@ -10,7 +10,9 @@ import (
"github.com/hashicorp/boundary/internal/bsr/internal/fstest"
"github.com/hashicorp/boundary/internal/bsr/kms"
"github.com/hashicorp/boundary/internal/storage"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/square/go-jose.v2/json"
)
func TestPopulateMeta(t *testing.T) {
@@ -19,34 +21,42 @@ func TestPopulateMeta(t *testing.T) {
keys, err := kms.CreateKeys(ctx, kms.TestWrapper(t), "session")
require.NoError(t, err)
sessionId := "session"
sessionProtocol := Protocol("TEST")
sessionId := "s_01234567890"
srm := &SessionRecordingMeta{
Id: "sr_012344567890",
Protocol: Protocol("TEST"),
}
// Populate session meta
sessionMeta := TestSessionMeta(sessionId, sessionProtocol)
s, err := NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, WithSupportsMultiplex(true))
sessionMeta := TestSessionMeta(sessionId)
s, err := NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, WithSupportsMultiplex(true))
require.NoError(t, err)
require.NotNil(t, s)
// Reset meta and populate it from the meta file
s.Meta = &SessionMeta{}
sm, err := decodeSessionMeta(ctx, s.container.meta)
s.Meta = &SessionRecordingMeta{}
sm, err := decodeSessionRecordingMeta(ctx, s.container.meta)
require.NoError(t, err)
s.Meta = sm
require.Equal(t, s.Meta.Id, sessionId)
require.Equal(t, s.Meta.Protocol, sessionProtocol)
require.Equal(t, s.Meta.Target, sessionMeta.Target)
require.Equal(t, s.Meta.User, sessionMeta.User)
require.Equal(t, s.Meta.StaticHost, sessionMeta.StaticHost)
require.Equal(t, s.Meta.Id, srm.Id)
require.Equal(t, s.Meta.Protocol, srm.Protocol)
gotSessionMeta := &SessionMeta{}
r, err := s.container.container.OpenFile(ctx, sessionMetaFile)
require.NoError(t, err)
dec := json.NewDecoder(r)
err = dec.Decode(gotSessionMeta)
require.NoError(t, err)
assert.Equal(t, sessionMeta, gotSessionMeta)
// Populate connection meta
connectionId := "connection"
c, err := s.NewConnection(ctx, &ConnectionMeta{Id: connectionId})
c, err := s.NewConnection(ctx, &ConnectionRecordingMeta{Id: connectionId})
require.NoError(t, err)
require.NotNil(t, c)
c.Meta = &ConnectionMeta{}
cm, err := decodeConnectionMeta(ctx, c.container.meta)
c.Meta = &ConnectionRecordingMeta{}
cm, err := decodeConnectionRecordingMeta(ctx, c.container.meta)
require.NoError(t, err)
c.Meta = cm
require.Equal(t, c.Meta.Id, connectionId)
@@ -54,12 +64,12 @@ func TestPopulateMeta(t *testing.T) {
// Populate channel meta
channelId := "channel"
channelType := "mythical"
ch, err := c.NewChannel(ctx, &ChannelMeta{Id: channelId, Type: channelType})
ch, err := c.NewChannel(ctx, &ChannelRecordingMeta{Id: channelId, Type: channelType})
require.NoError(t, err)
require.NotNil(t, ch)
ch.Meta = &ChannelMeta{}
chM, err := decodeChannelMeta(ctx, ch.container.meta)
ch.Meta = &ChannelRecordingMeta{}
chM, err := decodeChannelRecordingMeta(ctx, ch.container.meta)
require.NoError(t, err)
ch.Meta = chM
require.Equal(t, ch.Meta.Id, channelId)
@@ -73,21 +83,25 @@ func TestOpenBSRMethods(t *testing.T) {
require.NoError(t, err)
f := &fstest.MemFS{}
sessionId := "session"
sessionMeta := TestSessionMeta(sessionId, Protocol("test"))
sessionId := "s_01234567890"
srm := &SessionRecordingMeta{
Id: "sr_012344567890",
Protocol: Protocol("TEST"),
}
sessionMeta := TestSessionMeta(sessionId)
sesh, err := NewSession(ctx, sessionMeta, f, keys, WithSupportsMultiplex(true))
sesh, err := NewSession(ctx, srm, sessionMeta, f, keys, WithSupportsMultiplex(true))
require.NoError(t, err)
require.NotNil(t, sesh)
connectionId := "connection"
connMeta := &ConnectionMeta{Id: connectionId}
connMeta := &ConnectionRecordingMeta{Id: connectionId}
conn, err := sesh.NewConnection(ctx, connMeta)
require.NoError(t, err)
require.NotNil(t, conn)
channelId := "channel"
chanMeta := &ChannelMeta{
chanMeta := &ChannelRecordingMeta{
Id: channelId,
Type: "chan",
}
@@ -107,7 +121,7 @@ func TestOpenBSRMethods(t *testing.T) {
return u, nil
}
opSesh, err := OpenSession(ctx, sessionId, f, keyFn)
opSesh, err := OpenSession(ctx, srm.Id, f, keyFn)
require.NoError(t, err)
require.NotNil(t, opSesh)
sesh.Meta.connections = opSesh.Meta.connections
@@ -191,8 +205,13 @@ func TestOpenConnection(t *testing.T) {
connMap := make(map[string]bool)
connMap["connection"] = true
meta := TestSessionMeta("sessionId", Protocol("test"))
meta.connections = connMap
sessionId := "s_01234567890"
srm := &SessionRecordingMeta{
Id: "sr_012344567890",
Protocol: Protocol("TEST"),
connections: connMap,
}
meta := TestSessionMeta(sessionId)
cases := []struct {
name string
@@ -216,7 +235,8 @@ func TestOpenConnection(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
sesh := Session{
Meta: meta,
Meta: srm,
SessionMeta: meta,
}
got, err := sesh.OpenConnection(ctx, tc.id)
if tc.wantErr {
@@ -258,7 +278,7 @@ func TestOpenChannel(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
conn := Connection{
Meta: &ConnectionMeta{
Meta: &ConnectionRecordingMeta{
channels: chanMap,
},
}
+85 -50
View File
@@ -5,6 +5,7 @@ package bsr_test
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
@@ -32,18 +33,18 @@ func assertContainer(ctx context.Context, t *testing.T, path, state string, typ
td := filepath.Join("testdata", t.Name(), state, path)
// meta
wantMeta, err := os.ReadFile(filepath.Join(td, string(typ)+".meta"))
wantMeta, err := os.ReadFile(filepath.Join(td, string(typ)+"-recording.meta"))
require.NoError(t, err, "unable to find test data file")
meta, ok := fs.Files[string(typ)+".meta"]
meta, ok := fs.Files[string(typ)+"-recording.meta"]
require.True(t, ok, "container is missing meta file")
wantChecksumsRegex, err := regexp.Compile(string(wantMeta))
require.NoError(t, err)
assert.True(t, wantChecksumsRegex.MatchString(meta.Buf.String()))
// summary
wantSummary, err := os.ReadFile(filepath.Join(td, string(typ)+".summary"))
wantSummary, err := os.ReadFile(filepath.Join(td, string(typ)+"-recording-summary.json"))
require.NoError(t, err, "unable to find test data file")
summary, ok := fs.Files[string(typ)+".summary"]
summary, ok := fs.Files[string(typ)+"-recording-summary.json"]
require.True(t, ok, "container is missing summary file")
assert.Equal(t, string(wantSummary), summary.Buf.String())
@@ -60,7 +61,7 @@ func assertContainer(ctx context.Context, t *testing.T, path, state string, typ
wChecksumsRegex = append(wChecksumsRegex, r)
}
for _, cr := range wChecksumsRegex {
assert.True(t, cr.MatchString(checksums.Buf.String()))
assert.True(t, cr.MatchString(checksums.Buf.String()), "got:\n%s\nmust match:\n%s", checksums.Buf.String(), cr.String())
}
// SHA256SUM.sig signature file
@@ -99,7 +100,7 @@ func assertContainer(ctx context.Context, t *testing.T, path, state string, typ
wJournalRegex = append(wJournalRegex, r)
}
for _, cr := range wJournalRegex {
assert.True(t, cr.MatchString(journal.Buf.String()))
assert.True(t, cr.MatchString(journal.Buf.String()), "got:\n%s\nmust match:\n%s", journal.Buf.String(), cr.String())
}
if typ == "session" {
@@ -123,6 +124,14 @@ func assertContainer(ctx context.Context, t *testing.T, path, state string, typ
pubKeySelfSignature, ok := fs.Files["pubKeySelfSignature.sign"]
require.True(t, ok, "container is missing pubKeySelfSignature.sign file")
assert.NotEmpty(t, pubKeySelfSignature.Buf.String())
sessionMeta, ok := fs.Files["session-meta.json"]
require.True(t, ok, "container is missing session-meta.json file")
assert.NotEmpty(t, sessionMeta.Buf.String())
sm := &bsr.SessionMeta{}
err = json.Unmarshal(sessionMeta.Buf.Bytes(), sm)
require.NoError(t, err)
assert.Equal(t, sm, bsr.TestSessionMeta(strings.ReplaceAll(fs.Name, ".bsr", "")))
}
}
@@ -233,8 +242,12 @@ func TestBsr(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
sessionMeta := bsr.TestSessionMeta(tc.id, "TEST")
s, err := bsr.NewSession(ctx, sessionMeta, tc.c, tc.keys, tc.opts...)
srm := &bsr.SessionRecordingMeta{
Id: tc.id,
Protocol: bsr.Protocol("TEST"),
}
sessionMeta := bsr.TestSessionMeta(tc.id)
s, err := bsr.NewSession(ctx, srm, sessionMeta, tc.c, tc.keys, tc.opts...)
require.NoError(t, err)
require.NotNil(t, s)
@@ -247,7 +260,7 @@ func TestBsr(t *testing.T) {
// create all the things
for _, conn := range tc.conns {
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: conn.id})
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: conn.id})
require.NoError(t, err)
require.NotNil(t, c)
@@ -281,7 +294,7 @@ func TestBsr(t *testing.T) {
createdChannels := make([]*channel, 0, len(conn.channels))
for _, chann := range conn.channels {
ch, err := c.NewChannel(ctx, &bsr.ChannelMeta{Id: chann.id, Type: "chan"})
ch, err := c.NewChannel(ctx, &bsr.ChannelRecordingMeta{Id: chann.id, Type: "chan"})
require.NoError(t, err)
require.NotNil(t, ch)
@@ -370,43 +383,57 @@ func TestNewSessionErrors(t *testing.T) {
require.NoError(t, err)
cases := []struct {
name string
meta *bsr.SessionMeta
f storage.FS
keys *kms.Keys
wantError error
name string
meta *bsr.SessionRecordingMeta
sessionMeta *bsr.SessionMeta
f storage.FS
keys *kms.Keys
wantError error
}{
{
"nil-meta",
nil,
bsr.TestSessionMeta("session"),
&fstest.MemFS{},
keys,
errors.New("bsr.NewSession: missing meta: invalid parameter"),
},
{
"nil-session-meta",
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
nil,
&fstest.MemFS{},
keys,
errors.New("bsr.NewSession: missing session meta: invalid parameter"),
},
{
"empty-session-id",
bsr.TestSessionMeta("", "TEST"),
bsr.TestSessionRecordingMeta("", bsr.Protocol("TEST")),
bsr.TestSessionMeta("session"),
&fstest.MemFS{},
keys,
errors.New("bsr.NewSession: missing session id: invalid parameter"),
},
{
"nil-fs",
bsr.TestSessionMeta("session", "TEST"),
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
bsr.TestSessionMeta("session"),
nil,
keys,
errors.New("bsr.NewSession: missing storage fs: invalid parameter"),
},
{
"nil-keys",
bsr.TestSessionMeta("session", "TEST"),
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
bsr.TestSessionMeta("session"),
&fstest.MemFS{},
nil,
errors.New("bsr.NewSession: missing kms keys: invalid parameter"),
},
{
"missing-bsr-signature",
bsr.TestSessionMeta("session", "TEST"),
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
bsr.TestSessionMeta("session"),
&fstest.MemFS{},
&kms.Keys{
PubKey: keys.PubKey,
@@ -418,7 +445,8 @@ func TestNewSessionErrors(t *testing.T) {
},
{
"missing-pub-signature",
bsr.TestSessionMeta("session", "TEST"),
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
bsr.TestSessionMeta("session"),
&fstest.MemFS{},
&kms.Keys{
PubKey: keys.PubKey,
@@ -430,7 +458,8 @@ func TestNewSessionErrors(t *testing.T) {
},
{
"missing-pub-key",
bsr.TestSessionMeta("session", "TEST"),
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
bsr.TestSessionMeta("session"),
&fstest.MemFS{},
&kms.Keys{
WrappedBsrKey: keys.WrappedBsrKey,
@@ -442,7 +471,8 @@ func TestNewSessionErrors(t *testing.T) {
},
{
"missing-wrapped-bsr-key",
bsr.TestSessionMeta("session", "TEST"),
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
bsr.TestSessionMeta("session"),
&fstest.MemFS{},
&kms.Keys{
PubKey: keys.PubKey,
@@ -454,7 +484,8 @@ func TestNewSessionErrors(t *testing.T) {
},
{
"missing-wrapped-priv-key",
bsr.TestSessionMeta("session", "TEST"),
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
bsr.TestSessionMeta("session"),
&fstest.MemFS{},
&kms.Keys{
PubKey: keys.PubKey,
@@ -466,7 +497,8 @@ func TestNewSessionErrors(t *testing.T) {
},
{
"fs-new-error",
bsr.TestSessionMeta("session", "TEST"),
bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")),
bsr.TestSessionMeta("session"),
fstest.NewMemFS(fstest.WithNewFunc(func(_ context.Context, _ string) (storage.Container, error) {
return nil, errors.New("fs new error")
})),
@@ -477,7 +509,7 @@ func TestNewSessionErrors(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
_, err := bsr.NewSession(ctx, tc.meta, tc.f, tc.keys)
_, err := bsr.NewSession(ctx, tc.meta, tc.sessionMeta, tc.f, tc.keys)
require.Error(t, err)
assert.EqualError(t, err, tc.wantError.Error())
})
@@ -493,13 +525,13 @@ func TestNewConnectionErrors(t *testing.T) {
cases := []struct {
name string
session *bsr.Session
meta *bsr.ConnectionMeta
meta *bsr.ConnectionRecordingMeta
wantError error
}{
{
"nil-meta",
func() *bsr.Session {
s, err := bsr.NewSession(ctx, bsr.TestSessionMeta("session", "TEST"), &fstest.MemFS{}, keys)
s, err := bsr.NewSession(ctx, bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")), bsr.TestSessionMeta("session"), &fstest.MemFS{}, keys)
require.NoError(t, err)
return s
}(),
@@ -509,11 +541,11 @@ func TestNewConnectionErrors(t *testing.T) {
{
"empty-connection-id",
func() *bsr.Session {
s, err := bsr.NewSession(ctx, bsr.TestSessionMeta("session", "TEST"), &fstest.MemFS{}, keys)
s, err := bsr.NewSession(ctx, bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST")), bsr.TestSessionMeta("session"), &fstest.MemFS{}, keys)
require.NoError(t, err)
return s
}(),
&bsr.ConnectionMeta{Id: ""},
&bsr.ConnectionRecordingMeta{Id: ""},
errors.New("bsr.(Session).NewConnection: missing connection id: invalid parameter"),
},
}
@@ -533,20 +565,21 @@ func TestNewChannelErrors(t *testing.T) {
keys, err := kms.CreateKeys(ctx, kms.TestWrapper(t), "session")
require.NoError(t, err)
sessionMeta := bsr.TestSessionMeta("session", "TEST")
srm := bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST"))
sessionMeta := bsr.TestSessionMeta("session")
cases := []struct {
name string
connection *bsr.Connection
meta *bsr.ChannelMeta
meta *bsr.ChannelRecordingMeta
wantError error
}{
{
"nil-meta",
func() *bsr.Connection {
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
require.NoError(t, err)
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
require.NoError(t, err)
return c
}(),
@@ -556,40 +589,40 @@ func TestNewChannelErrors(t *testing.T) {
{
"empty-connection-id",
func() *bsr.Connection {
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
require.NoError(t, err)
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
require.NoError(t, err)
return c
}(),
&bsr.ChannelMeta{Id: ""},
&bsr.ChannelRecordingMeta{Id: ""},
errors.New("bsr.(Connection).NewChannel: missing channel id: invalid parameter"),
},
{
"not-multiplexed",
func() *bsr.Connection {
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(false))
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(false))
require.NoError(t, err)
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
require.NoError(t, err)
return c
}(),
&bsr.ChannelMeta{Id: ""},
&bsr.ChannelRecordingMeta{Id: ""},
errors.New("bsr.(Connection).NewChannel: connection cannot make channels: not supported by protocol"),
},
{
"not-multiplexed-default",
func() *bsr.Connection {
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys)
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys)
require.NoError(t, err)
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
require.NoError(t, err)
return c
}(),
&bsr.ChannelMeta{Id: ""},
&bsr.ChannelRecordingMeta{Id: ""},
errors.New("bsr.(Connection).NewChannel: connection cannot make channels: not supported by protocol"),
},
}
@@ -609,7 +642,8 @@ func TestChannelNewMessagesWriterErrors(t *testing.T) {
keys, err := kms.CreateKeys(ctx, kms.TestWrapper(t), "session")
require.NoError(t, err)
sessionMeta := bsr.TestSessionMeta("session", "TEST")
srm := bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST"))
sessionMeta := bsr.TestSessionMeta("session")
cases := []struct {
name string
channel *bsr.Channel
@@ -619,13 +653,13 @@ func TestChannelNewMessagesWriterErrors(t *testing.T) {
{
"invalid-dir",
func() *bsr.Channel {
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
require.NoError(t, err)
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
require.NoError(t, err)
ch, err := c.NewChannel(ctx, &bsr.ChannelMeta{Id: "channel"})
ch, err := c.NewChannel(ctx, &bsr.ChannelRecordingMeta{Id: "channel"})
require.NoError(t, err)
return ch
}(),
@@ -649,7 +683,8 @@ func TestChannelNewRequestsWriterErrors(t *testing.T) {
keys, err := kms.CreateKeys(ctx, kms.TestWrapper(t), "session")
require.NoError(t, err)
sessionMeta := bsr.TestSessionMeta("session", "TEST")
srm := bsr.TestSessionRecordingMeta("session_recording", bsr.Protocol("TEST"))
sessionMeta := bsr.TestSessionMeta("session")
cases := []struct {
name string
channel *bsr.Channel
@@ -659,13 +694,13 @@ func TestChannelNewRequestsWriterErrors(t *testing.T) {
{
"invalid-dir",
func() *bsr.Channel {
s, err := bsr.NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
s, err := bsr.NewSession(ctx, srm, sessionMeta, &fstest.MemFS{}, keys, bsr.WithSupportsMultiplex(true))
require.NoError(t, err)
c, err := s.NewConnection(ctx, &bsr.ConnectionMeta{Id: "connection"})
c, err := s.NewConnection(ctx, &bsr.ConnectionRecordingMeta{Id: "connection"})
require.NoError(t, err)
ch, err := c.NewChannel(ctx, &bsr.ChannelMeta{Id: "channel"})
ch, err := c.NewChannel(ctx, &bsr.ChannelRecordingMeta{Id: "channel"})
require.NoError(t, err)
return ch
}(),
+62 -21
View File
@@ -6,6 +6,7 @@ package bsr
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
@@ -22,8 +23,8 @@ import (
)
const (
metaFile = "%s.meta"
summaryFile = "%s.summary"
metaFile = "%s-recording.meta"
summaryFile = "%s-recording-summary.json"
checksumFile = "SHA256SUM"
sigFile = "SHA256SUM.sig"
journalFile = ".journal"
@@ -45,12 +46,13 @@ type container struct {
container storage.Container
// Fields primarily used for writing
journal *journal.Journal
sumName string
meta *checksum.File
sum *checksum.File
checksums *sign.File
sigs storage.File
journal *journal.Journal
sumName string
meta *checksum.File
sum *checksum.File
sumEncoder *json.Encoder
checksums *sign.File
sigs storage.File
// Field used for reading
shaSums checksum.Sha256Sums
@@ -113,6 +115,8 @@ func newContainer(ctx context.Context, t containerType, c storage.Container, key
if err != nil {
return nil, err
}
cc.sumEncoder = json.NewEncoder(cc.sum)
cc.sumEncoder.SetIndent("", " ")
return cc, nil
}
@@ -369,6 +373,53 @@ func (c *container) create(ctx context.Context, s string, options ...storage.Opt
return jf, nil
}
func (c *container) decodeJsonFile(ctx context.Context, s string, v any) error {
const op = "bsr.(container).decodeJsonFile"
return c.decodeFile(ctx, s, func(_ context.Context, r io.Reader) error {
dec := json.NewDecoder(r)
if err := dec.Decode(v); err != nil {
return fmt.Errorf("%s: %w", op, err)
}
return nil
})
}
func (c *container) decodeFile(ctx context.Context, s string, fn func(context.Context, io.Reader) error) error {
const op = "bsr.(container).decodeFile"
expectedSum, err := c.shaSums.Sum(s)
if err != nil {
return fmt.Errorf("%s: %w", op, err)
}
f, err := c.container.OpenFile(ctx, s)
if err != nil {
return fmt.Errorf("%s: %w", op, err)
}
sha256Reader, err := crypto.NewSha256SumReader(ctx, f)
if err != nil {
f.Close()
return fmt.Errorf("%s: %w", op, err)
}
defer sha256Reader.Close()
if err := fn(ctx, sha256Reader); err != nil {
return fmt.Errorf("%s: %w", op, err)
}
gotSum, err := sha256Reader.Sum(ctx, crypto.WithHexEncoding(true))
if err != nil {
return fmt.Errorf("%s: %w", op, err)
}
if !bytes.Equal(expectedSum, gotSum) {
return fmt.Errorf("%s: checksum did not match expected value", op)
}
return nil
}
// syncBsrKey will take the marshalled bytes of a key, write its contents to a local file,
// and then close it. The key file is created using the synchronous storage option, so
// close will block until the file is synced to remote storage
@@ -421,19 +472,9 @@ func (c *container) WriteMeta(_ context.Context, k, v string) (int, error) {
return c.meta.WriteString(fmt.Sprintf("%s: %s\n", k, v))
}
// writeSummaryString writes a string to the container's summary file.
func (c *container) writeSummaryString(_ context.Context, s string) (int, error) {
return c.sum.WriteString(s)
}
// WriteSummary writes a new line terminated key : value pair to the container's summary file
func (c *container) WriteSummary(_ context.Context, k, v string) (int, error) {
return c.sum.WriteString(fmt.Sprintf("%s: %s\n", k, v))
}
// WriteSummaryLine writes a new line terminated string to the container's summary file.
func (c *container) WriteSummaryLine(_ context.Context, s string) (int, error) {
return c.sum.WriteString(s + "\n")
// EncodeSummary writes a new line terminated key : value pair to the container's summary file
func (c *container) EncodeSummary(_ context.Context, s any) error {
return c.sumEncoder.Encode(s)
}
// WriteBinaryChecksum writes a checksum for a binary file to the checksum file.
-787
View File
@@ -1,787 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package bsr
import (
"context"
"fmt"
"strconv"
)
// Scope contains information about the scope of a Boundary domain object
type Scope struct {
PublicId string
Name string // optional
Description string // optional
Type string
ParentId string // optional
PrimaryAuthMethodId string // optional
}
func (s Scope) writeMeta(ctx context.Context, c *container, domainObj string) error {
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_scope_publicId", domainObj), s.PublicId)
if err != nil {
return err
}
if s.Name != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_name", domainObj), s.Name)
if err != nil {
return err
}
}
if s.Description != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_description", domainObj), s.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_type", domainObj), s.Type)
if err != nil {
return err
}
if s.ParentId != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_parentId", domainObj), s.ParentId)
if err != nil {
return err
}
}
if s.PrimaryAuthMethodId != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_scope_primaryAuthMethodId", domainObj), s.PrimaryAuthMethodId)
if err != nil {
return err
}
}
return nil
}
// User contains information about user who initiated this session
type User struct {
PublicId string
Scope Scope
Name string // optional field
Description string // optional field
}
func (u User) writeMeta(ctx context.Context, c *container) error {
_, err := c.WriteMeta(ctx, "user_publicId", u.PublicId)
if err != nil {
return err
}
err = u.Scope.writeMeta(ctx, c, "user")
if err != nil {
return err
}
if u.Name != "" {
_, err = c.WriteMeta(ctx, "user_name", u.Name)
if err != nil {
return err
}
}
if u.Description != "" {
_, err = c.WriteMeta(ctx, "user_description", u.Description)
if err != nil {
return err
}
}
return nil
}
// Target contains information about the target for this session
type Target struct {
PublicId string
Scope Scope
Name string // optional field
Description string // optional field
DefaultPort uint32
SessionMaxSeconds uint32
SessionConnectionLimit int32
WorkerFilter string // optional field
EgressWorkerFilter string // optional field
IngressWorkerFilter string // optional field
}
func (t Target) writeMeta(ctx context.Context, c *container) error {
_, err := c.WriteMeta(ctx, "target_publicId", t.PublicId)
if err != nil {
return err
}
err = t.Scope.writeMeta(ctx, c, "target")
if err != nil {
return err
}
if t.Name != "" {
_, err = c.WriteMeta(ctx, "target_name", t.Name)
if err != nil {
return err
}
}
if t.Description != "" {
_, err = c.WriteMeta(ctx, "target_description", t.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, "target_defaultPort", fmt.Sprintf("%d", t.DefaultPort))
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, "target_sessionMaxSeconds", fmt.Sprintf("%d", t.SessionMaxSeconds))
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, "target_sessionConnectionLimit", fmt.Sprintf("%d", t.SessionConnectionLimit))
if err != nil {
return err
}
if t.WorkerFilter != "" {
_, err = c.WriteMeta(ctx, "target_workerFilter", t.WorkerFilter)
if err != nil {
return err
}
}
if t.IngressWorkerFilter != "" {
_, err = c.WriteMeta(ctx, "target_ingressWorkerFilter", t.IngressWorkerFilter)
if err != nil {
return err
}
}
if t.EgressWorkerFilter != "" {
_, err = c.WriteMeta(ctx, "target_egressWorkerFilter", t.EgressWorkerFilter)
if err != nil {
return err
}
}
return nil
}
// Worker contains information about the worker used to record this session
type Worker struct {
PublicId string
Version string
Sha string
}
func (w Worker) writeMeta(ctx context.Context, c *container) error {
_, err := c.WriteMeta(ctx, "worker_publicId", w.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, "worker_version", w.Version)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, "worker_sha", w.Sha)
if err != nil {
return err
}
return nil
}
// StaticHostCatalog contains information about the static host catalog for this session
type StaticHostCatalog struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
}
func (h StaticHostCatalog) writeMeta(ctx context.Context, c *container) error {
_, err := c.WriteMeta(ctx, "staticHostCatalog_publicId", h.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, "staticHostCatalog_projectId", h.ProjectId)
if err != nil {
return err
}
if h.Name != "" {
_, err = c.WriteMeta(ctx, "staticHostCatalog_name", h.Name)
if err != nil {
return err
}
}
if h.Description != "" {
_, err = c.WriteMeta(ctx, "staticHostCatalog_description", h.Description)
if err != nil {
return err
}
}
return nil
}
// StaticHost contains information about the static host for this session
type StaticHost struct {
PublicId string
Catalog StaticHostCatalog
Name string // optional field
Description string // optional field
Address string
}
func (h StaticHost) writeMeta(ctx context.Context, c *container) error {
_, err := c.WriteMeta(ctx, "staticHost_publicId", h.PublicId)
if err != nil {
return err
}
err = h.Catalog.writeMeta(ctx, c)
if err != nil {
return err
}
if h.Name != "" {
_, err = c.WriteMeta(ctx, "staticHost_name", h.Name)
if err != nil {
return err
}
}
if h.Description != "" {
_, err = c.WriteMeta(ctx, "staticHost_description", h.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, "staticHost_address", h.Address)
if err != nil {
return err
}
return nil
}
// DynamicHostCatalog contains information about the dynamic host catalog for this session
type DynamicHostCatalog struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
PluginId string
Attributes string
}
func (h DynamicHostCatalog) writeMeta(ctx context.Context, c *container) error {
_, err := c.WriteMeta(ctx, "dynamicHostCatalog_publicId", h.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_projectId", h.ProjectId)
if err != nil {
return err
}
if h.Name != "" {
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_name", h.Name)
if err != nil {
return err
}
}
if h.Description != "" {
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_description", h.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_pluginId", h.PluginId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, "dynamicHostCatalog_attributes", h.Attributes)
if err != nil {
return err
}
return nil
}
// DynamicHost contains information about the dynamic host for this session
type DynamicHost struct {
PublicId string
Catalog DynamicHostCatalog
Name string // optional field
Description string // optional field
ExternalId string
}
func (h DynamicHost) writeMeta(ctx context.Context, c *container) error {
_, err := c.WriteMeta(ctx, "dynamicHost_publicId", h.PublicId)
if err != nil {
return err
}
err = h.Catalog.writeMeta(ctx, c)
if err != nil {
return err
}
if h.Name != "" {
_, err = c.WriteMeta(ctx, "dynamicHost_name", h.Name)
if err != nil {
return err
}
}
if h.Description != "" {
_, err = c.WriteMeta(ctx, "dynamicHost_description", h.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, "dynamicHost_externalId", h.ExternalId)
if err != nil {
return err
}
return nil
}
// StaticCredentialStore represents a static credential store used for this session
type StaticCredentialStore struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
Credentials []StaticCredential
}
func (s StaticCredentialStore) writeMeta(ctx context.Context, c *container) error {
prefix := fmt.Sprintf("%s_staticCredentialStore", s.PublicId)
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), s.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), s.ProjectId)
if err != nil {
return err
}
if s.Name != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), s.Name)
if err != nil {
return err
}
}
if s.Description != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), s.Description)
if err != nil {
return err
}
}
if len(s.Credentials) > 0 {
credentialPrefix := fmt.Sprintf("%s_credential", prefix)
for _, sc := range s.Credentials {
err = sc.writeStaticCredentialMeta(ctx, c, credentialPrefix)
if err != nil {
return err
}
}
}
return nil
}
// StaticCredential represents a static credential used for this session
type StaticCredential interface {
writeStaticCredentialMeta(ctx context.Context, c *container, prefix string) error
}
// StaticJsonCredential represents a static json credential used for this session
type StaticJsonCredential struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
ObjectHmac []byte
}
func (s StaticJsonCredential) writeStaticCredentialMeta(ctx context.Context, c *container, p string) error {
prefix := fmt.Sprintf("%s_%s_staticJsonCredential", p, s.PublicId)
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), s.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), s.ProjectId)
if err != nil {
return err
}
if s.Name != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), s.Name)
if err != nil {
return err
}
}
if s.Description != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), s.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_objectHmac", prefix), string(s.ObjectHmac))
if err != nil {
return err
}
return nil
}
// StaticUsernamePasswordCredential represents a Static username password credential used for this session
type StaticUsernamePasswordCredential struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
PasswordHmac []byte
}
func (s StaticUsernamePasswordCredential) writeStaticCredentialMeta(ctx context.Context, c *container, p string) error {
prefix := fmt.Sprintf("%s_%s_staticUsernamePasswordCredential", p, s.PublicId)
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), s.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), s.ProjectId)
if err != nil {
return err
}
if s.Name != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), s.Name)
if err != nil {
return err
}
}
if s.Description != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), s.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_passwordHmac", prefix), string(s.PasswordHmac))
if err != nil {
return err
}
return nil
}
// StaticSshPrivateKeyCredential represents a Static Ssh private key credential used for this session
type StaticSshPrivateKeyCredential struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
PrivateKeyHmac []byte
PrivateKeyPassphraseHmac []byte // optional field
}
func (s StaticSshPrivateKeyCredential) writeStaticCredentialMeta(ctx context.Context, c *container, p string) error {
prefix := fmt.Sprintf("%s_%s_staticSshPrivateKeyCredential", p, s.PublicId)
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), s.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), s.ProjectId)
if err != nil {
return err
}
if s.Name != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), s.Name)
if err != nil {
return err
}
}
if s.Description != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), s.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_privateKeyHmac", prefix), string(s.PrivateKeyHmac))
if err != nil {
return err
}
if len(s.PrivateKeyPassphraseHmac) > 0 {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_privateKeyPassphraseHmac", prefix), string(s.PrivateKeyPassphraseHmac))
if err != nil {
return err
}
}
return nil
}
// VaultCredentialStore represents a Vault credential store used for this session
type VaultCredentialStore struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
VaultAddress string
Namespace string
TlsServerName string
TlsSkipVerify bool
WorkerFilter string // optional field
CredentialLibraries []DynamicCredentialLibraries
}
func (v VaultCredentialStore) writeMeta(ctx context.Context, c *container) error {
prefix := fmt.Sprintf("%s_vaultCredentialStore", v.PublicId)
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), v.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), v.ProjectId)
if err != nil {
return err
}
if v.Name != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), v.Name)
if err != nil {
return err
}
}
if v.Description != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), v.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_vaultAddress", prefix), v.VaultAddress)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_namespace", prefix), v.Namespace)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_tlsServerName", prefix), v.TlsServerName)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_tlsSkipVerify", prefix), strconv.FormatBool(v.TlsSkipVerify))
if err != nil {
return err
}
if v.WorkerFilter != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_workerFilter", prefix), v.WorkerFilter)
if err != nil {
return err
}
}
if len(v.CredentialLibraries) > 0 {
credentialPrefix := fmt.Sprintf("%s_credential", prefix)
for _, cl := range v.CredentialLibraries {
err = cl.writeDynamicCredentialLibraryMeta(ctx, c, credentialPrefix)
if err != nil {
return err
}
}
}
return nil
}
// DynamicCredentialLibraries represents a dynamic credential library used for this session
type DynamicCredentialLibraries interface {
writeDynamicCredentialLibraryMeta(ctx context.Context, c *container, prefix string) error
}
// VaultLibrary contains information about the Vault library used for this session
type VaultLibrary struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
VaultPath string
HttpMethod string
HttpRequestBody []byte // optional field
CredentialType string
}
func (v VaultLibrary) writeDynamicCredentialLibraryMeta(ctx context.Context, c *container, p string) error {
prefix := fmt.Sprintf("%s_%s_vaultLibrary", p, v.PublicId)
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), v.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), v.ProjectId)
if err != nil {
return err
}
if v.Name != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), v.Name)
if err != nil {
return err
}
}
if v.Description != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), v.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_vaultPath", prefix), v.VaultPath)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_httpMethod", prefix), v.HttpMethod)
if err != nil {
return err
}
if len(v.HttpRequestBody) > 0 {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_httpRequestBody", prefix), string(v.HttpRequestBody))
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_credentialType", prefix), v.CredentialType)
if err != nil {
return err
}
return nil
}
// VaultSshCertLibrary contains information about a Vault Ssh Cert library for this session
type VaultSshCertLibrary struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
VaultPath string
Username string
KeyType string
KeyBits int
Ttl string // optional field
CriticalOptions []byte // optional field
Extensions []byte // optional field
CredentialType string // optional field
}
func (v VaultSshCertLibrary) writeDynamicCredentialLibraryMeta(ctx context.Context, c *container, p string) error {
prefix := fmt.Sprintf("%s_%s_vaultSshCertLibrary", p, v.PublicId)
_, err := c.WriteMeta(ctx, fmt.Sprintf("%s_publicId", prefix), v.PublicId)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_projectId", prefix), v.ProjectId)
if err != nil {
return err
}
if v.Name != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_name", prefix), v.Name)
if err != nil {
return err
}
}
if v.Description != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_description", prefix), v.Description)
if err != nil {
return err
}
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_vaultPath", prefix), v.VaultPath)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_username", prefix), v.Username)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_keyType", prefix), v.KeyType)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_keyBits", prefix), strconv.Itoa(v.KeyBits))
if err != nil {
return err
}
if v.Ttl != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_ttl", prefix), v.Ttl)
if err != nil {
return err
}
}
if len(v.CriticalOptions) > 0 {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_criticalOptions", prefix), string(v.CriticalOptions))
if err != nil {
return err
}
}
if len(v.Extensions) > 0 {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_extensions", prefix), string(v.Extensions))
if err != nil {
return err
}
}
if v.Name != "" {
_, err = c.WriteMeta(ctx, fmt.Sprintf("%s_credentialType", prefix), v.CredentialType)
if err != nil {
return err
}
}
return nil
}
// SessionMeta contains metadata about a session in a BSR.
// Most fields are written to the meta file as k:v pairs
// Slice fields are written to the meta file as id_k:v
// Nested slice fields are written as parentId_parentKey_id_k:v
type SessionMeta struct {
Id string
Protocol Protocol
User *User
Target *Target
Worker *Worker
// StaticHost and DynamicHost are mutually exclusive
StaticHost *StaticHost
DynamicHost *DynamicHost
StaticCredentialStore []StaticCredentialStore
VaultCredentialStore []VaultCredentialStore
connections map[string]bool
}
func (s SessionMeta) writeMeta(ctx context.Context, c *container) error {
_, err := c.WriteMeta(ctx, "id", s.Id)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, "protocol", string(s.Protocol))
if err != nil {
return err
}
err = s.User.writeMeta(ctx, c)
if err != nil {
return err
}
err = s.Target.writeMeta(ctx, c)
if err != nil {
return err
}
err = s.Worker.writeMeta(ctx, c)
if err != nil {
return err
}
if s.StaticHost != nil {
err = s.StaticHost.writeMeta(ctx, c)
if err != nil {
return err
}
}
if s.DynamicHost != nil {
err = s.DynamicHost.writeMeta(ctx, c)
if err != nil {
return err
}
}
if len(s.StaticCredentialStore) > 0 {
for _, sc := range s.StaticCredentialStore {
err = sc.writeMeta(ctx, c)
if err != nil {
return err
}
}
}
if len(s.VaultCredentialStore) > 0 {
for _, dc := range s.VaultCredentialStore {
err = dc.writeMeta(ctx, c)
if err != nil {
return err
}
}
}
return nil
}
+170
View File
@@ -0,0 +1,170 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package bsr
import (
"bufio"
"context"
"fmt"
"io"
"strings"
)
// SessionRecordingMeta contains metadata about a session in a BSR.
// Most fields are written to the meta file as k:v pairs
// Slice fields are written to the meta file as id_k:v
// Nested slice fields are written as parentId_parentKey_id_k:v
type SessionRecordingMeta struct {
Id string
Protocol Protocol
connections map[string]bool
}
func (s *SessionRecordingMeta) writeMeta(ctx context.Context, c *container) error {
_, err := c.WriteMeta(ctx, "id", s.Id)
if err != nil {
return err
}
_, err = c.WriteMeta(ctx, "protocol", string(s.Protocol))
if err != nil {
return err
}
return nil
}
// decodeSessionRecordingMeta will populate a SessionRecordingMeta for an opened BSR Session
func decodeSessionRecordingMeta(ctx context.Context, r io.Reader) (*SessionRecordingMeta, error) {
const op = "bsr.decodeSessionRecordingMeta"
switch {
case r == nil:
return nil, fmt.Errorf("%s: missing session meta file: %w", op, ErrInvalidParameter)
}
connections := make(map[string]bool)
s := &SessionRecordingMeta{}
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
if len(l) == 0 {
continue
}
k, v, ok := strings.Cut(l, ":")
if !ok {
return nil, fmt.Errorf("%s: session meta file contains invalid entry; expecting k: v pair:%s", op, l)
}
v = strings.TrimSpace(v)
switch {
case k == "id":
s.Id = v
case k == "protocol":
s.Protocol = Protocol(v)
// connections
case k == "connection":
connections[v] = true
}
}
s.connections = connections
return s, nil
}
// ConnectionRecordingMeta contains metadata about a connection in a BSR.
type ConnectionRecordingMeta struct {
Id string
channels map[string]bool
}
func (c ConnectionRecordingMeta) isValid() bool {
switch {
case c.Id == "":
return false
default:
return true
}
}
// decodeConnectionRecordingMeta will populate the ConnectionRecordingMeta for a BSR Connection
func decodeConnectionRecordingMeta(ctx context.Context, r io.Reader) (*ConnectionRecordingMeta, error) {
const op = "bsr.decodeConnectionRecordingMeta"
switch {
case r == nil:
return nil, fmt.Errorf("%s: missing connection meta file: %w", op, ErrInvalidParameter)
}
c := &ConnectionRecordingMeta{}
channels := make(map[string]bool)
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
if len(l) == 0 {
continue
}
k, v, ok := strings.Cut(l, ":")
if !ok {
return nil, fmt.Errorf("%s: connection meta file contains invalid entry; expecting k: v pair:%s", op, l)
}
v = strings.TrimSpace(v)
switch {
case k == "id":
c.Id = v
case k == "channel":
channels[v] = true
}
}
c.channels = channels
return c, nil
}
// ChannelRecordingMeta contains metadata about a channel in a BSR.
type ChannelRecordingMeta struct {
Id string
Type string
}
func (c ChannelRecordingMeta) isValid() bool {
switch {
case c.Id == "":
return false
case c.Type == "":
return false
default:
return true
}
}
// decodeChannelRecordingMeta will populate the ChannelRecordingMeta for a BSR Channel
func decodeChannelRecordingMeta(ctx context.Context, r io.Reader) (*ChannelRecordingMeta, error) {
const op = "bsr.decodeChannelRecordingMeta"
switch {
case r == nil:
return nil, fmt.Errorf("%s: missing channel meta file: %w", op, ErrInvalidParameter)
}
c := &ChannelRecordingMeta{}
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
if len(l) == 0 {
continue
}
k, v, ok := strings.Cut(l, ":")
if !ok {
return nil, fmt.Errorf("%s: channel meta file contains invalid entry; expecting k: v pair:%s", op, l)
}
v = strings.TrimSpace(v)
switch {
case k == "id":
c.Id = v
case k == "channelType":
c.Type = v
}
}
return c, nil
}
+174
View File
@@ -0,0 +1,174 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package bsr
// Scope contains information about the scope of a Boundary domain object
type Scope struct {
PublicId string
Name string // optional
Description string // optional
Type string
ParentId string // optional
PrimaryAuthMethodId string // optional
}
// User contains information about user who initiated this session
type User struct {
PublicId string
Scope Scope
Name string // optional field
Description string // optional field
}
// Target contains information about the target for this session
type Target struct {
PublicId string
Scope Scope
Name string // optional field
Description string // optional field
DefaultPort uint32
SessionMaxSeconds uint32
SessionConnectionLimit int32
WorkerFilter string // optional field
EgressWorkerFilter string // optional field
IngressWorkerFilter string // optional field
}
// Worker contains information about the worker used to record this session
type Worker struct {
PublicId string
Version string
Sha string
}
// StaticHostCatalog contains information about the static host catalog for this session
type StaticHostCatalog struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
}
// StaticHost contains information about the static host for this session
type StaticHost struct {
PublicId string
Catalog StaticHostCatalog
Name string // optional field
Description string // optional field
Address string
}
// DynamicHostCatalog contains information about the dynamic host catalog for this session
type DynamicHostCatalog struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
PluginId string
Attributes string
}
// DynamicHost contains information about the dynamic host for this session
type DynamicHost struct {
PublicId string
Catalog DynamicHostCatalog
Name string // optional field
Description string // optional field
ExternalId string
}
// StaticCredentialStore represents a static credential store used for this session
type StaticCredentialStore struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
StaticJsonCredentials []StaticJsonCredential
StaticUsernamePasswordCredentials []StaticUsernamePasswordCredential
}
// StaticJsonCredential represents a static json credential used for this session
type StaticJsonCredential struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
ObjectHmac []byte
}
// StaticUsernamePasswordCredential represents a Static username password credential used for this session
type StaticUsernamePasswordCredential struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
PasswordHmac []byte
}
// StaticSshPrivateKeyCredential represents a Static Ssh private key credential used for this session
type StaticSshPrivateKeyCredential struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
PrivateKeyHmac []byte
PrivateKeyPassphraseHmac []byte // optional field
}
// VaultCredentialStore represents a Vault credential store used for this session
type VaultCredentialStore struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
VaultAddress string
Namespace string
TlsServerName string
TlsSkipVerify bool
WorkerFilter string // optional field
VaultGenericLibraries []VaultLibrary
VaultSshCertLibraries []VaultSshCertLibrary
}
// VaultLibrary contains information about the Vault library used for this session
type VaultLibrary struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
VaultPath string
HttpMethod string
HttpRequestBody []byte // optional field
CredentialType string
}
// VaultSshCertLibrary contains information about a Vault Ssh Cert library for this session
type VaultSshCertLibrary struct {
PublicId string
ProjectId string
Name string // optional field
Description string // optional field
VaultPath string
Username string
KeyType string
KeyBits int
Ttl string // optional field
CriticalOptions []byte // optional field
Extensions []byte // optional field
CredentialType string // optional field
}
// SessionMeta contains metadata about a session in a BSR.
type SessionMeta struct {
PublicId string
User *User
Target *Target
Worker *Worker
// StaticHost and DynamicHost are mutually exclusive
StaticHost *StaticHost
DynamicHost *DynamicHost
StaticCredentialStore []StaticCredentialStore
VaultCredentialStore []VaultCredentialStore
}
@@ -2,10 +2,13 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING session.meta
CREATED session.meta
CREATING session.summary
CREATED session.summary
CREATING session-recording.meta
CREATED session-recording.meta
CREATING session-meta.json
CREATED session-meta.json
CLOSED session-meta.json
CREATING session-recording-summary.json
CREATED session-recording-summary.json
CREATING bsrKey.pub
CREATED bsrKey.pub
CLOSING bsrKey.pub
@@ -26,10 +29,10 @@ CREATING pubKeySelfSignature.sign
CREATED pubKeySelfSignature.sign
CLOSING pubKeySelfSignature.sign
CLOSED pubKeySelfSignature.sign
CLOSING session.meta
CLOSED session.meta
CLOSING session.summary
CLOSED session.summary
CLOSING session-recording.meta
CLOSED session-recording.meta
CLOSING session-recording-summary.json
CLOSED session-recording-summary.json
CLOSING SHA256SUM
CLOSED SHA256SUM
CLOSING SHA256SUM.sig
@@ -3,5 +3,6 @@
.* wrappedPrivKey
.* pubKeyBsrSignature.sign
.* pubKeySelfSignature.sign
1aac36a2c36e4de69c5bf3522ada1c7f080ac807f2182c013ec8ddf60bedae10 session.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 session.summary
.* session-meta.json
523569b06adc4a1996c7d3833105a48485428e663bf8a11ed9b4d8f84f68b85c session-recording.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 session-recording-summary.json
@@ -2,10 +2,10 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING connection.meta
CREATED connection.meta
CREATING connection.summary
CREATED connection.summary
CREATING connection-recording.meta
CREATED connection-recording.meta
CREATING connection-recording-summary.json
CREATED connection-recording-summary.json
CREATING requests-inbound.data
CREATED requests-inbound.data
CREATING requests-outbound.data
@@ -14,10 +14,10 @@ CLOSING requests-inbound.data
CLOSED requests-inbound.data
CLOSING requests-outbound.data
CLOSED requests-outbound.data
CLOSING connection.meta
CLOSED connection.meta
CLOSING connection.summary
CLOSED connection.summary
CLOSING connection-recording.meta
CLOSED connection-recording.meta
CLOSING connection-recording-summary.json
CLOSED connection-recording-summary.json
CLOSING SHA256SUM
CLOSED SHA256SUM
CLOSING SHA256SUM.sig
@@ -1,4 +1,4 @@
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-inbound.data
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-outbound.data
e4df3504aaa6fee4426f67ba998cdd90f84c579d98db979e589d8ca2ffd1e733 connection.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 connection.summary
e4df3504aaa6fee4426f67ba998cdd90f84c579d98db979e589d8ca2ffd1e733 connection-recording.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 connection-recording-summary.json
@@ -2,10 +2,10 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING channel.meta
CREATED channel.meta
CREATING channel.summary
CREATED channel.summary
CREATING channel-recording.meta
CREATED channel-recording.meta
CREATING channel-recording-summary.json
CREATED channel-recording-summary.json
CREATING messages-inbound.data
CREATED messages-inbound.data
CREATING requests-inbound.data
@@ -22,10 +22,10 @@ CLOSING messages-outbound.data
CLOSED messages-outbound.data
CLOSING requests-outbound.data
CLOSED requests-outbound.data
CLOSING channel.meta
CLOSED channel.meta
CLOSING channel.summary
CLOSED channel.summary
CLOSING channel-recording.meta
CLOSED channel-recording.meta
CLOSING channel-recording-summary.json
CLOSED channel-recording-summary.json
CLOSING SHA256SUM
CLOSED SHA256SUM
CLOSING SHA256SUM.sig
@@ -2,5 +2,5 @@ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-inbou
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-inbound.data
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-outbound.data
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-outbound.data
27a58452605f6e30ca048cc540e9d963c7270212fcb2c7b73fc69e314ffd1902 channel.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 channel.summary
27a58452605f6e30ca048cc540e9d963c7270212fcb2c7b73fc69e314ffd1902 channel-recording.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 channel-recording-summary.json
@@ -0,0 +1,3 @@
id: session_123456789
protocol: TEST
connection: conn_1.connection
@@ -1,36 +0,0 @@
id: session_123456789
protocol: TEST
user_publicId: user123
user_scope_publicId: global
user_scope_type: global
target_publicId: target123
target_scope_publicId: proj123
target_scope_type: project
target_scope_parentId: org123
target_defaultPort: 0
target_sessionMaxSeconds: 0
target_sessionConnectionLimit: 0
worker_publicId: w_12345
worker_version: 0.25.5
worker_sha: beepboopgitsha
staticHost_publicId: host123
staticHostCatalog_publicId: staticcat123
staticHostCatalog_projectId: proj123
staticHost_address: 127.0.0.1
scs123_staticCredentialStore_publicId: scs123
scs123_staticCredentialStore_projectId: proj123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_publicId: scjson123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_projectId: proj123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_objectHmac: hmac
vcs123_vaultCredentialStore_publicId: vcs123
vcs123_vaultCredentialStore_projectId: proj123
vcs123_vaultCredentialStore_vaultAddress: an/address
vcs123_vaultCredentialStore_namespace: name
vcs123_vaultCredentialStore_tlsServerName: imaserver
vcs123_vaultCredentialStore_tlsSkipVerify: false
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_publicId: vl123
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_projectId: proj123
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_vaultPath: /a/path
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_httpMethod: GET
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_credentialType: magic
connection: conn_1.connection
@@ -2,10 +2,13 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING session.meta
CREATED session.meta
CREATING session.summary
CREATED session.summary
CREATING session-recording.meta
CREATED session-recording.meta
CREATING session-meta.json
CREATED session-meta.json
CLOSED session-meta.json
CREATING session-recording-summary.json
CREATED session-recording-summary.json
CREATING bsrKey.pub
CREATED bsrKey.pub
CLOSING bsrKey.pub
@@ -3,3 +3,4 @@
.* wrappedPrivKey
.* pubKeyBsrSignature.sign
.* pubKeySelfSignature.sign
.* session-meta.json
@@ -2,7 +2,7 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING connection.meta
CREATED connection.meta
CREATING connection.summary
CREATED connection.summary
CREATING connection-recording.meta
CREATED connection-recording.meta
CREATING connection-recording-summary.json
CREATED connection-recording-summary.json
@@ -2,7 +2,7 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING channel.meta
CREATED channel.meta
CREATING channel.summary
CREATED channel.summary
CREATING channel-recording.meta
CREATED channel-recording.meta
CREATING channel-recording-summary.json
CREATED channel-recording-summary.json
@@ -0,0 +1,2 @@
id: session_123456789
protocol: TEST
@@ -1,35 +0,0 @@
id: session_123456789
protocol: TEST
user_publicId: user123
user_scope_publicId: global
user_scope_type: global
target_publicId: target123
target_scope_publicId: proj123
target_scope_type: project
target_scope_parentId: org123
target_defaultPort: 0
target_sessionMaxSeconds: 0
target_sessionConnectionLimit: 0
worker_publicId: w_12345
worker_version: 0.25.5
worker_sha: beepboopgitsha
staticHost_publicId: host123
staticHostCatalog_publicId: staticcat123
staticHostCatalog_projectId: proj123
staticHost_address: 127.0.0.1
scs123_staticCredentialStore_publicId: scs123
scs123_staticCredentialStore_projectId: proj123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_publicId: scjson123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_projectId: proj123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_objectHmac: hmac
vcs123_vaultCredentialStore_publicId: vcs123
vcs123_vaultCredentialStore_projectId: proj123
vcs123_vaultCredentialStore_vaultAddress: an/address
vcs123_vaultCredentialStore_namespace: name
vcs123_vaultCredentialStore_tlsServerName: imaserver
vcs123_vaultCredentialStore_tlsSkipVerify: false
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_publicId: vl123
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_projectId: proj123
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_vaultPath: /a/path
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_httpMethod: GET
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_credentialType: magic
@@ -2,10 +2,13 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING session.meta
CREATED session.meta
CREATING session.summary
CREATED session.summary
CREATING session-recording.meta
CREATED session-recording.meta
CREATING session-meta.json
CREATED session-meta.json
CLOSED session-meta.json
CREATING session-recording-summary.json
CREATED session-recording-summary.json
CREATING bsrKey.pub
CREATED bsrKey.pub
CLOSING bsrKey.pub
@@ -26,10 +29,10 @@ CREATING pubKeySelfSignature.sign
CREATED pubKeySelfSignature.sign
CLOSING pubKeySelfSignature.sign
CLOSED pubKeySelfSignature.sign
CLOSING session.meta
CLOSED session.meta
CLOSING session.summary
CLOSED session.summary
CLOSING session-recording.meta
CLOSED session-recording.meta
CLOSING session-recording-summary.json
CLOSED session-recording-summary.json
CLOSING SHA256SUM
CLOSED SHA256SUM
CLOSING SHA256SUM.sig
@@ -3,5 +3,6 @@
.* wrappedPrivKey
.* pubKeyBsrSignature.sign
.* pubKeySelfSignature.sign
1aac36a2c36e4de69c5bf3522ada1c7f080ac807f2182c013ec8ddf60bedae10 session.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 session.summary
.* session-meta.json
523569b06adc4a1996c7d3833105a48485428e663bf8a11ed9b4d8f84f68b85c session-recording.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 session-recording-summary.json
@@ -2,10 +2,10 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING connection.meta
CREATED connection.meta
CREATING connection.summary
CREATED connection.summary
CREATING connection-recording.meta
CREATED connection-recording.meta
CREATING connection-recording-summary.json
CREATED connection-recording-summary.json
CREATING messages-inbound.data
CREATED messages-inbound.data
CREATING messages-outbound.data
@@ -22,10 +22,10 @@ CLOSING requests-inbound.data
CLOSED requests-inbound.data
CLOSING requests-outbound.data
CLOSED requests-outbound.data
CLOSING connection.meta
CLOSED connection.meta
CLOSING connection.summary
CLOSED connection.summary
CLOSING connection-recording.meta
CLOSED connection-recording.meta
CLOSING connection-recording-summary.json
CLOSED connection-recording-summary.json
CLOSING SHA256SUM
CLOSED SHA256SUM
CLOSING SHA256SUM.sig
@@ -2,5 +2,5 @@ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-inbou
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-outbound.data
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-inbound.data
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-outbound.data
03edd8ed2a4d678ea79d14538e504b6bb9aaec51c7e3ebf3a4891083d97ac7a9 connection.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 connection.summary
03edd8ed2a4d678ea79d14538e504b6bb9aaec51c7e3ebf3a4891083d97ac7a9 connection-recording.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 connection-recording-summary.json
@@ -0,0 +1,3 @@
id: session_123456789
protocol: TEST
connection: conn_1.connection
@@ -1,36 +0,0 @@
id: session_123456789
protocol: TEST
user_publicId: user123
user_scope_publicId: global
user_scope_type: global
target_publicId: target123
target_scope_publicId: proj123
target_scope_type: project
target_scope_parentId: org123
target_defaultPort: 0
target_sessionMaxSeconds: 0
target_sessionConnectionLimit: 0
worker_publicId: w_12345
worker_version: 0.25.5
worker_sha: beepboopgitsha
staticHost_publicId: host123
staticHostCatalog_publicId: staticcat123
staticHostCatalog_projectId: proj123
staticHost_address: 127.0.0.1
scs123_staticCredentialStore_publicId: scs123
scs123_staticCredentialStore_projectId: proj123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_publicId: scjson123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_projectId: proj123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_objectHmac: hmac
vcs123_vaultCredentialStore_publicId: vcs123
vcs123_vaultCredentialStore_projectId: proj123
vcs123_vaultCredentialStore_vaultAddress: an/address
vcs123_vaultCredentialStore_namespace: name
vcs123_vaultCredentialStore_tlsServerName: imaserver
vcs123_vaultCredentialStore_tlsSkipVerify: false
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_publicId: vl123
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_projectId: proj123
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_vaultPath: /a/path
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_httpMethod: GET
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_credentialType: magic
connection: conn_1.connection
@@ -2,10 +2,13 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING session.meta
CREATED session.meta
CREATING session.summary
CREATED session.summary
CREATING session-recording.meta
CREATED session-recording.meta
CREATING session-meta.json
CREATED session-meta.json
CLOSED session-meta.json
CREATING session-recording-summary.json
CREATED session-recording-summary.json
CREATING bsrKey.pub
CREATED bsrKey.pub
CLOSING bsrKey.pub
@@ -2,4 +2,5 @@
.* wrappedBsrKey
.* wrappedPrivKey
.* pubKeyBsrSignature.sign
.* pubKeySelfSignature.sign
.* pubKeySelfSignature.sign
.* session-meta.json
@@ -2,7 +2,7 @@ CREATING SHA256SUM.sig
CREATED SHA256SUM.sig
CREATING SHA256SUM
CREATED SHA256SUM
CREATING connection.meta
CREATED connection.meta
CREATING connection.summary
CREATED connection.summary
CREATING connection-recording.meta
CREATED connection-recording.meta
CREATING connection-recording-summary.json
CREATED connection-recording-summary.json
@@ -0,0 +1,2 @@
id: session_123456789
protocol: TEST
@@ -1,35 +0,0 @@
id: session_123456789
protocol: TEST
user_publicId: user123
user_scope_publicId: global
user_scope_type: global
target_publicId: target123
target_scope_publicId: proj123
target_scope_type: project
target_scope_parentId: org123
target_defaultPort: 0
target_sessionMaxSeconds: 0
target_sessionConnectionLimit: 0
worker_publicId: w_12345
worker_version: 0.25.5
worker_sha: beepboopgitsha
staticHost_publicId: host123
staticHostCatalog_publicId: staticcat123
staticHostCatalog_projectId: proj123
staticHost_address: 127.0.0.1
scs123_staticCredentialStore_publicId: scs123
scs123_staticCredentialStore_projectId: proj123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_publicId: scjson123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_projectId: proj123
scs123_staticCredentialStore_credential_scjson123_staticJsonCredential_objectHmac: hmac
vcs123_vaultCredentialStore_publicId: vcs123
vcs123_vaultCredentialStore_projectId: proj123
vcs123_vaultCredentialStore_vaultAddress: an/address
vcs123_vaultCredentialStore_namespace: name
vcs123_vaultCredentialStore_tlsServerName: imaserver
vcs123_vaultCredentialStore_tlsSkipVerify: false
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_publicId: vl123
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_projectId: proj123
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_vaultPath: /a/path
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_httpMethod: GET
vcs123_vaultCredentialStore_credential_vl123_vaultLibrary_credentialType: magic
+49 -50
View File
@@ -3,60 +3,30 @@
package bsr
func TestSessionMeta(s string, p Protocol) *SessionMeta {
scope := Scope{
PublicId: "global",
Type: "global",
}
staticCatalog := StaticHostCatalog{
PublicId: "staticcat123",
ProjectId: "proj123",
}
creds := make([]StaticCredential, 0)
c := StaticJsonCredential{
PublicId: "scjson123",
ProjectId: "proj123",
ObjectHmac: []byte("hmac"),
}
creds = append(creds, c)
staticCredentialStore := make([]StaticCredentialStore, 0)
scs := StaticCredentialStore{
PublicId: "scs123",
ProjectId: "proj123",
Credentials: creds,
}
staticCredentialStore = append(staticCredentialStore, scs)
vcreds := make([]DynamicCredentialLibraries, 0)
v := VaultLibrary{
PublicId: "vl123",
ProjectId: "proj123",
VaultPath: "/a/path",
HttpMethod: "GET",
CredentialType: "magic",
}
vcreds = append(vcreds, v)
vaultCredentialStore := make([]VaultCredentialStore, 0)
vcs := VaultCredentialStore{
PublicId: "vcs123",
ProjectId: "proj123",
VaultAddress: "an/address",
Namespace: "name",
TlsServerName: "imaserver",
TlsSkipVerify: false,
CredentialLibraries: vcreds,
}
vaultCredentialStore = append(vaultCredentialStore, vcs)
sessionMeta := &SessionMeta{
func TestSessionRecordingMeta(s string, p Protocol) *SessionRecordingMeta {
return &SessionRecordingMeta{
Id: s,
Protocol: p,
}
}
func TestSessionMeta(s string) *SessionMeta {
return &SessionMeta{
PublicId: s,
User: &User{
PublicId: "user123",
Scope: scope,
Scope: Scope{
PublicId: "global",
Type: "global",
},
},
StaticHost: &StaticHost{
PublicId: "host123",
Catalog: staticCatalog,
Address: "127.0.0.1",
Catalog: StaticHostCatalog{
PublicId: "staticcat123",
ProjectId: "proj123",
},
Address: "127.0.0.1",
},
Target: &Target{
PublicId: "target123",
@@ -74,8 +44,37 @@ func TestSessionMeta(s string, p Protocol) *SessionMeta {
Version: "0.25.5",
Sha: "beepboopgitsha",
},
StaticCredentialStore: staticCredentialStore,
VaultCredentialStore: vaultCredentialStore,
StaticCredentialStore: []StaticCredentialStore{
{
PublicId: "scs123",
ProjectId: "proj123",
StaticJsonCredentials: []StaticJsonCredential{
{
PublicId: "scjson123",
ProjectId: "proj123",
ObjectHmac: []byte("hmac"),
},
},
},
},
VaultCredentialStore: []VaultCredentialStore{
{
PublicId: "vcs123",
ProjectId: "proj123",
VaultAddress: "an/address",
Namespace: "name",
TlsServerName: "imaserver",
TlsSkipVerify: false,
VaultGenericLibraries: []VaultLibrary{
{
PublicId: "vl123",
ProjectId: "proj123",
VaultPath: "/a/path",
HttpMethod: "GET",
CredentialType: "magic",
},
},
},
},
}
return sessionMeta
}
+1
View File
@@ -25,6 +25,7 @@ type (
EndTime time.Time
BytesUp uint64
BytesDown uint64
Errors error
}
// ChannelSummary encapsulates data for a channel, including its id, channel type,