Merge branch 'main' into plugin-hostcatalogs

This commit is contained in:
Jeff Mitchell committed 2021-10-21 11:47:13 -04:00
commit 0fd906d964
146 files changed
+5532 -3412

No files matched your search

+19 -1
View File
@@ -1055,7 +1055,7 @@ jobs:
- run:
command: |
which pg_isready || sudo apt-get update && sudo apt-get install -y postgresql-client
make DOCKER_ARGS='-d' -C testing/dbtest/docker database-up
make DOCKER_ARGS='-d' PG_OPTS='-c shared_buffers=256MB -c max_connections=200000' -C testing/dbtest/docker database-up
until pg_isready -h 127.0.0.1; do docker container inspect boundary-sql-tests &> /dev/null || exit -1; sleep 1; done
name: Initialize Test Database
- run:
@@ -1267,6 +1267,17 @@ jobs:
name: Save package cache
paths:
- .buildcache/packages/store
trigger-merge-to-ent:
machine:
image: ubuntu-2004:202107-02
resource_class: medium
working_directory: ~/boundary
steps:
- checkout
- run:
command: |
./scripts/trigger-merge-to-ent
name: Trigger Merge to Enterprise
openbsd_amd64_package:
docker:
- image: docker.mirror.hashicorp.services/circleci/buildpack-deps
@@ -1648,4 +1659,11 @@ workflows:
branches:
only:
- stable-website
trigger-merge-to-ent:
jobs:
- trigger-merge-to-ent:
filters:
branches:
only:
- main
version: 2
+1 -1
View File
@@ -5,7 +5,7 @@ steps:
name: "Initialize Test Database"
command: |
which pg_isready || sudo apt-get update && sudo apt-get install -y postgresql-client
make DOCKER_ARGS='-d' -C testing/dbtest/docker database-up
make DOCKER_ARGS='-d' PG_OPTS='-c shared_buffers=256MB -c max_connections=200000' -C testing/dbtest/docker database-up
until pg_isready -h 127.0.0.1; do docker container inspect boundary-sql-tests &> /dev/null || exit -1; sleep 1; done
- run:
name: "Run Acceptance Tests"
@@ -0,0 +1,7 @@
executor: go-machine-medium
steps:
- checkout
- run:
name: "Trigger Merge to Enterprise"
command: |
./scripts/trigger-merge-to-ent
@@ -0,0 +1,6 @@
jobs:
- trigger-merge-to-ent:
filters:
branches:
only:
- main
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
remote="$1"
remote_url=$(git remote get-url $remote)
if [[ $remote_url == *"boundary-enterprise"* ]]; then
exit 0
fi
if [ -f cmd/boundary/package_registration_ent.go ]; then
echo "Found enterprise file while pushing to oss remote"
exit 1
fi
exit 0
+1
View File
@@ -127,6 +127,7 @@ protobuild:
@protoc-go-inject-tag -input=./internal/kms/store/session_key.pb.go
@protoc-go-inject-tag -input=./internal/kms/store/oidc_key.pb.go
@protoc-go-inject-tag -input=./internal/target/store/target.pb.go
@protoc-go-inject-tag -input=./internal/target/tcp/store/target.pb.go
@protoc-go-inject-tag -input=./internal/auth/oidc/store/oidc.pb.go
@protoc-go-inject-tag -input=./internal/scheduler/job/store/job.pb.go
@protoc-go-inject-tag -input=./internal/credential/store/credential.pb.go
+1
View File
@@ -0,0 +1 @@
/boundary
+6
View File
@@ -0,0 +1,6 @@
package main
import (
// Enable tcp target support.
_ "github.com/hashicorp/boundary/internal/target/tcp"
)
+2
View File
@@ -19,10 +19,12 @@ require (
github.com/fatih/color v1.12.0
github.com/fatih/structs v1.1.0
github.com/favadi/protoc-go-inject-tag v1.3.0
github.com/godbus/dbus/v5 v5.0.4 // indirect
github.com/golang-migrate/migrate/v4 v4.14.1
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe
github.com/golang/protobuf v1.5.2
github.com/google/go-cmp v0.5.6
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0
github.com/hashicorp/boundary/api v0.0.19
github.com/hashicorp/boundary/sdk v0.0.12-0.20211007161358-65f3725bf3e1
+5 -1
View File
@@ -341,8 +341,9 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E
github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY=
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
@@ -451,6 +452,8 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -1438,6 +1441,7 @@ google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200323114720-3f67cca34472/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
@@ -11,6 +11,7 @@ import (
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/authtoken"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/servers"
"github.com/hashicorp/boundary/internal/servers/controller"
@@ -92,10 +93,10 @@ func TestFetchActionSetForId(t *testing.T) {
authTokenRepoFn,
serversRepoFn,
tc.Kms(),
auth.RequestInfo{
&authpb.RequestInfo{
PublicId: token.Id,
EncryptedToken: strings.Split(token.Token, "_")[2],
TokenFormat: auth.AuthTokenTypeBearer,
TokenFormat: uint32(auth.AuthTokenTypeBearer),
})
typ := resource.Target
if tt.typeOverride != resource.Unknown {
+38 -104
View File
@@ -2,11 +2,9 @@ package oidc
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"net/url"
"strings"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
@@ -72,148 +70,84 @@ func (r *Repository) upsertAccount(ctx context.Context, am *AuthMethod, IdTokenC
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
columns := []string{"public_id", "auth_method_id", "issuer", "subject"}
values := []interface{}{
sql.Named("1", pubId),
sql.Named("2", am.PublicId),
sql.Named("3", iss),
sql.Named("4", sub),
}
var conflictClauses, fieldMasks, nullMasks []string
{
marshaledTokenClaims, err := json.Marshal(IdTokenClaims)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
columns, values = append(columns, "token_claims"), append(values, sql.Named(fmt.Sprintf("%d", len(values)+1), string(marshaledTokenClaims)))
conflictClauses = append(conflictClauses, fmt.Sprintf("token_claims = @%d", len(values)))
fieldMasks = append(fieldMasks, TokenClaimsField)
}
{
marshaledAccessTokenClaims, err := json.Marshal(AccessTokenClaims)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
columns, values = append(columns, "userinfo_claims"), append(values, sql.Named(fmt.Sprintf("%d", len(values)+1), string(marshaledAccessTokenClaims)))
conflictClauses = append(conflictClauses, fmt.Sprintf("userinfo_claims = @%d", len(values)))
fieldMasks = append(fieldMasks, UserinfoClaimsField)
}
issAsUrl, err := url.Parse(iss)
if err != nil {
return nil, errors.New(ctx, errors.Unknown, op, "unable to parse issuer", errors.WithWrap(err))
}
acctForOplog, err := NewAccount(ctx, am.PublicId, sub, WithIssuer(issAsUrl))
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create new acct for oplog"))
acct := AllocAccount()
acct.PublicId = pubId
acct.AuthMethodId = am.PublicId
acct.Issuer = issAsUrl.String()
acct.Subject = sub
oc := db.OnConflict{
Target: db.Constraint("auth_oidc_account_auth_method_id_issuer_subject_uq"),
Action: db.SetColumns([]string{"public_id", "auth_method_id", "issuer", "subject", "userinfo_claims", "token_claims"}),
}
var foundName interface{}
marshaledTokenClaims, err := json.Marshal(IdTokenClaims)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
acct.TokenClaims = string(marshaledTokenClaims)
marshaledAccessTokenClaims, err := json.Marshal(AccessTokenClaims)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
acct.UserinfoClaims = string(marshaledAccessTokenClaims)
var foundName, foundEmail bool
switch {
case AccessTokenClaims[fromName] != nil:
foundName = AccessTokenClaims[fromName]
columns, values = append(columns, "full_name"), append(values, sql.Named(fmt.Sprintf("%d", len(values)+1), foundName))
foundName = true
acct.FullName = AccessTokenClaims[fromName].(string)
case IdTokenClaims[fromName] != nil:
foundName = IdTokenClaims[fromName]
columns, values = append(columns, "full_name"), append(values, sql.Named(fmt.Sprintf("%d", len(values)+1), foundName))
}
if foundName != nil {
acctForOplog.FullName = foundName.(string)
conflictClauses = append(conflictClauses, fmt.Sprintf("full_name = @%d", len(values)))
fieldMasks = append(fieldMasks, NameField)
} else {
conflictClauses = append(conflictClauses, "full_name = NULL")
nullMasks = append(nullMasks, NameField)
foundName = true
acct.FullName = IdTokenClaims[fromName].(string)
}
var foundEmail interface{}
switch {
case AccessTokenClaims[fromEmail] != nil:
foundEmail = AccessTokenClaims[fromEmail]
columns, values = append(columns, "email"), append(values, sql.Named(fmt.Sprintf("%d", len(values)+1), foundEmail))
foundEmail = true
acct.Email = AccessTokenClaims[fromEmail].(string)
case IdTokenClaims[fromEmail] != nil:
foundEmail = IdTokenClaims[fromEmail]
columns, values = append(columns, "email"), append(values, sql.Named(fmt.Sprintf("%d", len(values)+1), foundEmail))
foundEmail = true
acct.Email = IdTokenClaims[fromEmail].(string)
}
if foundEmail != nil {
acctForOplog.Email = foundEmail.(string)
conflictClauses = append(conflictClauses, fmt.Sprintf("email = @%d", len(values)))
fieldMasks = append(fieldMasks, "Email")
} else {
conflictClauses = append(conflictClauses, "email = NULL")
nullMasks = append(nullMasks, "Email")
if foundName {
oc.Action = append(oc.Action.([]db.ColumnValue), db.SetColumns([]string{"full_name"})...)
}
placeHolders := make([]string, 0, len(columns))
for colNum := range columns {
placeHolders = append(placeHolders, fmt.Sprintf("@%d", colNum+1))
if foundEmail {
oc.Action = append(oc.Action.([]db.ColumnValue), db.SetColumns([]string{"email"})...)
}
query := fmt.Sprintf(acctUpsertQuery, strings.Join(columns, ", "), strings.Join(placeHolders, ", "), strings.Join(conflictClauses, ", "))
oplogWrapper, err := r.kms.GetWrapper(ctx, am.ScopeId, kms.KeyPurposeOplog)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
}
updatedAcct := AllocAccount()
_, err = r.writer.DoTx(
ctx,
db.StdRetryCnt,
db.ExpBackoff{},
func(reader db.Reader, w db.Writer) error {
var err error
rows, err := w.Query(ctx, query, values)
var rowCnt int64
err := w.Create(ctx, acct, db.WithOnConflict(&oc), db.WithReturnRowsAffected(&rowCnt), db.WithOplog(oplogWrapper, acct.oplog(oplog.OpType_OP_TYPE_CREATE, am.ScopeId)))
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to insert/update auth oidc account"))
}
defer rows.Close()
result := struct {
PublicId string
Version int
}{}
var rowCnt int
for rows.Next() {
rowCnt += 1
err = r.reader.ScanRows(rows, &result)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to scan rows for account"))
}
}
if rowCnt > 1 {
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("expected 1 row but got: %d", rowCnt))
}
if err := reader.LookupWhere(ctx, &updatedAcct, "auth_method_id = ? and issuer = ? and subject = ?", am.PublicId, iss, sub); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("unable to look up auth oidc account for: %s / %s / %s", am.PublicId, iss, sub)))
}
// include the version incase of predictable account public ids based on a calculation using authmethod id and subject
if result.Version == 1 && updatedAcct.PublicId == pubId {
if err := upsertOplog(ctx, w, oplogWrapper, oplog.OpType_OP_TYPE_CREATE, am.ScopeId, updatedAcct, nil, nil); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write create oplog for account"))
}
} else {
if len(fieldMasks) > 0 || len(nullMasks) > 0 {
acctForOplog := AllocAccount()
acctForOplog.PublicId = updatedAcct.PublicId
if foundEmail != nil {
acctForOplog.Email = foundEmail.(string)
}
if foundName != nil {
acctForOplog.FullName = foundName.(string)
}
if err := upsertOplog(ctx, w, oplogWrapper, oplog.OpType_OP_TYPE_UPDATE, am.ScopeId, acctForOplog, fieldMasks, nullMasks); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write update oplog for account"))
}
}
}
return nil
},
)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
return updatedAcct, nil
return acct, nil
}
// upsertOplog will write oplog msgs for account upserts. The db.Writer needs to be the writer for the current
+1 -1
View File
@@ -212,7 +212,7 @@ func validLoginName(u string) bool {
if u == "" {
return false
}
return !reInvalidLoginName.Match([]byte(u))
return !reInvalidLoginName.MatchString(u)
}
// UpdateAccount updates the repository entry for a.PublicId with the
+4 -3
View File
@@ -13,6 +13,7 @@ import (
hostplugin "github.com/hashicorp/boundary/internal/plugin/host"
"github.com/hashicorp/boundary/internal/servers/controller/auth"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/hashicorp/boundary/internal/types/scope"
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
"github.com/hashicorp/go-secure-stdlib/base62"
@@ -497,7 +498,7 @@ func (b *Server) CreateInitialTarget(ctx context.Context) (target.Target, error)
// Host Catalog
if b.DevTargetId == "" {
b.DevTargetId, err = db.NewPublicId(target.TcpTargetPrefix)
b.DevTargetId, err = db.NewPublicId(tcp.TargetPrefix)
if err != nil {
return nil, fmt.Errorf("error generating initial target id: %w", err)
}
@@ -514,11 +515,11 @@ func (b *Server) CreateInitialTarget(ctx context.Context) (target.Target, error)
target.WithSessionConnectionLimit(int32(b.DevTargetSessionConnectionLimit)),
target.WithPublicId(b.DevTargetId),
}
t, err := target.NewTcpTarget(b.DevProjectId, opts...)
t, err := tcp.New(b.DevProjectId, opts...)
if err != nil {
return nil, fmt.Errorf("error creating in memory target: %w", err)
}
tt, _, _, err := targetRepo.CreateTcpTarget(cancelCtx, t, opts...)
tt, _, _, err := targetRepo.CreateTarget(cancelCtx, t, opts...)
if err != nil {
return nil, fmt.Errorf("error saving target to the db: %w", err)
}
+2 -2
View File
@@ -23,7 +23,7 @@ import (
"github.com/hashicorp/boundary/internal/servers/controller"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"github.com/hashicorp/boundary/internal/servers/worker"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/strutil"
@@ -397,7 +397,7 @@ func (c *Command) Run(args []string) int {
c.DevHostCatalogId = fmt.Sprintf("%s_%s", static.HostCatalogPrefix, c.flagIdSuffix)
c.DevHostSetId = fmt.Sprintf("%s_%s", static.HostSetPrefix, c.flagIdSuffix)
c.DevHostId = fmt.Sprintf("%s_%s", static.HostPrefix, c.flagIdSuffix)
c.DevTargetId = fmt.Sprintf("%s_%s", target.TcpTargetPrefix, c.flagIdSuffix)
c.DevTargetId = fmt.Sprintf("%s_%s", tcp.TargetPrefix, c.flagIdSuffix)
}
host, port, err := net.SplitHostPort(c.flagHostAddress)
+1 -1
View File
@@ -301,7 +301,7 @@ func HandleAttributeFlags(c *base.Command, suffix, fullField string, sepFields [
case strings.HasPrefix(field.Value, `"`): // explicitly quoted string
val = strings.Trim(field.Value, `"`)
case jsonNumberRegex.Match([]byte(strings.Trim(field.Value, `"`))): // number
case jsonNumberRegex.MatchString(strings.Trim(field.Value, `"`)): // number
// Same logic as above
if strings.Contains(field.Value, ".") {
val, err = strconv.ParseFloat(field.Value, 64)
+10 -9
View File
@@ -17,6 +17,7 @@ import (
"github.com/hashicorp/boundary/internal/scheduler"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
wrapping "github.com/hashicorp/go-kms-wrapping"
vault "github.com/hashicorp/vault/api"
"github.com/stretchr/testify/assert"
@@ -815,7 +816,7 @@ func TestTokenRevocationJob_Run(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
target.TestCredentialLibrary(t, conn, tar.GetPublicId(), cl.GetPublicId())
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
UserId: uId,
@@ -1008,7 +1009,7 @@ func TestCredentialRenewalJob_RunLimits(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
target.TestCredentialLibrary(t, conn, tar.GetPublicId(), cl.GetPublicId())
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
UserId: uId,
@@ -1117,7 +1118,7 @@ func TestCredentialRenewalJob_Run(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
UserId: uId,
HostId: h.GetPublicId(),
@@ -1223,7 +1224,7 @@ func TestCredentialRenewalJob_RunExpired(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
UserId: uId,
HostId: h.GetPublicId(),
@@ -1296,7 +1297,7 @@ func TestCredentialRenewalJob_NextRunIn(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
target.TestCredentialLibrary(t, conn, tar.GetPublicId(), cl.GetPublicId())
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
UserId: uId,
@@ -1535,7 +1536,7 @@ func TestCredentialRevocationJob_RunLimits(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
target.TestCredentialLibrary(t, conn, tar.GetPublicId(), cl.GetPublicId())
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
UserId: uId,
@@ -1646,7 +1647,7 @@ func TestCredentialRevocationJob_Run(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
UserId: uId,
HostId: h.GetPublicId(),
@@ -1736,7 +1737,7 @@ func TestCredentialRevocationJob_RunDeleted(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
UserId: uId,
HostId: h.GetPublicId(),
@@ -2114,7 +2115,7 @@ func TestCredentialCleanupJob_Run(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
sess1 := session.TestSession(t, conn, wrapper, session.ComposedOf{
UserId: uId,
HostId: h.GetPublicId(),
@@ -16,6 +16,7 @@ import (
"github.com/hashicorp/boundary/internal/scheduler"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -103,7 +104,7 @@ func TestRepository_IssueCredentials(t *testing.T) {
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
rc2dc := func(rcs []credential.Request) []*session.DynamicCredential {
var dcs []*session.DynamicCredential
@@ -221,7 +222,7 @@ func TestRepository_Revoke(t *testing.T) {
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
target.TestCredentialLibrary(t, conn, tar.GetPublicId(), cl.GetPublicId())
const (
@@ -339,7 +340,7 @@ func Test_TerminateSession(t *testing.T) {
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
target.TestCredentialLibrary(t, conn, tar.GetPublicId(), cl.GetPublicId())
const (
@@ -11,6 +11,7 @@ import (
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -34,7 +35,7 @@ func Test_TestCredentials(t *testing.T) {
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
target.TestCredentialLibrary(t, conn, tar.GetPublicId(), cl.GetPublicId())
at := authtoken.TestAuthToken(t, conn, kms, org.GetPublicId())
+123
View File
@@ -0,0 +1,123 @@
package db
import (
"sort"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
// ColumnValue defines a column and it's assigned value for a database operation
type ColumnValue struct {
column string
value interface{}
}
type assigner interface {
toAssignment(column string) clause.Assignment
}
// column represents a table column
type column struct {
name string
table string
}
func (c *column) toAssignment(column string) clause.Assignment {
return clause.Assignment{
Column: clause.Column{Name: column},
Value: clause.Column{Table: c.table, Name: c.name},
}
}
func rawAssignment(column string, value interface{}) clause.Assignment {
return clause.Assignment{
Column: clause.Column{Name: column},
Value: value,
}
}
// ExprValue encapsulates an expression value for a column assignment. See
// Expr(...) to create these values.
type ExprValue struct {
sql string
vars []interface{}
}
func (ev *ExprValue) toAssignment(column string) clause.Assignment {
return clause.Assignment{
Column: clause.Column{Name: column},
Value: gorm.Expr(ev.sql, ev.vars...),
}
}
// Expr creates an expression value (ExprValue) which can be used when setting
// column values for database operations. See: Expr(...)
//
// Set name column to null example:
// SetColumnValues(map[string]interface{}{"name": Expr("NULL")})
//
// Set exp_time column to N seconds from now:
// SetColumnValues(map[string]interface{}{"exp_time": Expr("wt_add_seconds_to_now(?)", 10)})
func Expr(expr string, args ...interface{}) ExprValue {
return ExprValue{sql: expr, vars: args}
}
// SetColumnValues defines a map from column names to values
func SetColumnValues(columnValues map[string]interface{}) []ColumnValue {
keys := make([]string, 0, len(columnValues))
for key := range columnValues {
keys = append(keys, key)
}
sort.Strings(keys)
assignments := make([]ColumnValue, len(keys))
for idx, key := range keys {
assignments[idx] = ColumnValue{column: key, value: columnValues[key]}
}
return assignments
}
// SetColumns defines a list of column (names) to update using the set of
// proposed insert columns during an on conflict update.
func SetColumns(names []string) []ColumnValue {
assignments := make([]ColumnValue, len(names))
for idx, name := range names {
assignments[idx] = ColumnValue{
column: name,
value: column{name: name, table: "excluded"},
}
}
return assignments
}
// OnConflict specifies how to handle alternative actions to take when an insert
// results in a unique constraint or exclusion constraint error.
type OnConflict struct {
// Target specifies what conflict you want to define a policy for. This can
// be any one of these:
// Columns: the name of a specific column or columns
// Constraint: the name of a unique constraint
Target interface{}
// Action specifies the action to take on conflict. This can be any one of
// these:
// DoNothing: leaves the conflicting record as-is
// UpdateAll: updates all the columns of the conflicting record using the resource's data
// []ColumnValue: update a set of columns of the conflicting record using the set of assignments
Action interface{}
}
// Constraint defines database constraint name
type Constraint string
// Columns defines a set of column names
type Columns []string
// DoNothing defines an "on conflict" action of doing nothing
type DoNothing bool
// UpdateAll defines an "on conflict" action of updating all columns using the
// proposed insert column values
type UpdateAll bool
+19
View File
@@ -47,6 +47,9 @@ type Options struct {
withGormFormatter hclog.Logger
withMaxOpenConnections int
withOnConflict *OnConflict
withRowsAffected *int64
}
type oplogOpts struct {
@@ -185,3 +188,19 @@ func WithMaxOpenConnections(max int) Option {
o.withMaxOpenConnections = max
}
}
// WithOnConflict specifies an optional on conflict criteria which specify
// alternative actions to take when an insert results in a unique constraint or
// exclusion constraint error
func WithOnConflict(onConflict *OnConflict) Option {
return func(o *Options) {
o.withOnConflict = onConflict
}
}
// WithReturnRowsAffected specifies an option for returning the rows affected
func WithReturnRowsAffected(rowsAffected *int64) Option {
return func(o *Options) {
o.withRowsAffected = rowsAffected
}
}
+29 -10
View File
@@ -141,8 +141,6 @@ func Test_getOpts(t *testing.T) {
testOpts := getDefaultOptions()
testOpts.withSkipVetForWrite = false
assert.Equal(opts, testOpts)
// try setting to false
opts = GetOpts(WithSkipVetForWrite(true))
testOpts = getDefaultOptions()
testOpts.withSkipVetForWrite = true
@@ -156,8 +154,6 @@ func Test_getOpts(t *testing.T) {
testOpts.withWhereClause = ""
testOpts.withWhereClauseArgs = nil
assert.Equal(opts, testOpts)
// try setting to false
opts = GetOpts(WithWhere("id = ? and foo = ?", 1234, "bar"))
testOpts.withWhereClause = "id = ? and foo = ?"
testOpts.withWhereClauseArgs = []interface{}{1234, "bar"}
@@ -170,8 +166,6 @@ func Test_getOpts(t *testing.T) {
testOpts := getDefaultOptions()
testOpts.withOrder = ""
assert.Equal(opts, testOpts)
// try setting to false
opts = GetOpts(WithOrder("version desc"))
testOpts.withOrder = "version desc"
assert.Equal(opts, testOpts)
@@ -184,8 +178,6 @@ func Test_getOpts(t *testing.T) {
assert.Equal(opts, testOpts)
testLogger := hclog.New(&hclog.LoggerOptions{})
// try setting to false
opts = GetOpts(WithGormFormatter(testLogger))
testOpts.withGormFormatter = testLogger
assert.Equal(opts, testOpts)
@@ -196,10 +188,37 @@ func Test_getOpts(t *testing.T) {
opts := GetOpts()
testOpts := getDefaultOptions()
assert.Equal(opts, testOpts)
// try setting to false
opts = GetOpts(WithMaxOpenConnections(22))
testOpts.withMaxOpenConnections = 22
assert.Equal(opts, testOpts)
})
t.Run("WithOnConflict", func(t *testing.T) {
assert := assert.New(t)
// test default of false
opts := GetOpts()
testOpts := getDefaultOptions()
assert.Equal(opts, testOpts)
columns := SetColumns([]string{"name", "description"})
columnValues := SetColumnValues(map[string]interface{}{"expiration": "NULL"})
testOnConflict := OnConflict{
Target: Constraint("uniq-name"),
Action: append(columns, columnValues...),
}
opts = GetOpts(WithOnConflict(&testOnConflict))
testOpts.withOnConflict = &testOnConflict
assert.Equal(opts, testOpts)
})
t.Run("WithReturnRowsAffected", func(t *testing.T) {
assert := assert.New(t)
// test default of false
opts := GetOpts()
testOpts := getDefaultOptions()
assert.Equal(opts, testOpts)
var rowsAffected int64
opts = GetOpts(WithReturnRowsAffected(&rowsAffected))
testOpts.withRowsAffected = &rowsAffected
assert.Equal(opts, testOpts)
})
}
+73 -10
View File
@@ -15,6 +15,7 @@ import (
wrapping "github.com/hashicorp/go-kms-wrapping"
"google.golang.org/protobuf/proto"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
const (
@@ -260,10 +261,12 @@ func (rw *Db) lookupAfterWrite(ctx context.Context, i interface{}, opt ...Option
return nil
}
// Create an object in the db with options: WithOplog, NewOplogMsg and
// WithLookup. WithOplog will write an oplog entry for the create.
// Create an object in the db with options: WithOplog, NewOplogMsg, WithLookup
// and OnConflict. WithOplog will write an oplog entry for the create.
// NewOplogMsg will return in-memory oplog message. WithOplog and NewOplogMsg
// cannot be used together. WithLookup with to force a lookup after create.
// OnConflict specifies alternative actions to take when an insert results in a
// unique constraint or exclusion constraint error.
func (rw *Db) Create(ctx context.Context, i interface{}, opt ...Option) error {
const op = "db.Create"
if rw.underlying == nil {
@@ -295,6 +298,54 @@ func (rw *Db) Create(ctx context.Context, i interface{}, opt ...Option) error {
}
}
}
db := rw.underlying.WithContext(ctx)
var onConflictDoNothing bool
if opts.withOnConflict != nil {
c := clause.OnConflict{}
switch opts.withOnConflict.Target.(type) {
case Constraint:
c.OnConstraint = string(opts.withOnConflict.Target.(Constraint))
case Columns:
columns := make([]clause.Column, 0, len(opts.withOnConflict.Target.(Columns)))
for _, name := range opts.withOnConflict.Target.(Columns) {
columns = append(columns, clause.Column{Name: name})
}
c.Columns = columns
default:
return errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("invalid conflict target: %v", reflect.TypeOf(opts.withOnConflict.Target)))
}
switch opts.withOnConflict.Action.(type) {
case DoNothing:
c.DoNothing = true
onConflictDoNothing = true
case UpdateAll:
c.UpdateAll = true
case []ColumnValue:
updates := opts.withOnConflict.Action.([]ColumnValue)
set := make(clause.Set, 0, len(updates))
for _, s := range updates {
// make sure it's not one of the std immutable columns
if contains([]string{"createtime", "publicid"}, strings.ToLower(s.column)) {
return errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("Cannot do update on conflict for column %s", s.column))
}
switch sv := s.value.(type) {
case column:
set = append(set, sv.toAssignment(s.column))
case ExprValue:
set = append(set, sv.toAssignment(s.column))
default:
set = append(set, rawAssignment(s.column, s.value))
}
}
c.DoUpdates = set
default:
return errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("invalid conflict action: %v", reflect.TypeOf(opts.withOnConflict.Action)))
}
db = db.Clauses(c)
}
var ticket *store.Ticket
if withOplog {
var err error
@@ -303,20 +354,32 @@ func (rw *Db) Create(ctx context.Context, i interface{}, opt ...Option) error {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get ticket"))
}
}
if err := rw.underlying.Create(i).Error; err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("create failed"), errors.WithoutEvent())
tx := db.Create(i)
if tx.Error != nil {
return errors.Wrap(ctx, tx.Error, op, errors.WithMsg("create failed"), errors.WithoutEvent())
}
if opts.withRowsAffected != nil {
*opts.withRowsAffected = tx.RowsAffected
}
if withOplog {
if err := rw.addOplog(ctx, CreateOp, opts, ticket, i); err != nil {
return errors.Wrap(ctx, err, op)
switch {
case onConflictDoNothing && tx.RowsAffected == 0:
default:
if err := rw.addOplog(ctx, CreateOp, opts, ticket, i); err != nil {
return errors.Wrap(ctx, err, op)
}
}
}
if opts.newOplogMsg != nil {
msg, err := rw.newOplogMessage(ctx, CreateOp, i)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("returning oplog failed"))
switch {
case onConflictDoNothing && tx.RowsAffected == 0:
default:
msg, err := rw.newOplogMessage(ctx, CreateOp, i)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("returning oplog failed"))
}
*opts.newOplogMsg = *msg
}
*opts.newOplogMsg = *msg
}
if err := rw.lookupAfterWrite(ctx, i, opt...); err != nil {
return errors.Wrap(ctx, err, op, errors.WithoutEvent())
+152
View File
@@ -0,0 +1,152 @@
package db_test
import (
"context"
"testing"
"time"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/db_test"
"github.com/hashicorp/boundary/internal/db/timestamp"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb"
)
func TestDb_Create_OnConflict(t *testing.T) {
ctx := context.Background()
wrapper := db.TestWrapper(t)
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
// create initial user for on conflict tests
id, err := db.NewPublicId("test-user")
require.NoError(t, err)
initialUser, err := db_test.NewTestUser()
require.NoError(t, err)
ts := &timestamp.Timestamp{Timestamp: timestamppb.Now()}
initialUser.CreateTime = ts
initialUser.UpdateTime = ts
initialUser.Name = "foo-" + id
err = rw.Create(ctx, initialUser)
require.NoError(t, err)
assert.NotEmpty(t, initialUser.Id)
tests := []struct {
name string
onConflict db.OnConflict
wantUpdate bool
wantEmail string
wantOplog bool
}{
{
name: "set-columns",
onConflict: db.OnConflict{
Target: db.Columns{"public_id"},
Action: db.SetColumns([]string{"name"}),
},
wantUpdate: true,
wantOplog: true,
},
{
name: "set-column-values",
onConflict: db.OnConflict{
Target: db.Columns{"public_id"},
Action: db.SetColumnValues(map[string]interface{}{
"name": db.Expr("md5(?)", "alice eve smith"),
"email": "alice@gmail.com",
"phone_number": db.Expr("NULL"),
}),
},
wantUpdate: true,
wantEmail: "alice@gmail.com",
wantOplog: true,
},
{
name: "both-set-columns-and-set-column-values",
onConflict: func() db.OnConflict {
onConflict := db.OnConflict{
Target: db.Columns{"public_id"},
}
cv := db.SetColumns([]string{"name"})
cv = append(cv,
db.SetColumnValues(map[string]interface{}{
"email": "alice@gmail.com",
"phone_number": db.Expr("NULL"),
})...)
onConflict.Action = cv
return onConflict
}(),
wantUpdate: true,
wantEmail: "alice@gmail.com",
wantOplog: true,
},
{
name: "update-all",
onConflict: db.OnConflict{
Target: db.Columns{"public_id"},
Action: db.UpdateAll(true),
},
wantUpdate: true,
wantOplog: true,
},
{
name: "do-nothing",
onConflict: db.OnConflict{
Target: db.Columns{"public_id"},
Action: db.DoNothing(true),
},
wantOplog: false,
},
{
name: "on-constraint",
onConflict: db.OnConflict{
Target: db.Constraint("db_test_user_public_id_key"),
Action: db.SetColumns([]string{"name"}),
},
wantUpdate: true,
wantOplog: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
conflictUser, err := db_test.NewTestUser()
require.NoError(err)
userNameId, err := db.NewPublicId("test-user-name")
require.NoError(err)
conflictUser.PublicId = initialUser.PublicId
conflictUser.Name = userNameId
md := oplog.Metadata{
"resource-public-id": []string{conflictUser.PublicId},
"op-type": []string{oplog.OpType_OP_TYPE_CREATE.String()},
}
var rowsAffected int64
err = rw.Create(ctx, conflictUser, db.WithOnConflict(&tt.onConflict), db.WithOplog(wrapper, md), db.WithReturnRowsAffected(&rowsAffected))
require.NoError(err)
if tt.wantOplog {
err = db.TestVerifyOplog(t, rw, conflictUser.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second))
assert.NoError(err)
}
foundUser, err := db_test.NewTestUser()
require.NoError(err)
foundUser.PublicId = conflictUser.PublicId
err = rw.LookupByPublicId(context.Background(), foundUser)
require.NoError(err)
if tt.wantUpdate {
assert.Equal(int64(1), rowsAffected)
assert.Equal(conflictUser.Id, foundUser.Id)
assert.Equal(conflictUser.Name, foundUser.Name)
if tt.wantEmail != "" {
assert.Equal(tt.wantEmail, foundUser.Email)
}
} else {
assert.Equal(int64(0), rowsAffected)
assert.NotEqual(conflictUser.Id, foundUser.Id)
assert.NotEqual(conflictUser.Name, foundUser.Name)
}
})
}
}
+1 -1
View File
@@ -723,8 +723,8 @@ func TestDb_Create(t *testing.T) {
metadata := oplog.Metadata{
"resource-public-id": []string{user.PublicId},
// "op-type": []string{oplog.OpType_OP_TYPE_UPDATE.String()},
}
err = w.WriteOplogEntryWith(context.Background(), TestWrapper(t), ticket, metadata, []*oplog.Message{&createMsg, &updateMsg})
require.NoError(err)
@@ -0,0 +1,16 @@
begin;
-- server table inserts/updates historically included setting the update_time
-- column to now(). Since we're now using the "standard" db package to do this,
-- we need to add triggers to set the update_time for every insert/update.
create trigger
update_time_column
before update on server
for each row execute procedure update_time_column();
create trigger
insert_time_column
before insert on server
for each row execute procedure update_time_column();
commit;
@@ -14,6 +14,7 @@ import (
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/hashicorp/boundary/testing/dbtest"
wrapping "github.com/hashicorp/go-kms-wrapping"
"github.com/stretchr/testify/assert"
@@ -79,7 +80,7 @@ func TestMigrations_UserDimension(t *testing.T) {
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
var sessions []*session.Session
kmsCache := kms.TestKms(t, conn, wrapper)
@@ -15,6 +15,7 @@ import (
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/hashicorp/boundary/testing/dbtest"
wrapping "github.com/hashicorp/go-kms-wrapping"
"github.com/stretchr/testify/assert"
@@ -81,7 +82,7 @@ func TestMigrations_CredentialDimension(t *testing.T) {
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, prj.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
var sessions []*session.Session
kmsCache := kms.TestKms(t, conn, wrapper)
@@ -157,12 +158,12 @@ func TestMigrations_CredentialDimension(t *testing.T) {
require.Equal(want, state)
}
func testSessionCredentialParams(t *testing.T, conn *db.DB, kms *kms.Kms, wrapper wrapping.Wrapper, tar *target.TcpTarget) []*session.DynamicCredential {
func testSessionCredentialParams(t *testing.T, conn *db.DB, kms *kms.Kms, wrapper wrapping.Wrapper, tar target.Target) []*session.DynamicCredential {
t.Helper()
rw := db.New(conn)
ctx := context.Background()
stores := vault.TestCredentialStores(t, conn, wrapper, tar.ScopeId, 1)
stores := vault.TestCredentialStores(t, conn, wrapper, tar.GetScopeId(), 1)
libs := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2)
targetRepo, err := target.NewRepository(rw, rw, kms)
+5 -3
View File
@@ -66,9 +66,11 @@ const (
GenKey Code = 304 // GenKey represents an error occurred during the underlying key generation process
GenCert Code = 305 // GenCert represents an error occurred during the underlying certificate generation process
// General system errors are reserved Codes 400-599 and align with http client and server error codes
Forbidden Code = 403 // Forbidden represents the operation is forbidden
Internal Code = 500 // InternalError represents the system encountered an unexpected condition.
// General system errors are reserved Codes 400-599 and align with http
// client and server error codes
Unauthorized Code = 401 // Unauthorized represents the operation is unauthorized
Forbidden Code = 403 // Forbidden represents the operation is forbidden
Internal Code = 500 // InternalError represents the system encountered an unexpected condition.
// DB errors are reserved Codes from 1000-1999
CheckConstraint Code = 1000 // CheckConstraint represents a check constraint error
+44
View File
@@ -7,6 +7,7 @@ import (
"runtime"
"strings"
pberrors "github.com/hashicorp/boundary/internal/gen/errors"
"github.com/hashicorp/boundary/internal/observability/event"
"github.com/jackc/pgconn"
)
@@ -266,6 +267,49 @@ func (e *Err) Error() string {
return s.String()
}
// ToPbErrors will convert to an Err protobuf
func ToPbErrors(err *Err) *pberrors.Err {
pbErr := &pberrors.Err{
Code: uint32(err.Code),
Msg: err.Msg,
Op: string(err.Op),
}
var wrappedErr *Err
isWrappedErr := As(err.Wrapped, &wrappedErr)
switch {
case err.Wrapped == nil:
pbErr.Wrapped = &pberrors.Err_None{
None: false,
}
case isWrappedErr:
pbErr.Wrapped = &pberrors.Err_Err{
Err: ToPbErrors(wrappedErr),
}
default:
pbErr.Wrapped = &pberrors.Err_StdError{
StdError: err.Wrapped.Error(),
}
}
return pbErr
}
// FromPbErrors will convert from Err protobuf
func FromPbErrors(pbErr *pberrors.Err) *Err {
err := &Err{
Code: Code(pbErr.Code),
Msg: pbErr.Msg,
Op: Op(pbErr.Op),
}
switch w := pbErr.Wrapped.(type) {
case *pberrors.Err_Err:
err.Wrapped = FromPbErrors(w.Err)
case *pberrors.Err_StdError:
err.Wrapped = errors.New(w.StdError)
}
return err
}
func join(str *strings.Builder, delim string, s string) {
if str.Len() == 0 {
_, _ = str.WriteString(s)
+4
View File
@@ -148,6 +148,10 @@ var errorCodeInfo = map[Code]Info{
Message: "forbidden",
Kind: Other,
},
Unauthorized: {
Message: "unauthorized",
Kind: Other,
},
CheckConstraint: {
Message: "constraint check failed",
Kind: Integrity,
+8 -4
View File
@@ -5038,7 +5038,8 @@
"items": {
"type": "string"
},
"description": "The IDs of the Host Sets associated with this Target."
"description": "Output only. The IDs of the Host Sets associated with this Target.",
"readOnly": true
},
"host_sets": {
"type": "array",
@@ -5053,7 +5054,8 @@
"items": {
"type": "string"
},
"description": "The IDs of the Host Sources associated with this Target."
"description": "Output only. The IDs of the Host Sources associated with this Target.",
"readOnly": true
},
"host_sources": {
"type": "array",
@@ -5082,7 +5084,8 @@
"items": {
"type": "string"
},
"description": "The IDs of the application credential library ids associated with this Target. Deprecated: use application_credential_source_ids instead."
"description": "Output only. The IDs of the application credential library ids associated with this Target. Deprecated: use application_credential_source_ids instead.",
"readOnly": true
},
"application_credential_libraries": {
"type": "array",
@@ -5097,7 +5100,8 @@
"items": {
"type": "string"
},
"description": "The IDs of the application credential source ids associated with this Target."
"description": "Output only. The IDs of the application credential source ids associated with this Target.",
"readOnly": true
},
"application_credential_sources": {
"type": "array",
+137
View File
@@ -0,0 +1,137 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.17.3
// source: controller/api/v1/empty_msg.proto
package api
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// EmptyResponse represents an empty response
type EmptyResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *EmptyResponse) Reset() {
*x = EmptyResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_v1_empty_msg_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EmptyResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EmptyResponse) ProtoMessage() {}
func (x *EmptyResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_v1_empty_msg_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EmptyResponse.ProtoReflect.Descriptor instead.
func (*EmptyResponse) Descriptor() ([]byte, []int) {
return file_controller_api_v1_empty_msg_proto_rawDescGZIP(), []int{0}
}
var File_controller_api_v1_empty_msg_proto protoreflect.FileDescriptor
var file_controller_api_v1_empty_msg_proto_rawDesc = []byte{
0x0a, 0x21, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x76, 0x31, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x6d, 0x73, 0x67, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x22, 0x0f, 0x0a, 0x0d, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3f, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f,
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_controller_api_v1_empty_msg_proto_rawDescOnce sync.Once
file_controller_api_v1_empty_msg_proto_rawDescData = file_controller_api_v1_empty_msg_proto_rawDesc
)
func file_controller_api_v1_empty_msg_proto_rawDescGZIP() []byte {
file_controller_api_v1_empty_msg_proto_rawDescOnce.Do(func() {
file_controller_api_v1_empty_msg_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_api_v1_empty_msg_proto_rawDescData)
})
return file_controller_api_v1_empty_msg_proto_rawDescData
}
var file_controller_api_v1_empty_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_controller_api_v1_empty_msg_proto_goTypes = []interface{}{
(*EmptyResponse)(nil), // 0: controller.api.v1.EmptyResponse
}
var file_controller_api_v1_empty_msg_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_controller_api_v1_empty_msg_proto_init() }
func file_controller_api_v1_empty_msg_proto_init() {
if File_controller_api_v1_empty_msg_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_controller_api_v1_empty_msg_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EmptyResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_api_v1_empty_msg_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_controller_api_v1_empty_msg_proto_goTypes,
DependencyIndexes: file_controller_api_v1_empty_msg_proto_depIdxs,
MessageInfos: file_controller_api_v1_empty_msg_proto_msgTypes,
}.Build()
File_controller_api_v1_empty_msg_proto = out.File
file_controller_api_v1_empty_msg_proto_rawDesc = nil
file_controller_api_v1_empty_msg_proto_goTypes = nil
file_controller_api_v1_empty_msg_proto_depIdxs = nil
}
+263
View File
@@ -0,0 +1,263 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.17.3
// source: controller/auth/v1/auth.proto
package auth
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// RequestInfo contains request parameters necessary for checking authn/authz
type RequestInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// path of the request
Path string `protobuf:"bytes,10,opt,name=path,proto3" json:"path,omitempty"`
// method (http verb) of the request
Method string `protobuf:"bytes,20,opt,name=method,proto3" json:"method,omitempty"`
// public_id for the request
PublicId string `protobuf:"bytes,30,opt,name=public_id,json=publicId,proto3" json:"public_id,omitempty"`
// encrypted_token from the request
EncryptedToken string `protobuf:"bytes,40,opt,name=encrypted_token,json=encryptedToken,proto3" json:"encrypted_token,omitempty"`
// token from the request
Token string `protobuf:"bytes,50,opt,name=token,proto3" json:"token,omitempty"`
// token_format of the request's token
TokenFormat uint32 `protobuf:"varint,60,opt,name=token_format,json=tokenFormat,proto3" json:"token_format,omitempty"`
// scope_id_override for the request (helpful for tests)
ScopeIdOverride string `protobuf:"bytes,70,opt,name=scope_id_override,json=scopeIdOverride,proto3" json:"scope_id_override,omitempty"`
// user_id_override for the request (helpful for tests)
UserIdOverride string `protobuf:"bytes,80,opt,name=user_id_override,json=userIdOverride,proto3" json:"user_id_override,omitempty"`
// disable_authz_failures for the request (helpful for tests)
DisableAuthzFailures bool `protobuf:"varint,90,opt,name=disable_authz_failures,json=disableAuthzFailures,proto3" json:"disable_authz_failures,omitempty"`
// disable_auth_entirely for the request (helpful for tests)
DisableAuthEntirely bool `protobuf:"varint,100,opt,name=disable_auth_entirely,json=disableAuthEntirely,proto3" json:"disable_auth_entirely,omitempty"`
// ticket is a unique id that allows the grpc-gateway to verify that the info
// came from its companion http proxy
Ticket string `protobuf:"bytes,110,opt,name=ticket,proto3" json:"ticket,omitempty"`
}
func (x *RequestInfo) Reset() {
*x = RequestInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_auth_v1_auth_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RequestInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RequestInfo) ProtoMessage() {}
func (x *RequestInfo) ProtoReflect() protoreflect.Message {
mi := &file_controller_auth_v1_auth_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RequestInfo.ProtoReflect.Descriptor instead.
func (*RequestInfo) Descriptor() ([]byte, []int) {
return file_controller_auth_v1_auth_proto_rawDescGZIP(), []int{0}
}
func (x *RequestInfo) GetPath() string {
if x != nil {
return x.Path
}
return ""
}
func (x *RequestInfo) GetMethod() string {
if x != nil {
return x.Method
}
return ""
}
func (x *RequestInfo) GetPublicId() string {
if x != nil {
return x.PublicId
}
return ""
}
func (x *RequestInfo) GetEncryptedToken() string {
if x != nil {
return x.EncryptedToken
}
return ""
}
func (x *RequestInfo) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
func (x *RequestInfo) GetTokenFormat() uint32 {
if x != nil {
return x.TokenFormat
}
return 0
}
func (x *RequestInfo) GetScopeIdOverride() string {
if x != nil {
return x.ScopeIdOverride
}
return ""
}
func (x *RequestInfo) GetUserIdOverride() string {
if x != nil {
return x.UserIdOverride
}
return ""
}
func (x *RequestInfo) GetDisableAuthzFailures() bool {
if x != nil {
return x.DisableAuthzFailures
}
return false
}
func (x *RequestInfo) GetDisableAuthEntirely() bool {
if x != nil {
return x.DisableAuthEntirely
}
return false
}
func (x *RequestInfo) GetTicket() string {
if x != nil {
return x.Ticket
}
return ""
}
var File_controller_auth_v1_auth_proto protoreflect.FileDescriptor
var file_controller_auth_v1_auth_proto_rawDesc = []byte{
0x0a, 0x1d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x75, 0x74,
0x68, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x12, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x75, 0x74, 0x68,
0x2e, 0x76, 0x31, 0x22, 0x90, 0x03, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49,
0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f,
0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12,
0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x1e, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f,
0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18,
0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x32,
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x74,
0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x3c, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x0b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x2a,
0x0a, 0x11, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72,
0x69, 0x64, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x6f, 0x70, 0x65,
0x49, 0x64, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73,
0x65, 0x72, 0x5f, 0x69, 0x64, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x50,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x4f, 0x76, 0x65, 0x72,
0x72, 0x69, 0x64, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f,
0x61, 0x75, 0x74, 0x68, 0x7a, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x18, 0x5a,
0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x75, 0x74,
0x68, 0x7a, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x64, 0x69,
0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x72,
0x65, 0x6c, 0x79, 0x18, 0x64, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x64, 0x69, 0x73, 0x61, 0x62,
0x6c, 0x65, 0x41, 0x75, 0x74, 0x68, 0x45, 0x6e, 0x74, 0x69, 0x72, 0x65, 0x6c, 0x79, 0x12, 0x16,
0x0a, 0x06, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x41, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f,
0x61, 0x75, 0x74, 0x68, 0x3b, 0x61, 0x75, 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_controller_auth_v1_auth_proto_rawDescOnce sync.Once
file_controller_auth_v1_auth_proto_rawDescData = file_controller_auth_v1_auth_proto_rawDesc
)
func file_controller_auth_v1_auth_proto_rawDescGZIP() []byte {
file_controller_auth_v1_auth_proto_rawDescOnce.Do(func() {
file_controller_auth_v1_auth_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_auth_v1_auth_proto_rawDescData)
})
return file_controller_auth_v1_auth_proto_rawDescData
}
var file_controller_auth_v1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_controller_auth_v1_auth_proto_goTypes = []interface{}{
(*RequestInfo)(nil), // 0: controller.auth.v1.RequestInfo
}
var file_controller_auth_v1_auth_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_controller_auth_v1_auth_proto_init() }
func file_controller_auth_v1_auth_proto_init() {
if File_controller_auth_v1_auth_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_controller_auth_v1_auth_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RequestInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_auth_v1_auth_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_controller_auth_v1_auth_proto_goTypes,
DependencyIndexes: file_controller_auth_v1_auth_proto_depIdxs,
MessageInfos: file_controller_auth_v1_auth_proto_msgTypes,
}.Build()
File_controller_auth_v1_auth_proto = out.File
file_controller_auth_v1_auth_proto_rawDesc = nil
file_controller_auth_v1_auth_proto_goTypes = nil
file_controller_auth_v1_auth_proto_depIdxs = nil
}
+322
View File
@@ -0,0 +1,322 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.17.3
// source: errors/v1/errors.proto
package errors
import (
api "github.com/hashicorp/boundary/internal/gen/controller/api"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Err is a protobuf representation of a domain error
type Err struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// code is the error's code, which can be used to get the error's
// errorCodeInfo, which contains the error's Kind and Message
Code uint32 `protobuf:"varint,10,opt,name=code,proto3" json:"code,omitempty"`
// msg for the error
Msg string `protobuf:"bytes,20,opt,name=msg,proto3" json:"msg,omitempty"`
// op represents the operation raising/propagating an error and is optional.
Op string `protobuf:"bytes,30,opt,name=op,proto3" json:"op,omitempty"`
// wrapped represents an optionally wrapped error
//
// Types that are assignable to Wrapped:
// *Err_Err
// *Err_StdError
// *Err_None
Wrapped isErr_Wrapped `protobuf_oneof:"wrapped"`
}
func (x *Err) Reset() {
*x = Err{}
if protoimpl.UnsafeEnabled {
mi := &file_errors_v1_errors_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Err) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Err) ProtoMessage() {}
func (x *Err) ProtoReflect() protoreflect.Message {
mi := &file_errors_v1_errors_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Err.ProtoReflect.Descriptor instead.
func (*Err) Descriptor() ([]byte, []int) {
return file_errors_v1_errors_proto_rawDescGZIP(), []int{0}
}
func (x *Err) GetCode() uint32 {
if x != nil {
return x.Code
}
return 0
}
func (x *Err) GetMsg() string {
if x != nil {
return x.Msg
}
return ""
}
func (x *Err) GetOp() string {
if x != nil {
return x.Op
}
return ""
}
func (m *Err) GetWrapped() isErr_Wrapped {
if m != nil {
return m.Wrapped
}
return nil
}
func (x *Err) GetErr() *Err {
if x, ok := x.GetWrapped().(*Err_Err); ok {
return x.Err
}
return nil
}
func (x *Err) GetStdError() string {
if x, ok := x.GetWrapped().(*Err_StdError); ok {
return x.StdError
}
return ""
}
func (x *Err) GetNone() bool {
if x, ok := x.GetWrapped().(*Err_None); ok {
return x.None
}
return false
}
type isErr_Wrapped interface {
isErr_Wrapped()
}
type Err_Err struct {
// err is a wrapped Err (aka a domain error)
Err *Err `protobuf:"bytes,40,opt,name=err,proto3,oneof"`
}
type Err_StdError struct {
// std_error is a wrapped std error
StdError string `protobuf:"bytes,50,opt,name=std_error,json=stdError,proto3,oneof"`
}
type Err_None struct {
// no error or err is wrapped
None bool `protobuf:"varint,60,opt,name=none,proto3,oneof"`
}
func (*Err_Err) isErr_Wrapped() {}
func (*Err_StdError) isErr_Wrapped() {}
func (*Err_None) isErr_Wrapped() {}
// ApiError is a protobuf representation of a controller ApiError
type ApiError struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// api_error is the controller ApiError
ApiError *api.Error `protobuf:"bytes,10,opt,name=api_error,json=apiError,proto3" json:"api_error,omitempty"`
// status is the status code assocatiated with the api error
Status int32 `protobuf:"varint,20,opt,name=status,proto3" json:"status,omitempty"`
}
func (x *ApiError) Reset() {
*x = ApiError{}
if protoimpl.UnsafeEnabled {
mi := &file_errors_v1_errors_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ApiError) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ApiError) ProtoMessage() {}
func (x *ApiError) ProtoReflect() protoreflect.Message {
mi := &file_errors_v1_errors_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ApiError.ProtoReflect.Descriptor instead.
func (*ApiError) Descriptor() ([]byte, []int) {
return file_errors_v1_errors_proto_rawDescGZIP(), []int{1}
}
func (x *ApiError) GetApiError() *api.Error {
if x != nil {
return x.ApiError
}
return nil
}
func (x *ApiError) GetStatus() int32 {
if x != nil {
return x.Status
}
return 0
}
var File_errors_v1_errors_proto protoreflect.FileDescriptor
var file_errors_v1_errors_proto_rawDesc = []byte{
0x0a, 0x16, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73,
0x2e, 0x76, 0x31, 0x1a, 0x1d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0x9f, 0x01, 0x0a, 0x03, 0x45, 0x72, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10,
0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67,
0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x70, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x70,
0x12, 0x22, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x72, 0x72, 0x48, 0x00, 0x52,
0x03, 0x65, 0x72, 0x72, 0x12, 0x1d, 0x0a, 0x09, 0x73, 0x74, 0x64, 0x5f, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x18, 0x32, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x73, 0x74, 0x64, 0x45, 0x72,
0x72, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x6e, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28,
0x08, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x6e, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x77, 0x72, 0x61,
0x70, 0x70, 0x65, 0x64, 0x22, 0x59, 0x0a, 0x08, 0x41, 0x70, 0x69, 0x45, 0x72, 0x72, 0x6f, 0x72,
0x12, 0x35, 0x0a, 0x09, 0x61, 0x70, 0x69, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0a, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x08, 0x61,
0x70, 0x69, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42,
0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79,
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x73, 0x3b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var (
file_errors_v1_errors_proto_rawDescOnce sync.Once
file_errors_v1_errors_proto_rawDescData = file_errors_v1_errors_proto_rawDesc
)
func file_errors_v1_errors_proto_rawDescGZIP() []byte {
file_errors_v1_errors_proto_rawDescOnce.Do(func() {
file_errors_v1_errors_proto_rawDescData = protoimpl.X.CompressGZIP(file_errors_v1_errors_proto_rawDescData)
})
return file_errors_v1_errors_proto_rawDescData
}
var file_errors_v1_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_errors_v1_errors_proto_goTypes = []interface{}{
(*Err)(nil), // 0: errors.v1.Err
(*ApiError)(nil), // 1: errors.v1.ApiError
(*api.Error)(nil), // 2: controller.api.v1.Error
}
var file_errors_v1_errors_proto_depIdxs = []int32{
0, // 0: errors.v1.Err.err:type_name -> errors.v1.Err
2, // 1: errors.v1.ApiError.api_error:type_name -> controller.api.v1.Error
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_errors_v1_errors_proto_init() }
func file_errors_v1_errors_proto_init() {
if File_errors_v1_errors_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_errors_v1_errors_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Err); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_errors_v1_errors_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ApiError); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_errors_v1_errors_proto_msgTypes[0].OneofWrappers = []interface{}{
(*Err_Err)(nil),
(*Err_StdError)(nil),
(*Err_None)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_errors_v1_errors_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_errors_v1_errors_proto_goTypes,
DependencyIndexes: file_errors_v1_errors_proto_depIdxs,
MessageInfos: file_errors_v1_errors_proto_msgTypes,
}.Build()
File_errors_v1_errors_proto = out.File
file_errors_v1_errors_proto_rawDesc = nil
file_errors_v1_errors_proto_goTypes = nil
file_errors_v1_errors_proto_depIdxs = nil
}
@@ -0,0 +1,222 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.17.3
// source: testing/interceptor/v1/greeter.proto
package interceptor
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// The request message containing the user's name.
type SayHelloRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
}
func (x *SayHelloRequest) Reset() {
*x = SayHelloRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_testing_interceptor_v1_greeter_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SayHelloRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SayHelloRequest) ProtoMessage() {}
func (x *SayHelloRequest) ProtoReflect() protoreflect.Message {
mi := &file_testing_interceptor_v1_greeter_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SayHelloRequest.ProtoReflect.Descriptor instead.
func (*SayHelloRequest) Descriptor() ([]byte, []int) {
return file_testing_interceptor_v1_greeter_proto_rawDescGZIP(), []int{0}
}
func (x *SayHelloRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
// The response message containing the greetings
type SayHelloResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *SayHelloResponse) Reset() {
*x = SayHelloResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_testing_interceptor_v1_greeter_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SayHelloResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SayHelloResponse) ProtoMessage() {}
func (x *SayHelloResponse) ProtoReflect() protoreflect.Message {
mi := &file_testing_interceptor_v1_greeter_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SayHelloResponse.ProtoReflect.Descriptor instead.
func (*SayHelloResponse) Descriptor() ([]byte, []int) {
return file_testing_interceptor_v1_greeter_proto_rawDescGZIP(), []int{1}
}
func (x *SayHelloResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
var File_testing_interceptor_v1_greeter_proto protoreflect.FileDescriptor
var file_testing_interceptor_v1_greeter_proto_rawDesc = []byte{
0x0a, 0x24, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63,
0x65, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x22, 0x25,
0x0a, 0x0f, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2c, 0x0a, 0x10, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c,
0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x32, 0x71, 0x0a, 0x0e, 0x47, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c,
0x6f, 0x12, 0x27, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x61, 0x79, 0x48, 0x65,
0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x74, 0x65, 0x73,
0x74, 0x69, 0x6e, 0x67, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x3b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65,
0x70, 0x74, 0x6f, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_testing_interceptor_v1_greeter_proto_rawDescOnce sync.Once
file_testing_interceptor_v1_greeter_proto_rawDescData = file_testing_interceptor_v1_greeter_proto_rawDesc
)
func file_testing_interceptor_v1_greeter_proto_rawDescGZIP() []byte {
file_testing_interceptor_v1_greeter_proto_rawDescOnce.Do(func() {
file_testing_interceptor_v1_greeter_proto_rawDescData = protoimpl.X.CompressGZIP(file_testing_interceptor_v1_greeter_proto_rawDescData)
})
return file_testing_interceptor_v1_greeter_proto_rawDescData
}
var file_testing_interceptor_v1_greeter_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_testing_interceptor_v1_greeter_proto_goTypes = []interface{}{
(*SayHelloRequest)(nil), // 0: testing.interceptor.v1.SayHelloRequest
(*SayHelloResponse)(nil), // 1: testing.interceptor.v1.SayHelloResponse
}
var file_testing_interceptor_v1_greeter_proto_depIdxs = []int32{
0, // 0: testing.interceptor.v1.GreeterService.SayHello:input_type -> testing.interceptor.v1.SayHelloRequest
1, // 1: testing.interceptor.v1.GreeterService.SayHello:output_type -> testing.interceptor.v1.SayHelloResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_testing_interceptor_v1_greeter_proto_init() }
func file_testing_interceptor_v1_greeter_proto_init() {
if File_testing_interceptor_v1_greeter_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_testing_interceptor_v1_greeter_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SayHelloRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_testing_interceptor_v1_greeter_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SayHelloResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_testing_interceptor_v1_greeter_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_testing_interceptor_v1_greeter_proto_goTypes,
DependencyIndexes: file_testing_interceptor_v1_greeter_proto_depIdxs,
MessageInfos: file_testing_interceptor_v1_greeter_proto_msgTypes,
}.Build()
File_testing_interceptor_v1_greeter_proto = out.File
file_testing_interceptor_v1_greeter_proto_rawDesc = nil
file_testing_interceptor_v1_greeter_proto_goTypes = nil
file_testing_interceptor_v1_greeter_proto_depIdxs = nil
}
@@ -0,0 +1,103 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package interceptor
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// GreeterServiceClient is the client API for GreeterService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type GreeterServiceClient interface {
// Sends a greeting
SayHello(ctx context.Context, in *SayHelloRequest, opts ...grpc.CallOption) (*SayHelloResponse, error)
}
type greeterServiceClient struct {
cc grpc.ClientConnInterface
}
func NewGreeterServiceClient(cc grpc.ClientConnInterface) GreeterServiceClient {
return &greeterServiceClient{cc}
}
func (c *greeterServiceClient) SayHello(ctx context.Context, in *SayHelloRequest, opts ...grpc.CallOption) (*SayHelloResponse, error) {
out := new(SayHelloResponse)
err := c.cc.Invoke(ctx, "/testing.interceptor.v1.GreeterService/SayHello", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// GreeterServiceServer is the server API for GreeterService service.
// All implementations must embed UnimplementedGreeterServiceServer
// for forward compatibility
type GreeterServiceServer interface {
// Sends a greeting
SayHello(context.Context, *SayHelloRequest) (*SayHelloResponse, error)
mustEmbedUnimplementedGreeterServiceServer()
}
// UnimplementedGreeterServiceServer must be embedded to have forward compatible implementations.
type UnimplementedGreeterServiceServer struct {
}
func (UnimplementedGreeterServiceServer) SayHello(context.Context, *SayHelloRequest) (*SayHelloResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
}
func (UnimplementedGreeterServiceServer) mustEmbedUnimplementedGreeterServiceServer() {}
// UnsafeGreeterServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to GreeterServiceServer will
// result in compilation errors.
type UnsafeGreeterServiceServer interface {
mustEmbedUnimplementedGreeterServiceServer()
}
func RegisterGreeterServiceServer(s grpc.ServiceRegistrar, srv GreeterServiceServer) {
s.RegisterService(&GreeterService_ServiceDesc, srv)
}
func _GreeterService_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SayHelloRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GreeterServiceServer).SayHello(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/testing.interceptor.v1.GreeterService/SayHello",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GreeterServiceServer).SayHello(ctx, req.(*SayHelloRequest))
}
return interceptor(ctx, in, info, handler)
}
// GreeterService_ServiceDesc is the grpc.ServiceDesc for GreeterService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var GreeterService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "testing.interceptor.v1.GreeterService",
HandlerType: (*GreeterServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "SayHello",
Handler: _GreeterService_SayHello_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "testing/interceptor/v1/greeter.proto",
}
@@ -112,13 +112,13 @@ message Target {
// The type of the Target.
string type = 90;
// The IDs of the Host Sets associated with this Target.
// Output only. The IDs of the Host Sets associated with this Target.
repeated string host_set_ids = 100 [json_name="host_set_ids"];
// Output only. The Host Sets associated with this Target.
repeated HostSet host_sets = 110 [json_name="host_sets"];
// The IDs of the Host Sources associated with this Target.
// Output only. The IDs of the Host Sources associated with this Target.
repeated string host_source_ids = 420 [json_name="host_source_ids"];
// Output only. The Host Sources associated with this Target.
@@ -133,12 +133,12 @@ message Target {
// Optional boolean expression to filter the workers that are allowed to satisfy this request.
google.protobuf.StringValue worker_filter = 140 [json_name="worker_filter", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this: "worker_filter" that: "WorkerFilter"}];
// The IDs of the application credential library ids associated with this Target. Deprecated: use application_credential_source_ids instead.
// Output only. The IDs of the application credential library ids associated with this Target. Deprecated: use application_credential_source_ids instead.
repeated string application_credential_library_ids = 150 [json_name="application_credential_library_ids", deprecated = true];
// Output only. The application credential libraries associated with this Target. Deprecated: use application_credential_sources instead.
repeated CredentialLibrary application_credential_libraries = 180 [json_name="application_credential_libraries", deprecated = true];
// The IDs of the application credential source ids associated with this Target.
// Output only. The IDs of the application credential source ids associated with this Target.
repeated string application_credential_source_ids = 400 [json_name="application_credential_source_ids"];
// Output only. The application credential sources associated with this Target.
repeated CredentialSource application_credential_sources = 410 [json_name="application_credential_sources"];
@@ -238,4 +238,4 @@ message SessionAuthorization {
// Output only. The credentials for this session.
repeated SessionCredential credentials = 110 [json_name="credentials"];
}
}
@@ -0,0 +1,8 @@
syntax = "proto3";
package controller.api.v1;
option go_package = "github.com/hashicorp/boundary/internal/gen/controller/api;api";
// EmptyResponse represents an empty response
message EmptyResponse {}
@@ -0,0 +1,42 @@
syntax = "proto3";
package controller.auth.v1;
option go_package = "github.com/hashicorp/boundary/internal/gen/controller/auth;auth";
// RequestInfo contains request parameters necessary for checking authn/authz
message RequestInfo {
// path of the request
string path = 10;
// method (http verb) of the request
string method = 20;
// public_id for the request
string public_id = 30;
// encrypted_token from the request
string encrypted_token = 40;
// token from the request
string token = 50;
// token_format of the request's token
uint32 token_format = 60;
// scope_id_override for the request (helpful for tests)
string scope_id_override = 70;
// user_id_override for the request (helpful for tests)
string user_id_override = 80;
// disable_authz_failures for the request (helpful for tests)
bool disable_authz_failures = 90;
// disable_auth_entirely for the request (helpful for tests)
bool disable_auth_entirely = 100;
// ticket is a unique id that allows the grpc-gateway to verify that the info
// came from its companion http proxy
string ticket = 110;
}
@@ -17,6 +17,7 @@ message Server {
// private ID and name to be identical, and there is currently no reason we
// can think of to allow a given server's name to match another within the
// same cluster. So we simply use the private ID and deprecate this.
// @inject_tag: `gorm:"-"`
string name = 30 [deprecated = true];
// Description of the resource
@@ -73,70 +73,6 @@ message TargetHostSet {
timestamp.v1.Timestamp create_time = 30;
}
message TcpTarget {
// public_id is used to access the TargetTcp via an API
// @inject_tag: gorm:"primary_key"
string public_id = 10;
// scope id for the TargetTcp
// @inject_tag: `gorm:"default:null"`
string scope_id = 20;
// name is the optional friendly name used to
// access the TargetTcp via an API
// @inject_tag: `gorm:"default:null"`
string name = 30
[(custom_options.v1.mask_mapping) = { this: "name" that: "name" }];
// description of the TargetTcp
// @inject_tag: `gorm:"default:null"`
string description = 40 [(custom_options.v1.mask_mapping) = {
this: "description"
that: "description"
}];
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp create_time = 50;
// update_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp update_time = 60;
// version allows optimistic locking of the TargetTcp when modifying the
// TargetTcp
// @inject_tag: `gorm:"default:null"`
uint32 version = 70;
// default port of the TargetTcp
// @inject_tag: `gorm:"default:null"`
uint32 default_port = 80 [(custom_options.v1.mask_mapping) = {
this: "DefaultPort"
that: "attributes.default_port"
}];
// Maximum total lifetime of a created session, in seconds
// @inject_tag: `gorm:"default:null"`
uint32 session_max_seconds = 100 [(custom_options.v1.mask_mapping) = {
this: "SessionMaxSeconds"
that: "session_max_seconds"
}];
// Maximum number of connections in a session
// @inject_tag: `gorm:"default:null"`
int32 session_connection_limit = 110 [(custom_options.v1.mask_mapping) = {
this: "SessionConnectionLimit"
that: "session_connection_limit"
}];
// A boolean expression that allows filtering the workers that can handle a session
// @inject_tag: `gorm:"default:null"`
string worker_filter = 120 [(custom_options.v1.mask_mapping) = {
this: "WorkerFilter"
that: "worker_filter"
}];
}
message CredentialLibrary {
// target_id of the Target
// @inject_tag: gorm:"primary_key"
@@ -0,0 +1,72 @@
syntax = "proto3";
package controller.storage.target.tcp.store.v1;
option go_package = "github.com/hashicorp/boundary/internal/target/tcp/store;store";
import "controller/storage/timestamp/v1/timestamp.proto";
import "controller/custom_options/v1/options.proto";
message Target {
// public_id is used to access the tcp.Target via an API
// @inject_tag: gorm:"primary_key"
string public_id = 10;
// scope id for the tcp.Target
// @inject_tag: `gorm:"default:null"`
string scope_id = 20;
// name is the optional friendly name used to
// access the tcp.Target via an API
// @inject_tag: `gorm:"default:null"`
string name = 30
[(custom_options.v1.mask_mapping) = { this: "name" that: "name" }];
// description of the tcp.Target
// @inject_tag: `gorm:"default:null"`
string description = 40 [(custom_options.v1.mask_mapping) = {
this: "description"
that: "description"
}];
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp create_time = 50;
// update_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp update_time = 60;
// version allows optimistic locking of the tcp.Target when modifying the
// tcp.Target
// @inject_tag: `gorm:"default:null"`
uint32 version = 70;
// default port of the tcp.Target
// @inject_tag: `gorm:"default:null"`
uint32 default_port = 80 [(custom_options.v1.mask_mapping) = {
this: "DefaultPort"
that: "attributes.default_port"
}];
// Maximum total lifetime of a created session, in seconds
// @inject_tag: `gorm:"default:null"`
uint32 session_max_seconds = 100 [(custom_options.v1.mask_mapping) = {
this: "SessionMaxSeconds"
that: "session_max_seconds"
}];
// Maximum number of connections in a session
// @inject_tag: `gorm:"default:null"`
int32 session_connection_limit = 110 [(custom_options.v1.mask_mapping) = {
this: "SessionConnectionLimit"
that: "session_connection_limit"
}];
// A boolean expression that allows filtering the workers that can handle a session
// @inject_tag: `gorm:"default:null"`
string worker_filter = 120 [(custom_options.v1.mask_mapping) = {
this: "WorkerFilter"
that: "worker_filter"
}];
}
@@ -0,0 +1,41 @@
syntax = "proto3";
package errors.v1;
option go_package = "github.com/hashicorp/boundary/internal/gen/errors;errors";
import "controller/api/v1/error.proto";
// Err is a protobuf representation of a domain error
message Err {
// code is the error's code, which can be used to get the error's
// errorCodeInfo, which contains the error's Kind and Message
uint32 code = 10;
// msg for the error
string msg = 20;
// op represents the operation raising/propagating an error and is optional.
string op = 30;
// wrapped represents an optionally wrapped error
oneof wrapped {
// err is a wrapped Err (aka a domain error)
Err err = 40;
// std_error is a wrapped std error
string std_error = 50;
// no error or err is wrapped
bool none = 60;
}
}
// ApiError is a protobuf representation of a controller ApiError
message ApiError {
// api_error is the controller ApiError
controller.api.v1.Error api_error = 10;
// status is the status code assocatiated with the api error
int32 status = 20;
}
@@ -0,0 +1,22 @@
syntax = "proto3";
package testing.interceptor.v1;
option go_package = "github.com/hashicorp/boundary/internal/gen/testing/interceptor;interceptor";
// The greeting service definition. This is just a dead simple service that can
// be used to test interceptors. (See controller.startTestGreeterService)
service GreeterService {
// Sends a greeting
rpc SayHello(SayHelloRequest) returns (SayHelloResponse) {}
}
// The request message containing the user's name.
message SayHelloRequest {
string name = 1;
}
// The response message containing the greetings
message SayHelloResponse {
string message = 1;
}
+39 -53
View File
@@ -11,7 +11,9 @@ import (
"github.com/hashicorp/boundary/api/recovery"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/errors"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/gen/controller/tokens"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/observability/event"
"github.com/hashicorp/boundary/internal/perms"
@@ -27,7 +29,7 @@ import (
"google.golang.org/protobuf/proto"
)
type TokenFormat int
type TokenFormat uint32
const (
// We weren't given one or couldn't parse it
@@ -51,22 +53,6 @@ type key int
var verifierKey key
// RequestInfo contains request parameters necessary for checking authn/authz
type RequestInfo struct {
Path string
Method string
PublicId string
EncryptedToken string
Token string
TokenFormat TokenFormat
// The following are useful for tests
scopeIdOverride string
userIdOverride string
DisableAuthzFailures bool
DisableAuthEntirely bool
}
type VerifyResults struct {
UserId string
AuthTokenId string
@@ -108,7 +94,7 @@ type verifier struct {
authTokenRepoFn common.AuthTokenRepoFactory
serversRepoFn common.ServersRepoFactory
kms *kms.Kms
requestInfo RequestInfo
requestInfo *authpb.RequestInfo
res *perms.Resource
act action.Type
ctx context.Context
@@ -124,7 +110,7 @@ func NewVerifierContext(ctx context.Context,
authTokenRepoFn common.AuthTokenRepoFactory,
serversRepoFn common.ServersRepoFactory,
kms *kms.Kms,
requestInfo RequestInfo) context.Context {
requestInfo *authpb.RequestInfo) context.Context {
return context.WithValue(ctx, verifierKey, &verifier{
iamRepoFn: iamRepoFn,
authTokenRepoFn: authTokenRepoFn,
@@ -174,7 +160,7 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) {
// without fuss
if v.requestInfo.DisableAuthEntirely {
const op = "auth.(disabled).lookupScope"
ret.Scope.Id = v.requestInfo.scopeIdOverride
ret.Scope.Id = v.requestInfo.ScopeIdOverride
if ret.Scope.Id == "" {
ret.Scope.Id = opts.withScopeId
}
@@ -214,7 +200,7 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) {
ParentScopeId: scp.GetParentId(),
}
}
ret.UserId = v.requestInfo.userIdOverride
ret.UserId = v.requestInfo.UserIdOverride
if reqInfo != nil {
reqInfo.UserId = ret.UserId
}
@@ -291,40 +277,40 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) {
func (v *verifier) decryptToken(ctx context.Context) {
const op = "auth.(verifier).decryptToken"
switch v.requestInfo.TokenFormat {
case AuthTokenTypeUnknown:
case uint32(AuthTokenTypeUnknown):
// Nothing to decrypt
return
case AuthTokenTypeBearer, AuthTokenTypeSplitCookie:
case uint32(AuthTokenTypeBearer), uint32(AuthTokenTypeSplitCookie):
if v.kms == nil {
event.WriteError(ctx, op, stderrors.New("no KMS object available to authz system"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
tokenRepo, err := v.authTokenRepoFn()
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to get authtoken repo"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
at, err := tokenRepo.LookupAuthToken(v.ctx, v.requestInfo.PublicId)
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to look up auth token by public ID"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
if at == nil {
event.WriteError(ctx, op, stderrors.New("nil result from looking up auth token by public ID"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
tokenWrapper, err := v.kms.GetWrapper(v.ctx, at.GetScopeId(), kms.KeyPurposeTokens)
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("unable to get wrapper for tokens; continuing as anonymous user"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
@@ -333,62 +319,62 @@ func (v *verifier) decryptToken(ctx context.Context) {
case globals.ServiceTokenV1:
default:
event.WriteError(ctx, op, stderrors.New("unknown token encryption version; continuing as anonymous user"), event.WithInfo("version", version))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
marshaledToken, err := base58.FastBase58Decoding(v.requestInfo.EncryptedToken[len(globals.ServiceTokenV1):])
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("error unmarshaling base58 token; continuing as anonymous user"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
blobInfo := new(wrapping.EncryptedBlobInfo)
if err := proto.Unmarshal(marshaledToken, blobInfo); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("error decoding encrypted token; continuing as anonymous user"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
s1Bytes, err := tokenWrapper.Decrypt(v.ctx, blobInfo, []byte(v.requestInfo.PublicId))
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("error decrypting encrypted token; continuing as anonymous user"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
var s1Info tokens.S1TokenInfo
if err := proto.Unmarshal(s1Bytes, &s1Info); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("error unmarshaling token info; continuing as anonymous user"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
if v.requestInfo.TokenFormat == AuthTokenTypeUnknown || s1Info.Token == "" || v.requestInfo.PublicId == "" {
if v.requestInfo.TokenFormat == uint32(AuthTokenTypeUnknown) || s1Info.Token == "" || v.requestInfo.PublicId == "" {
event.WriteError(ctx, op, stderrors.New("after parsing, could not find valid token; continuing as anonymous user"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
v.requestInfo.Token = s1Info.Token
return
case AuthTokenTypeRecoveryKms:
case uint32(AuthTokenTypeRecoveryKms):
if v.kms == nil {
event.WriteError(ctx, op, stderrors.New("no KMS object available to authz system"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
wrapper := v.kms.GetExternalWrappers().Recovery()
if wrapper == nil {
event.WriteError(ctx, op, stderrors.New("no recovery KMS is available"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
info, err := recovery.ParseRecoveryToken(v.ctx, wrapper, v.requestInfo.EncryptedToken)
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("decrypt recovery token: error parsing and validating recovery token"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
// If we add the validity period to the creation time (which we've
@@ -396,18 +382,18 @@ func (v *verifier) decryptToken(ctx context.Context) {
// it's before now, it's expired and might be a replay.
if info.CreationTime.Add(globals.RecoveryTokenValidityPeriod).Before(time.Now()) {
event.WriteError(ctx, op, stderrors.New("recovery token has expired (possible replay attack)"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
repo, err := v.serversRepoFn()
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("decrypt recovery token: error fetching servers repo"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
if err := repo.AddRecoveryNonce(v.ctx, info.Nonce); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("decrypt recovery token: error adding nonce to database (possible replay attack)"))
v.requestInfo.TokenFormat = AuthTokenTypeUnknown
v.requestInfo.TokenFormat = uint32(AuthTokenTypeUnknown)
return
}
event.WriteError(ctx, op, stderrors.New("recovery KMS was used to authorize a call"), event.WithInfo("url", v.requestInfo.Path, "method", v.requestInfo.Method))
@@ -426,15 +412,15 @@ func (v verifier) performAuthCheck(ctx context.Context) (aclResults perms.ACLRes
// Validate the token and fetch the corresponding user ID
switch v.requestInfo.TokenFormat {
case AuthTokenTypeUnknown:
case uint32(AuthTokenTypeUnknown):
// Nothing; remain as the anonymous user
case AuthTokenTypeRecoveryKms:
case uint32(AuthTokenTypeRecoveryKms):
// We validated the encrypted token in decryptToken and handled the
// nonces there, so just set the user
userId = "u_recovery"
case AuthTokenTypeBearer, AuthTokenTypeSplitCookie:
case uint32(AuthTokenTypeBearer), uint32(AuthTokenTypeSplitCookie):
if v.requestInfo.Token == "" {
// This will end up staying as the anonymous user
break
@@ -500,7 +486,7 @@ func (v verifier) performAuthCheck(ctx context.Context) (aclResults perms.ACLRes
}
// At this point we don't need to look up grants since it's automatically allowed
if v.requestInfo.TokenFormat == AuthTokenTypeRecoveryKms {
if v.requestInfo.TokenFormat == uint32(AuthTokenTypeRecoveryKms) {
aclResults.AuthenticationFinished = true
aclResults.Authorized = true
retErr = nil
@@ -561,7 +547,7 @@ func (r *VerifyResults) FetchActionSetForType(ctx context.Context, typ resource.
func (r *VerifyResults) fetchActions(id string, typ resource.Type, availableActions action.ActionSet, opt ...Option) action.ActionSet {
switch {
case r.v.requestInfo.DisableAuthEntirely,
r.v.requestInfo.TokenFormat == AuthTokenTypeRecoveryKms:
r.v.requestInfo.TokenFormat == uint32(AuthTokenTypeRecoveryKms):
// TODO: See if we can be better about what we return with the anonymous
// user and recovery KMS, perhaps given exclusionary options for each
return availableActions
@@ -598,7 +584,7 @@ func (r *VerifyResults) fetchActions(id string, typ resource.Type, availableActi
func (r *VerifyResults) FetchOutputFields(res perms.Resource, act action.Type) perms.OutputFieldsMap {
switch {
case r.v.requestInfo.TokenFormat == AuthTokenTypeRecoveryKms:
case r.v.requestInfo.TokenFormat == uint32(AuthTokenTypeRecoveryKms):
return perms.OutputFieldsMap{"*": true}
case r.v.requestInfo.DisableAuthEntirely:
return nil
@@ -611,7 +597,7 @@ func (r *VerifyResults) FetchOutputFields(res perms.Resource, act action.Type) p
// split cookies and parses it. If it cannot be parsed successfully, the issue
// is logged and we return blank, so logic will continue as the anonymous user.
// The public ID and _encrypted_ token are returned along with the token format.
func GetTokenFromRequest(ctx context.Context, kmsCache *kms.Kms, req *http.Request) (string, string, TokenFormat) {
func GetTokenFromRequest(ctx context.Context, kmsCache *kms.Kms, req *http.Request) (string, string, uint32) {
const op = "auth.GetTokenFromRequest"
// First, get the token, either from the authorization header or from split
// cookies
@@ -643,21 +629,21 @@ func GetTokenFromRequest(ctx context.Context, kmsCache *kms.Kms, req *http.Reque
// We didn't find auth info or a client screwed up and put in a blank
// header instead of nothing at all, so return blank which will indicate
// the anonymouse user
return "", "", AuthTokenTypeUnknown
return "", "", uint32(AuthTokenTypeUnknown)
}
if strings.HasPrefix(fullToken, "r_") {
return "", fullToken, AuthTokenTypeRecoveryKms
return "", fullToken, uint32(AuthTokenTypeRecoveryKms)
}
splitFullToken := strings.Split(fullToken, "_")
if len(splitFullToken) != 3 {
event.WriteError(ctx, op, stderrors.New("unexpected number of segments in token; continuing as anonymous user"), event.WithInfo("expected", 3, "found", len(splitFullToken)))
return "", "", AuthTokenTypeUnknown
return "", "", uint32(AuthTokenTypeUnknown)
}
publicId := strings.Join(splitFullToken[0:2], "_")
encryptedToken := splitFullToken[2]
return publicId, encryptedToken, receivedTokenType
return publicId, encryptedToken, uint32(receivedTokenType)
}
@@ -9,6 +9,7 @@ import (
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/db"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/servers"
@@ -107,17 +108,17 @@ func TestAuthTokenAuthenticator(t *testing.T) {
}
// Add values for authn/authz checking
requestInfo := RequestInfo{
requestInfo := authpb.RequestInfo{
Path: req.URL.Path,
Method: req.Method,
}
requestInfo.PublicId, requestInfo.EncryptedToken, requestInfo.TokenFormat = GetTokenFromRequest(context.TODO(), kms, req)
assert.Equal(t, tc.tokenFormat, requestInfo.TokenFormat)
assert.Equal(t, uint32(tc.tokenFormat), requestInfo.TokenFormat)
if tc.userId == "" {
return
}
ctx := NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, requestInfo)
ctx := NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, &requestInfo)
v, ok := ctx.Value(verifierKey).(*verifier)
require.True(t, ok)
+9 -8
View File
@@ -3,6 +3,7 @@ package auth
import (
"context"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/requests"
"github.com/hashicorp/boundary/internal/servers/controller/common"
)
@@ -11,16 +12,16 @@ import (
// auth checking entirely disabled. Supported options: WithScopeId an WithUserId
// are used directly; WithKms is passed through into the verifier context.
func DisabledAuthTestContext(iamRepoFn common.IamRepoFactory, scopeId string, opt ...Option) context.Context {
reqInfo := RequestInfo{DisableAuthEntirely: true}
reqInfo := authpb.RequestInfo{DisableAuthEntirely: true}
opts := getOpts(opt...)
reqInfo.scopeIdOverride = opts.withScopeId
if reqInfo.scopeIdOverride == "" {
reqInfo.scopeIdOverride = scopeId
reqInfo.ScopeIdOverride = opts.withScopeId
if reqInfo.ScopeIdOverride == "" {
reqInfo.ScopeIdOverride = scopeId
}
reqInfo.userIdOverride = opts.withUserId
if reqInfo.userIdOverride == "" {
reqInfo.userIdOverride = "u_auth"
reqInfo.UserIdOverride = opts.withUserId
if reqInfo.UserIdOverride == "" {
reqInfo.UserIdOverride = "u_auth"
}
requestContext := context.WithValue(context.Background(), requests.ContextRequestInformationKey, &requests.RequestContext{})
return NewVerifierContext(requestContext, iamRepoFn, nil, nil, opts.withKms, reqInfo)
return NewVerifierContext(requestContext, iamRepoFn, nil, nil, opts.withKms, &reqInfo)
}
@@ -7,6 +7,7 @@ import (
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/db"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/servers"
@@ -229,9 +230,9 @@ func TestListingScopeIds(t *testing.T) {
authTokenRepoFn,
serversRepoFn,
kms,
auth.RequestInfo{
&authpb.RequestInfo{
Token: at.GetToken(),
TokenFormat: auth.AuthTokenTypeBearer,
TokenFormat: uint32(auth.AuthTokenTypeBearer),
PublicId: at.GetPublicId(),
})
+10 -1
View File
@@ -6,6 +6,8 @@ import (
"fmt"
"sync"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/authtoken"
@@ -32,6 +34,7 @@ import (
"github.com/hashicorp/go-secure-stdlib/mlock"
"github.com/patrickmn/go-cache"
ua "go.uber.org/atomic"
"google.golang.org/grpc"
)
type Controller struct {
@@ -50,6 +53,12 @@ type Controller struct {
// Used for testing and tracking worker health
workerStatusUpdateTimes *sync.Map
// grpc gateway server
gatewayServer *grpc.Server
gatewayTicket string
gatewayListener gatewayListener
gatewayMux *runtime.ServeMux
// Repo factory methods
AuthTokenRepoFn common.AuthTokenRepoFactory
VaultCredentialRepoFn common.VaultCredentialRepoFactory
@@ -218,7 +227,7 @@ func (c *Controller) Start() error {
if err := c.scheduler.Start(c.baseContext, &c.schedulerWg); err != nil {
return fmt.Errorf("error starting scheduler: %w", err)
}
if err := c.startListeners(); err != nil {
if err := c.startListeners(c.baseContext); err != nil {
return fmt.Errorf("error starting controller listeners: %w", err)
}
+67
View File
@@ -0,0 +1,67 @@
package controller
import (
"context"
"math"
"net"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/servers/controller/common"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"google.golang.org/grpc"
"google.golang.org/grpc/test/bufconn"
)
// newGatewayListener will create an in-memory listener
func newGatewayListener() (gatewayListener, string) {
buffer := globals.DefaultMaxRequestSize // seems like a reasonable size for the ring buffer, but then happily change the size if more info becomes available
return bufconn.Listen(int(buffer)), ""
}
const gatewayTarget = ""
type gatewayListener interface {
net.Listener
Dial() (net.Conn, error)
}
func gatewayDialOptions(lis gatewayListener) []grpc.DialOption {
return []grpc.DialOption{
grpc.WithInsecure(),
grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}),
}
}
func newGatewayMux() *runtime.ServeMux {
return runtime.NewServeMux(
runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{
Marshaler: handlers.JSONMarshaler(),
}),
runtime.WithErrorHandler(handlers.ErrorHandler()),
runtime.WithForwardResponseOption(handlers.OutgoingResponseFilter),
)
}
func newGatewayServer(ctx context.Context, iamRepoFn common.IamRepoFactory, authTokenRepoFn common.AuthTokenRepoFactory, serversRepoFn common.ServersRepoFactory, kms *kms.Kms) (*grpc.Server, string, error) {
const op = "controller.newGatewayServer"
ticket, err := db.NewPrivateId("gwticket")
if err != nil {
return nil, "", errors.Wrap(ctx, err, op, errors.WithMsg("unable to generate gateway ticket"))
}
requestCtxInterceptor, err := requestCtxInterceptor(ctx, iamRepoFn, authTokenRepoFn, serversRepoFn, kms, ticket)
if err != nil {
return nil, "", err
}
return grpc.NewServer(
grpc.MaxRecvMsgSize(math.MaxInt32),
grpc.MaxSendMsgSize(math.MaxInt32),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(requestCtxInterceptor, errorInterceptor(ctx), statusCodeInterceptor(ctx))),
), ticket, nil
}
+170 -132
View File
@@ -13,35 +13,36 @@ import (
"strings"
"time"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/gen/controller/api/services"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/observability/event"
"github.com/hashicorp/boundary/internal/requests"
"github.com/hashicorp/boundary/internal/servers/common"
"github.com/hashicorp/boundary/internal/servers/controller/auth"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/accounts"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/authmethods"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/authtokens"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/credentiallibraries"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/credentialstores"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/groups"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/host_catalogs"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/host_sets"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/hosts"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/managed_groups"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/roles"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/scopes"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/sessions"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/targets"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/users"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/go-secure-stdlib/listenerutil"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/mr-tron/base58"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/proto"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/authtokens"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/groups"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/host_catalogs"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/hosts"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/roles"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/scopes"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/users"
)
type HandlerProperties struct {
@@ -78,129 +79,168 @@ func handleGrpcGateway(c *Controller, props HandlerProperties) (http.Handler, er
// Register*ServiceHandlerServer methods ignore the passed in ctx. Using it
// now however in case this changes in the future.
ctx := props.CancelCtx
mux := runtime.NewServeMux(
runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{
Marshaler: handlers.JSONMarshaler(),
}),
runtime.WithErrorHandler(handlers.ErrorHandler()),
runtime.WithForwardResponseOption(handlers.OutgoingInterceptor),
)
hcs, err := host_catalogs.NewService(c.StaticHostRepoFn, c.PluginHostRepoFn, c.HostPluginRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create host catalog handler service: %w", err)
currentServices := c.gatewayServer.GetServiceInfo()
dialOptions := gatewayDialOptions(c.gatewayListener)
if _, ok := currentServices[services.HostCatalogService_ServiceDesc.ServiceName]; !ok {
hcs, err := host_catalogs.NewService(c.StaticHostRepoFn, c.PluginHostRepoFn, c.HostPluginRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create host catalog handler service: %w", err)
}
services.RegisterHostCatalogServiceServer(c.gatewayServer, hcs)
if err := services.RegisterHostCatalogServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register host catalog service handler: %w", err)
}
}
if err := services.RegisterHostCatalogServiceHandlerServer(ctx, mux, hcs); err != nil {
return nil, fmt.Errorf("failed to register host catalog service handler: %w", err)
if _, ok := currentServices[services.HostSetService_ServiceDesc.ServiceName]; !ok {
hss, err := host_sets.NewService(c.StaticHostRepoFn, c.PluginHostRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create host set handler service: %w", err)
}
services.RegisterHostSetServiceServer(c.gatewayServer, hss)
if err := services.RegisterHostSetServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register host set service handler: %w", err)
}
}
hss, err := host_sets.NewService(c.StaticHostRepoFn, c.PluginHostRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create host set handler service: %w", err)
if _, ok := currentServices[services.HostService_ServiceDesc.ServiceName]; !ok {
hs, err := hosts.NewService(c.StaticHostRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create host handler service: %w", err)
}
services.RegisterHostServiceServer(c.gatewayServer, hs)
if err := services.RegisterHostServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register host service handler: %w", err)
}
}
if err := services.RegisterHostSetServiceHandlerServer(ctx, mux, hss); err != nil {
return nil, fmt.Errorf("failed to register host set service handler: %w", err)
if _, ok := currentServices[services.AccountService_ServiceDesc.ServiceName]; !ok {
accts, err := accounts.NewService(c.PasswordAuthRepoFn, c.OidcRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create account handler service: %w", err)
}
services.RegisterAccountServiceServer(c.gatewayServer, accts)
if err := services.RegisterAccountServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register account service handler: %w", err)
}
}
hs, err := hosts.NewService(c.StaticHostRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create host handler service: %w", err)
if _, ok := currentServices[services.AuthMethodService_ServiceDesc.ServiceName]; !ok {
authMethods, err := authmethods.NewService(c.kms, c.PasswordAuthRepoFn, c.OidcRepoFn, c.IamRepoFn, c.AuthTokenRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create auth method handler service: %w", err)
}
services.RegisterAuthMethodServiceServer(c.gatewayServer, authMethods)
if err := services.RegisterAuthMethodServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register auth method service handler: %w", err)
}
}
if err := services.RegisterHostServiceHandlerServer(ctx, mux, hs); err != nil {
return nil, fmt.Errorf("failed to register host service handler: %w", err)
if _, ok := currentServices[services.AuthTokenService_ServiceDesc.ServiceName]; !ok {
authtoks, err := authtokens.NewService(c.AuthTokenRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create auth token handler service: %w", err)
}
services.RegisterAuthTokenServiceServer(c.gatewayServer, authtoks)
if err := services.RegisterAuthTokenServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register auth token service handler: %w", err)
}
}
accts, err := accounts.NewService(c.PasswordAuthRepoFn, c.OidcRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create account handler service: %w", err)
if _, ok := currentServices[services.ScopeService_ServiceDesc.ServiceName]; !ok {
os, err := scopes.NewService(c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create scope handler service: %w", err)
}
services.RegisterScopeServiceServer(c.gatewayServer, os)
if err := services.RegisterScopeServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register scope service handler: %w", err)
}
}
if err := services.RegisterAccountServiceHandlerServer(ctx, mux, accts); err != nil {
return nil, fmt.Errorf("failed to register account service handler: %w", err)
if _, ok := currentServices[services.UserService_ServiceDesc.ServiceName]; !ok {
us, err := users.NewService(c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create user handler service: %w", err)
}
services.RegisterUserServiceServer(c.gatewayServer, us)
if err := services.RegisterUserServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register user service handler: %w", err)
}
}
authMethods, err := authmethods.NewService(c.kms, c.PasswordAuthRepoFn, c.OidcRepoFn, c.IamRepoFn, c.AuthTokenRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create auth method handler service: %w", err)
if _, ok := currentServices[services.TargetService_ServiceDesc.ServiceName]; !ok {
ts, err := targets.NewService(
c.kms,
c.TargetRepoFn,
c.IamRepoFn,
c.ServersRepoFn,
c.SessionRepoFn,
c.StaticHostRepoFn,
c.VaultCredentialRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create target handler service: %w", err)
}
services.RegisterTargetServiceServer(c.gatewayServer, ts)
if err := services.RegisterTargetServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register target service handler: %w", err)
}
}
if err := services.RegisterAuthMethodServiceHandlerServer(ctx, mux, authMethods); err != nil {
return nil, fmt.Errorf("failed to register auth method service handler: %w", err)
if _, ok := currentServices[services.GroupService_ServiceDesc.ServiceName]; !ok {
gs, err := groups.NewService(c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create group handler service: %w", err)
}
services.RegisterGroupServiceServer(c.gatewayServer, gs)
if err := services.RegisterGroupServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register group service handler: %w", err)
}
}
authtoks, err := authtokens.NewService(c.AuthTokenRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create auth token handler service: %w", err)
if _, ok := currentServices[services.RoleService_ServiceDesc.ServiceName]; !ok {
rs, err := roles.NewService(c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create role handler service: %w", err)
}
services.RegisterRoleServiceServer(c.gatewayServer, rs)
if err := services.RegisterRoleServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register role service handler: %w", err)
}
}
if err := services.RegisterAuthTokenServiceHandlerServer(ctx, mux, authtoks); err != nil {
return nil, fmt.Errorf("failed to register auth token service handler: %w", err)
if _, ok := currentServices[services.SessionService_ServiceDesc.ServiceName]; !ok {
ss, err := sessions.NewService(c.SessionRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create session handler service: %w", err)
}
services.RegisterSessionServiceServer(c.gatewayServer, ss)
if err := services.RegisterSessionServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register session service handler: %w", err)
}
}
os, err := scopes.NewService(c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create scope handler service: %w", err)
if _, ok := currentServices[services.ManagedGroupService_ServiceDesc.ServiceName]; !ok {
mgs, err := managed_groups.NewService(c.OidcRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create managed groups handler service: %w", err)
}
services.RegisterManagedGroupServiceServer(c.gatewayServer, mgs)
if err := services.RegisterManagedGroupServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register managed groups service handler: %w", err)
}
}
if err := services.RegisterScopeServiceHandlerServer(ctx, mux, os); err != nil {
return nil, fmt.Errorf("failed to register scope service handler: %w", err)
if _, ok := currentServices[services.CredentialStoreService_ServiceDesc.ServiceName]; !ok {
cs, err := credentialstores.NewService(c.VaultCredentialRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create credential store handler service: %w", err)
}
services.RegisterCredentialStoreServiceServer(c.gatewayServer, cs)
if err := services.RegisterCredentialStoreServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register credential store service handler: %w", err)
}
}
us, err := users.NewService(c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create user handler service: %w", err)
}
if err := services.RegisterUserServiceHandlerServer(ctx, mux, us); err != nil {
return nil, fmt.Errorf("failed to register user service handler: %w", err)
}
ts, err := targets.NewService(
ctx,
c.kms,
c.TargetRepoFn,
c.IamRepoFn,
c.ServersRepoFn,
c.SessionRepoFn,
c.PluginHostRepoFn,
c.StaticHostRepoFn,
c.VaultCredentialRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create target handler service: %w", err)
}
if err := services.RegisterTargetServiceHandlerServer(ctx, mux, ts); err != nil {
return nil, fmt.Errorf("failed to register target service handler: %w", err)
}
gs, err := groups.NewService(c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create group handler service: %w", err)
}
if err := services.RegisterGroupServiceHandlerServer(ctx, mux, gs); err != nil {
return nil, fmt.Errorf("failed to register group service handler: %w", err)
}
rs, err := roles.NewService(c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create role handler service: %w", err)
}
if err := services.RegisterRoleServiceHandlerServer(ctx, mux, rs); err != nil {
return nil, fmt.Errorf("failed to register role service handler: %w", err)
}
ss, err := sessions.NewService(c.SessionRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create session handler service: %w", err)
}
if err := services.RegisterSessionServiceHandlerServer(ctx, mux, ss); err != nil {
return nil, fmt.Errorf("failed to register session service handler: %w", err)
}
mgs, err := managed_groups.NewService(c.OidcRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create managed groups handler service: %w", err)
}
if err := services.RegisterManagedGroupServiceHandlerServer(ctx, mux, mgs); err != nil {
return nil, fmt.Errorf("failed to register managed groups service handler: %w", err)
}
cs, err := credentialstores.NewService(c.VaultCredentialRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create credential store handler service: %w", err)
}
if err := services.RegisterCredentialStoreServiceHandlerServer(ctx, mux, cs); err != nil {
return nil, fmt.Errorf("failed to register credential store service handler: %w", err)
}
cl, err := credentiallibraries.NewService(c.VaultCredentialRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create credential library handler service: %w", err)
}
if err := services.RegisterCredentialLibraryServiceHandlerServer(ctx, mux, cl); err != nil {
return nil, fmt.Errorf("failed to register credential library service handler: %w", err)
if _, ok := currentServices[services.CredentialLibraryService_ServiceDesc.ServiceName]; !ok {
cl, err := credentiallibraries.NewService(c.VaultCredentialRepoFn, c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create credential library handler service: %w", err)
}
services.RegisterCredentialLibraryServiceServer(c.gatewayServer, cl)
if err := services.RegisterCredentialLibraryServiceHandlerFromEndpoint(ctx, c.gatewayMux, gatewayTarget, dialOptions); err != nil {
return nil, fmt.Errorf("failed to register credential library service handler: %w", err)
}
}
return mux, nil
return c.gatewayMux, nil
}
func wrapHandlerWithCommonFuncs(h http.Handler, c *Controller, props HandlerProperties) http.Handler {
@@ -238,29 +278,27 @@ func wrapHandlerWithCommonFuncs(h http.Handler, c *Controller, props HandlerProp
}
// Add values for authn/authz checking
requestInfo := auth.RequestInfo{
requestInfo := authpb.RequestInfo{
Path: r.URL.Path,
Method: r.Method,
DisableAuthzFailures: disableAuthzFailures,
}
requestInfo.PublicId, requestInfo.EncryptedToken, requestInfo.TokenFormat = auth.GetTokenFromRequest(ctx, c.kms, r)
ctx = auth.NewVerifierContext(ctx, c.IamRepoFn, c.AuthTokenRepoFn, c.ServersRepoFn, c.kms, requestInfo)
// Add general request information to the context. The information from
// the auth verifier context is pretty specifically curated to
// authentication/authorization verification so this is more
// general-purpose.
//
// We could use requests.NewRequestContext but this saves an immediate
// lookup.
ctx = context.WithValue(ctx, requests.ContextRequestInformationKey, &requests.RequestContext{
Path: r.URL.Path,
Method: r.Method,
})
// Set the context back on the request
r = r.WithContext(ctx)
// Serialize the request info to send it across the wire to the
// grpc-gateway via an http header
requestInfo.Ticket = c.gatewayTicket // allows the grpc-gateway to verify the request info came from it's in-memory companion http proxy
marshalledRequestInfo, err := proto.Marshal(&requestInfo)
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("error marshaling request info"))
w.WriteHeader(http.StatusInternalServerError)
return
}
// Use the default grpc-gateway mapping rule to pass the request info as
// metadata.
// See: https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime#DefaultHeaderMatcher
r.Header.Set("Grpc-Metadata-"+requestInfoMdKey, base58.FastBase58Encoding(marshalledRequestInfo))
h.ServeHTTP(w, r)
})
@@ -389,7 +389,7 @@ func (s Service) DeleteAuthMethod(ctx context.Context, req *pbs.DeleteAuthMethod
if err != nil {
return nil, err
}
return nil, nil
return &pbs.DeleteAuthMethodResponse{}, nil
}
// Authenticate implements the interface pbs.AuthenticationServiceServer.
@@ -428,12 +428,14 @@ func TestDelete(t *testing.T) {
req: &pbs.DeleteAuthMethodRequest{
Id: pwam.GetPublicId(),
},
res: &pbs.DeleteAuthMethodResponse{},
},
{
name: "Delete an Existing OIDC AuthMethod",
req: &pbs.DeleteAuthMethodRequest{
Id: oidcam.GetPublicId(),
},
res: &pbs.DeleteAuthMethodResponse{},
},
{
name: "Delete bad auth_method id",
@@ -13,6 +13,8 @@ import (
"time"
"github.com/google/go-cmp/cmp"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/authtoken"
@@ -206,9 +208,9 @@ func TestList_FilterNonPublic(t *testing.T) {
atRepoFn,
serversRepoFn,
kmsCache,
auth.RequestInfo{
&authpb.RequestInfo{
Token: at.GetToken(),
TokenFormat: auth.AuthTokenTypeBearer,
TokenFormat: uint32(auth.AuthTokenTypeBearer),
PublicId: at.GetPublicId(),
})
}(),
@@ -11,6 +11,7 @@ import (
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/db"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/requests"
@@ -87,15 +88,15 @@ func TestGetSelf(t *testing.T) {
require, assert := require.New(t), assert.New(t)
// Setup the auth request information
req := httptest.NewRequest("GET", fmt.Sprintf("http://127.0.0.1/v1/auth-tokens/%s", tc.readId), nil)
requestInfo := auth.RequestInfo{
requestInfo := authpb.RequestInfo{
Path: req.URL.Path,
Method: req.Method,
TokenFormat: auth.AuthTokenTypeBearer,
TokenFormat: uint32(auth.AuthTokenTypeBearer),
PublicId: tc.token.GetPublicId(),
Token: tc.token.GetToken(),
}
ctx := auth.NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, requestInfo)
ctx := auth.NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, &requestInfo)
ctx = context.WithValue(ctx, requests.ContextRequestInformationKey, &requests.RequestContext{})
got, err := a.GetAuthToken(ctx, &pbs.GetAuthTokenRequest{Id: tc.readId})
if tc.err != nil {
@@ -236,15 +237,15 @@ func TestList_Self(t *testing.T) {
require, assert := require.New(t), assert.New(t)
// Setup the auth request information
req := httptest.NewRequest("GET", fmt.Sprintf("http://127.0.0.1/v1/auth-tokens?scope_id=%s", o.GetPublicId()), nil)
requestInfo := auth.RequestInfo{
requestInfo := authpb.RequestInfo{
Path: req.URL.Path,
Method: req.Method,
TokenFormat: auth.AuthTokenTypeBearer,
TokenFormat: uint32(auth.AuthTokenTypeBearer),
PublicId: tc.requester.GetPublicId(),
Token: tc.requester.GetToken(),
}
ctx := auth.NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, requestInfo)
ctx := auth.NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, &requestInfo)
got, err := a.ListAuthTokens(ctx, &pbs.ListAuthTokensRequest{ScopeId: o.GetPublicId()})
require.NoError(err)
require.Len(got.Items, 1)
@@ -482,15 +483,15 @@ func TestDeleteSelf(t *testing.T) {
require := require.New(t)
// Setup the auth request information
req := httptest.NewRequest("DELETE", fmt.Sprintf("http://127.0.0.1/v1/auth-tokens/%s", tc.deleteId), nil)
requestInfo := auth.RequestInfo{
requestInfo := authpb.RequestInfo{
Path: req.URL.Path,
Method: req.Method,
TokenFormat: auth.AuthTokenTypeBearer,
TokenFormat: uint32(auth.AuthTokenTypeBearer),
PublicId: tc.token.GetPublicId(),
Token: tc.token.GetToken(),
}
ctx := auth.NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, requestInfo)
ctx := auth.NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, &requestInfo)
got, err := a.DeleteAuthToken(ctx, &pbs.DeleteAuthTokenRequest{Id: tc.deleteId})
if tc.err != nil {
require.EqualError(err, tc.err.Error())
@@ -555,6 +555,7 @@ func TestDelete(t *testing.T) {
name string
id string
err error
res *pbs.DeleteCredentialLibraryResponse
}{
{
name: "success",
@@ -574,7 +575,7 @@ func TestDelete(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, gErr := s.DeleteCredentialLibrary(auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId()), &pbs.DeleteCredentialLibraryRequest{Id: tc.id})
assert.Nil(t, got)
assert.EqualValuesf(t, tc.res, got, "DeleteCredentialLibrary got response %q, wanted %q", got, tc.res)
if tc.err != nil {
require.Error(t, gErr)
assert.True(t, errors.Is(gErr, tc.err))
@@ -674,6 +674,7 @@ func TestDelete(t *testing.T) {
name string
id string
err error
res *pbs.DeleteCredentialStoreResponse
}{
{
name: "success",
@@ -693,7 +694,7 @@ func TestDelete(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, gErr := s.DeleteCredentialStore(auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId()), &pbs.DeleteCredentialStoreRequest{Id: tc.id})
assert.Nil(t, got)
assert.EqualValuesf(t, tc.res, got, "DeleteCredentialStore got response %q, wanted %q", got, tc.res)
if tc.err != nil {
require.Error(t, gErr)
assert.True(t, errors.Is(gErr, tc.err))
+143 -51
View File
@@ -5,31 +5,46 @@ import (
"fmt"
"io"
"net/http"
"regexp"
"sort"
"strconv"
"strings"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/hashicorp/boundary/internal/errors"
pb "github.com/hashicorp/boundary/internal/gen/controller/api"
pberrors "github.com/hashicorp/boundary/internal/gen/errors"
"github.com/hashicorp/boundary/internal/observability/event"
"github.com/mr-tron/base58"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
const (
genericUniquenessMsg = "Invalid request. Request attempted to make second resource with the same field value that must be unique."
genericNotFoundMsg = "Unable to find requested resource."
// domainErrHeader defines an http header for encoded domain errors from the
// grpc server.
domainErrHeader = "x-domain-err"
// domainErrMetadataHeader defines an http header for encoded domain errors from the
// grpc server via metadata
domainErrMetadataHeader = "Grpc-Metadata-X-Domain-Err"
apiErrHeader = "x-api-err"
apiErrMetadataHeader = "Grpc-Metadata-X-Api-Err"
)
type apiError struct {
status int32
inner *pb.Error
type ApiError struct {
Status int32
Inner *pb.Error
}
func (e *apiError) Error() string {
res := fmt.Sprintf("Status: %d, Kind: %q, Error: %q", e.status, e.inner.GetKind(), e.inner.GetMessage())
func (e *ApiError) Error() string {
res := fmt.Sprintf("Status: %d, Kind: %q, Error: %q", e.Status, e.Inner.GetKind(), e.Inner.GetMessage())
var dets []string
for _, rf := range e.inner.GetDetails().GetRequestFields() {
for _, rf := range e.Inner.GetDetails().GetRequestFields() {
dets = append(dets, fmt.Sprintf("{name: %q, desc: %q}", rf.GetName(), rf.GetDescription()))
}
if len(dets) > 0 {
@@ -39,19 +54,19 @@ func (e *apiError) Error() string {
return res
}
func (e *apiError) Is(target error) bool {
var tApiErr *apiError
func (e *ApiError) Is(target error) bool {
var tApiErr *ApiError
if !errors.As(target, &tApiErr) {
return false
}
return tApiErr.inner.Kind == e.inner.Kind && tApiErr.status == e.status
return tApiErr.Inner.Kind == e.Inner.Kind && tApiErr.Status == e.Status
}
// ApiErrorWithCode returns an api error with the provided code.
func ApiErrorWithCode(c codes.Code) error {
return &apiError{
status: int32(runtime.HTTPStatusFromCode(c)),
inner: &pb.Error{
return &ApiError{
Status: int32(runtime.HTTPStatusFromCode(c)),
Inner: &pb.Error{
Kind: c.String(),
},
}
@@ -59,9 +74,9 @@ func ApiErrorWithCode(c codes.Code) error {
// ApiErrorWithCodeAndMessage returns an api error with the provided code and message.
func ApiErrorWithCodeAndMessage(c codes.Code, msg string, args ...interface{}) error {
return &apiError{
status: int32(runtime.HTTPStatusFromCode(c)),
inner: &pb.Error{
return &ApiError{
Status: int32(runtime.HTTPStatusFromCode(c)),
Inner: &pb.Error{
Kind: c.String(),
Message: fmt.Sprintf(msg, args...),
},
@@ -70,9 +85,9 @@ func ApiErrorWithCodeAndMessage(c codes.Code, msg string, args ...interface{}) e
// NotFoundError returns an ApiError indicating a resource couldn't be found.
func NotFoundError() error {
return &apiError{
status: http.StatusNotFound,
inner: &pb.Error{
return &ApiError{
Status: http.StatusNotFound,
Inner: &pb.Error{
Kind: codes.NotFound.String(),
Message: "Resource not found.",
},
@@ -80,19 +95,19 @@ func NotFoundError() error {
}
// NotFoundErrorf returns an ApiError indicating a resource couldn't be found.
func NotFoundErrorf(msg string, a ...interface{}) *apiError {
return &apiError{
status: http.StatusNotFound,
inner: &pb.Error{
func NotFoundErrorf(msg string, a ...interface{}) *ApiError {
return &ApiError{
Status: http.StatusNotFound,
Inner: &pb.Error{
Kind: codes.NotFound.String(),
Message: fmt.Sprintf(msg, a...),
},
}
}
var unauthorizedError = &apiError{
status: http.StatusForbidden,
inner: &pb.Error{
var unauthorizedError = &ApiError{
Status: http.StatusForbidden,
Inner: &pb.Error{
Kind: codes.PermissionDenied.String(),
Message: "Forbidden.",
},
@@ -102,9 +117,9 @@ func ForbiddenError() error {
return unauthorizedError
}
var unauthenticatedError = &apiError{
status: http.StatusUnauthorized,
inner: &pb.Error{
var unauthenticatedError = &ApiError{
Status: http.StatusUnauthorized,
Inner: &pb.Error{
Kind: codes.Unauthenticated.String(),
Message: "Unauthenticated, or invalid token.",
},
@@ -114,47 +129,49 @@ func UnauthenticatedError() error {
return unauthenticatedError
}
func InvalidArgumentErrorf(msg string, fields map[string]string) *apiError {
func InvalidArgumentErrorf(msg string, fields map[string]string) *ApiError {
const op = "handlers.InvalidArgumentErrorf"
ctx := context.TODO()
err := ApiErrorWithCodeAndMessage(codes.InvalidArgument, msg)
var apiErr *apiError
var apiErr *ApiError
if !errors.As(err, &apiErr) {
event.WriteError(ctx, op, err, event.WithInfoMsg("Unable to build invalid argument api error."))
}
if len(fields) > 0 {
apiErr.inner.Details = &pb.ErrorDetails{}
apiErr.Inner.Details = &pb.ErrorDetails{}
}
for k, v := range fields {
apiErr.inner.Details.RequestFields = append(apiErr.inner.Details.RequestFields, &pb.FieldError{Name: k, Description: v})
apiErr.Inner.Details.RequestFields = append(apiErr.Inner.Details.RequestFields, &pb.FieldError{Name: k, Description: v})
}
sort.Slice(apiErr.inner.GetDetails().GetRequestFields(), func(i, j int) bool {
return apiErr.inner.Details.RequestFields[i].GetName() < apiErr.inner.Details.RequestFields[j].GetName()
sort.Slice(apiErr.Inner.GetDetails().GetRequestFields(), func(i, j int) bool {
return apiErr.Inner.Details.RequestFields[i].GetName() < apiErr.Inner.Details.RequestFields[j].GetName()
})
return apiErr
}
var statusRegEx = regexp.MustCompile("Status: ([0-9]+), Kind: \"(.*)\", Error: \"(.*)\"")
// Converts a known errors into an error that can presented to an end user over the API.
func backendErrorToApiError(inErr error) *apiError {
func backendErrorToApiError(inErr error) *ApiError {
stErr := status.Convert(inErr)
switch {
case errors.Is(inErr, runtime.ErrNotMatch):
// grpc gateway uses this error when the path was not matched, but the error uses codes.Unimplemented which doesn't match the intention.
// Overwrite the error to match our expected behavior.
return &apiError{
status: http.StatusNotFound,
inner: &pb.Error{
return &ApiError{
Status: http.StatusNotFound,
Inner: &pb.Error{
Kind: codes.NotFound.String(),
Message: http.StatusText(http.StatusNotFound),
},
}
case status.Code(inErr) == codes.Unimplemented:
// Instead of returning a 501 we always want to return a 405 when a method isn't implemented.
return &apiError{
status: http.StatusMethodNotAllowed,
inner: &pb.Error{
return &ApiError{
Status: http.StatusMethodNotAllowed,
Inner: &pb.Error{
Kind: codes.Unimplemented.String(),
Message: stErr.Message(),
},
@@ -176,11 +193,23 @@ func backendErrorToApiError(inErr error) *apiError {
statusCode = int32(domainErr.Code)
}
// perhaps the error is from the grpc gateway, so match against the known
// apiError msg format.
if found := statusRegEx.FindStringSubmatch(stErr.Message()); len(found) == 4 {
u32, err := strconv.ParseInt(found[1], 10, 32)
if err == nil { // notice it's testing for NO err
return &ApiError{
Status: int32(u32),
Inner: &pb.Error{Kind: found[2], Message: found[3]},
}
}
}
// TODO: Don't return potentially sensitive information (like which user id an account
// is already associated with when attempting to re-associate it).
return &apiError{
status: statusCode,
inner: &pb.Error{Kind: codes.Internal.String(), Message: inErr.Error()},
return &ApiError{
Status: statusCode,
Inner: &pb.Error{Kind: codes.Internal.String(), Message: inErr.Error()},
}
}
@@ -189,7 +218,70 @@ func ErrorHandler() runtime.ErrorHandlerFunc {
const errorFallback = `{"error": "failed to marshal error message"}`
return func(ctx context.Context, _ *runtime.ServeMux, mar runtime.Marshaler, w http.ResponseWriter, r *http.Request, inErr error) {
// API specified error, otherwise we need to translate repo/db errors.
var apiErr *apiError
// the grpc server will encoded domain errors into the x-domain-err, so
// let's check there first. (see: controller.errorInterceptor)
md, ok := runtime.ServerMetadataFromContext(ctx)
if ok {
defer func() {
// make sure we don't leak the headers that were used as a comm
// channel between the grpc server and the http proxy
delete(md.HeaderMD, domainErrHeader)
delete(w.Header(), domainErrMetadataHeader)
delete(md.HeaderMD, apiErrHeader)
delete(w.Header(), apiErrMetadataHeader)
}()
domainErrHdrs := md.HeaderMD.Get(domainErrHeader)
apiErrHdrs := md.HeaderMD.Get(apiErrHeader)
switch {
case len(domainErrHdrs) > 0:
decoded, err := base58.FastBase58Decoding(domainErrHdrs[0])
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to decode domain err header"))
w.WriteHeader(http.StatusInternalServerError)
if _, err := io.WriteString(w, errorFallback); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to write response"))
}
return
}
var pbErr pberrors.Err
if err := proto.Unmarshal(decoded, &pbErr); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to marshal domain err header"))
w.WriteHeader(http.StatusInternalServerError)
if _, err := io.WriteString(w, errorFallback); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to write response"))
}
return
}
inErr = errors.FromPbErrors(&pbErr)
case len(apiErrHdrs) > 0:
decoded, err := base58.FastBase58Decoding(apiErrHdrs[0])
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to decode api err header"))
w.WriteHeader(http.StatusInternalServerError)
if _, err := io.WriteString(w, errorFallback); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to write response"))
}
return
}
var pbApiErr pberrors.ApiError
if err := proto.Unmarshal(decoded, &pbApiErr); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to marshal api err header"))
w.WriteHeader(http.StatusInternalServerError)
if _, err := io.WriteString(w, errorFallback); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to write response"))
}
return
}
inErr = &ApiError{
Status: pbApiErr.Status,
Inner: pbApiErr.ApiError,
}
}
}
var apiErr *ApiError
isApiErr := errors.As(inErr, &apiErr)
if !isApiErr {
if err := backendErrorToApiError(inErr); err != nil && !errors.As(err, &apiErr) {
@@ -197,13 +289,13 @@ func ErrorHandler() runtime.ErrorHandlerFunc {
}
}
if apiErr.status == http.StatusInternalServerError {
if apiErr.Status == http.StatusInternalServerError {
event.WriteError(ctx, op, inErr, event.WithInfoMsg("internal error returned"))
}
buf, merr := mar.Marshal(apiErr.inner)
buf, merr := mar.Marshal(apiErr.Inner)
if merr != nil {
event.WriteError(ctx, op, merr, event.WithInfoMsg("failed to marshal error response", "response", fmt.Sprintf("%#v", apiErr.inner)))
event.WriteError(ctx, op, merr, event.WithInfoMsg("failed to marshal error response", "response", fmt.Sprintf("%#v", apiErr.Inner)))
w.WriteHeader(http.StatusInternalServerError)
if _, err := io.WriteString(w, errorFallback); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to write response"))
@@ -211,8 +303,8 @@ func ErrorHandler() runtime.ErrorHandlerFunc {
return
}
w.Header().Set("Content-Type", mar.ContentType(apiErr.inner))
w.WriteHeader(int(apiErr.status))
w.Header().Set("Content-Type", mar.ContentType(apiErr.Inner))
w.WriteHeader(int(apiErr.Status))
if _, err := w.Write(buf); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("failed to send response chunk"))
return
@@ -221,5 +313,5 @@ func ErrorHandler() runtime.ErrorHandlerFunc {
}
func ToApiError(e error) *pb.Error {
return backendErrorToApiError(e).inner
return backendErrorToApiError(e).Inner
}
@@ -32,14 +32,14 @@ func TestApiErrorHandler(t *testing.T) {
testCases := []struct {
name string
err error
expected apiError
expected ApiError
}{
{
name: "Not Found",
err: NotFoundErrorf("Test"),
expected: apiError{
status: http.StatusNotFound,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusNotFound,
Inner: &pb.Error{
Kind: "NotFound",
Message: "Test",
},
@@ -51,9 +51,9 @@ func TestApiErrorHandler(t *testing.T) {
"k1": "v1",
"k2": "v2",
}),
expected: apiError{
status: http.StatusBadRequest,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusBadRequest,
Inner: &pb.Error{
Kind: "InvalidArgument",
Message: "Test",
Details: &pb.ErrorDetails{
@@ -74,9 +74,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "GrpcGateway Routing Error",
err: runtime.ErrNotMatch,
expected: apiError{
status: http.StatusNotFound,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusNotFound,
Inner: &pb.Error{
Kind: "NotFound",
Message: http.StatusText(http.StatusNotFound),
},
@@ -85,9 +85,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Unimplemented error",
err: status.Error(codes.Unimplemented, "Test"),
expected: apiError{
status: http.StatusMethodNotAllowed,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusMethodNotAllowed,
Inner: &pb.Error{
Kind: "Unimplemented",
Message: "Test",
},
@@ -96,9 +96,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Unknown error",
err: stderrors.New("Some random error"),
expected: apiError{
status: http.StatusInternalServerError,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusInternalServerError,
Inner: &pb.Error{
Kind: "Internal",
Message: "Some random error",
},
@@ -107,9 +107,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Domain error Db invalid public id",
err: errors.E(ctx, errors.WithCode(errors.InvalidPublicId)),
expected: apiError{
status: http.StatusInternalServerError,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusInternalServerError,
Inner: &pb.Error{
Kind: "Internal",
Message: "invalid public id, parameter violation: error #102",
},
@@ -118,9 +118,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Domain error Db invalid parameter",
err: errors.E(ctx, errors.WithCode(errors.InvalidParameter)),
expected: apiError{
status: http.StatusInternalServerError,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusInternalServerError,
Inner: &pb.Error{
Kind: "Internal",
Message: "invalid parameter, parameter violation: error #100",
},
@@ -129,9 +129,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Domain error Db invalid field mask",
err: errors.E(ctx, errors.WithCode(errors.InvalidFieldMask)),
expected: apiError{
status: http.StatusBadRequest,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusBadRequest,
Inner: &pb.Error{
Kind: "InvalidArgument",
Message: "Error in provided request",
Details: &pb.ErrorDetails{RequestFields: []*pb.FieldError{{Name: "update_mask", Description: "Invalid update mask provided."}}},
@@ -141,9 +141,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Domain error Db empty field mask",
err: errors.E(ctx, errors.WithCode(errors.EmptyFieldMask)),
expected: apiError{
status: http.StatusBadRequest,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusBadRequest,
Inner: &pb.Error{
Kind: "InvalidArgument",
Message: "Error in provided request",
Details: &pb.ErrorDetails{RequestFields: []*pb.FieldError{{Name: "update_mask", Description: "Invalid update mask provided."}}},
@@ -153,9 +153,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Domain error Db not unqiue",
err: errors.E(ctx, errors.WithCode(errors.NotUnique)),
expected: apiError{
status: http.StatusBadRequest,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusBadRequest,
Inner: &pb.Error{
Kind: "InvalidArgument",
Message: genericUniquenessMsg,
},
@@ -164,9 +164,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Domain error Db record not found",
err: errors.E(ctx, errors.WithCode(errors.RecordNotFound)),
expected: apiError{
status: http.StatusNotFound,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusNotFound,
Inner: &pb.Error{
Kind: "NotFound",
Message: genericNotFoundMsg,
},
@@ -175,9 +175,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Domain error Db multiple records",
err: errors.E(ctx, errors.WithCode(errors.MultipleRecords)),
expected: apiError{
status: http.StatusInternalServerError,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusInternalServerError,
Inner: &pb.Error{
Kind: "Internal",
Message: "multiple records, search issue: error #1101",
},
@@ -186,9 +186,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Domain error account already associated",
err: errors.E(ctx, errors.WithCode(errors.AccountAlreadyAssociated)),
expected: apiError{
status: http.StatusBadRequest,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusBadRequest,
Inner: &pb.Error{
Kind: "InvalidArgument",
Message: "account already associated with another user, parameter violation: error #114",
},
@@ -197,9 +197,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Wrapped domain error",
err: errors.E(ctx, errors.WithCode(errors.InvalidAddress), errors.WithMsg("test msg"), errors.WithWrap(errors.E(ctx, errors.WithCode(errors.NotNull), errors.WithMsg("inner msg")))),
expected: apiError{
status: http.StatusInternalServerError,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusInternalServerError,
Inner: &pb.Error{
Kind: "Internal",
Message: "test msg: parameter violation: error #101: inner msg: integrity violation: error #1001",
},
@@ -208,9 +208,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Forbidden domain error",
err: errors.E(ctx, errors.WithCode(errors.Forbidden), errors.WithMsg("test msg")),
expected: apiError{
status: http.StatusForbidden,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusForbidden,
Inner: &pb.Error{
Kind: "Internal",
Message: "test msg: unknown: error #403",
},
@@ -219,9 +219,9 @@ func TestApiErrorHandler(t *testing.T) {
{
name: "Wrapped forbidden domain error",
err: fmt.Errorf("got error: %w", errors.E(ctx, errors.WithCode(errors.Forbidden), errors.WithMsg("test msg"))),
expected: apiError{
status: http.StatusForbidden,
inner: &pb.Error{
expected: ApiError{
Status: http.StatusForbidden,
Inner: &pb.Error{
Kind: "Internal",
Message: "got error: test msg: unknown: error #403",
},
@@ -234,7 +234,7 @@ func TestApiErrorHandler(t *testing.T) {
w := httptest.NewRecorder()
tested(ctx, mux, outMarsh, w, req, tc.err)
resp := w.Result()
assert.EqualValues(tc.expected.status, resp.StatusCode)
assert.EqualValues(tc.expected.Status, resp.StatusCode)
got, err := ioutil.ReadAll(resp.Body)
require.NoError(err)
@@ -243,8 +243,8 @@ func TestApiErrorHandler(t *testing.T) {
err = inMarsh.Unmarshal(got, gotErr)
require.NoError(err)
assert.Equal(tc.expected.status, int32(resp.StatusCode))
assert.Empty(cmp.Diff(tc.expected.inner, gotErr, protocmp.Transform()))
assert.Equal(tc.expected.Status, int32(resp.StatusCode))
assert.Empty(cmp.Diff(tc.expected.Inner, gotErr, protocmp.Transform()))
})
}
}
@@ -417,6 +417,7 @@ func TestDelete_twice(t *testing.T) {
o, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrap))
databaseWrapper, err := kmsCache.GetWrapper(context.Background(), o.PublicId, kms.KeyPurposeDatabase)
require.NoError(err)
oidcAm := oidc.TestAuthMethod(
t, conn, databaseWrapper, o.PublicId, oidc.ActivePrivateState,
@@ -1,26 +0,0 @@
package handlers
import (
"context"
"net/http"
"net/http/httptest"
"testing"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authtokens"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/structpb"
)
func TestOutgoingSplitCookie(t *testing.T) {
rec := httptest.NewRecorder()
attrs, err := ProtoToStruct(&pb.AuthToken{Token: "t_abc_1234567890"})
require.NoError(t, err)
attrs.GetFields()["token_type"] = structpb.NewStringValue("cookie")
require.NoError(t, OutgoingInterceptor(context.Background(), rec, &pbs.AuthenticateResponse{Attributes: attrs}))
assert.ElementsMatch(t, rec.Result().Cookies(), []*http.Cookie{
{Name: HttpOnlyCookieName, Value: "34567890", HttpOnly: true, Raw: "wt-http-token-cookie=34567890; HttpOnly"},
{Name: JsVisibleCookieName, Value: "t_abc_12", Raw: "wt-js-token-cookie=t_abc_12"},
})
}
@@ -4,30 +4,65 @@ import (
"context"
"fmt"
"net/http"
"strconv"
"strings"
"github.com/hashicorp/boundary/internal/errors"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/observability/event"
authtokenpb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authtokens"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
)
const (
HttpOnlyCookieName = "wt-http-token-cookie"
JsVisibleCookieName = "wt-js-token-cookie"
tokenTypeField = "token_type"
finalRedirectUrlField = "final_redirect_url"
statusField = "status"
HttpOnlyCookieName = "wt-http-token-cookie"
JsVisibleCookieName = "wt-js-token-cookie"
tokenTypeField = "token_type"
finalRedirectUrlField = "final_redirect_url"
statusField = "status"
StatusCodeHeader = "x-http-code"
statusCodeMetadataHeader = "Grpc-Metadata-X-Http-Code"
)
func OutgoingInterceptor(ctx context.Context, w http.ResponseWriter, m proto.Message) error {
const op = "handlers.OutgoingInterceptor"
m = m.ProtoReflect().Interface()
if !m.ProtoReflect().IsValid() {
// This would be the case if it's a nil pointer
w.WriteHeader(http.StatusNoContent)
return nil
// SetStatusCode allows a grpc service handler to set the outgoing http status
// code
func SetStatusCode(ctx context.Context, code int) error {
const op = "handlers.SetHttpStatusCode"
if http.StatusText(code) == "" {
return errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unknown status code: %d", code))
}
if err := grpc.SetHeader(ctx, metadata.Pairs(StatusCodeHeader, strconv.Itoa(code))); err != nil {
return errors.Wrap(ctx, err, op, errors.WithCode(errors.Internal))
}
return nil
}
// OutgoingResponseFilter is a gRPC gateway WithForwardResponseOption. It's
// basically a filter that can manipulate the http response and has acesss to
// the outgoing proto msg
func OutgoingResponseFilter(ctx context.Context, w http.ResponseWriter, m proto.Message) error {
const op = "handlers.OutgoingResponseFilter"
if md, ok := runtime.ServerMetadataFromContext(ctx); ok {
// set http status codes based on metadata set by the grpc service
if statusCodes := md.HeaderMD.Get(StatusCodeHeader); len(statusCodes) > 0 {
defer func() {
// delete the headers to not expose any grpc-metadata in http response
delete(md.HeaderMD, StatusCodeHeader)
delete(w.Header(), statusCodeMetadataHeader)
}()
lastStatus, err := strconv.Atoi(statusCodes[len(statusCodes)-1])
if err != nil {
return fmt.Errorf("%s: unable to convert status code %s: %w", op, statusCodes[len(statusCodes)-1], err)
}
w.WriteHeader(lastStatus)
return nil
}
}
// add the outgoing resp proto. See: common.flushGatedEvents is where the
@@ -0,0 +1,71 @@
package handlers
import (
"context"
"net/http"
"net/http/httptest"
"testing"
emptypb "github.com/hashicorp/boundary/internal/gen/controller/api"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authtokens"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
)
func TestOutgoingSplitCookie(t *testing.T) {
rec := httptest.NewRecorder()
attrs, err := ProtoToStruct(&pb.AuthToken{Token: "t_abc_1234567890"})
require.NoError(t, err)
attrs.GetFields()["token_type"] = structpb.NewStringValue("cookie")
require.NoError(t, OutgoingResponseFilter(context.Background(), rec, &pbs.AuthenticateResponse{Attributes: attrs}))
assert.ElementsMatch(t, rec.Result().Cookies(), []*http.Cookie{
{Name: HttpOnlyCookieName, Value: "34567890", HttpOnly: true, Raw: "wt-http-token-cookie=34567890; HttpOnly"},
{Name: JsVisibleCookieName, Value: "t_abc_12", Raw: "wt-js-token-cookie=t_abc_12"},
})
}
func TestOutgoingResponseFilter_StatusCode(t *testing.T) {
tests := []struct {
name string
md runtime.ServerMetadata
msg proto.Message
wantErr bool
wantStatusCode int
wantContent bool
}{
{
name: "204",
md: runtime.ServerMetadata{HeaderMD: metadata.Pairs(StatusCodeHeader, "204")},
wantStatusCode: 204,
},
{
name: "418",
md: runtime.ServerMetadata{HeaderMD: metadata.Pairs(StatusCodeHeader, "418")},
wantStatusCode: 418,
wantContent: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
rec := httptest.NewRecorder()
ctx := runtime.NewServerMetadataContext(context.Background(), tt.md)
err := OutgoingResponseFilter(ctx, rec, &emptypb.EmptyResponse{})
if tt.wantErr {
require.Error(err)
return
}
require.NoError(err)
resp := rec.Result()
if tt.wantStatusCode != 0 {
assert.Equal(tt.wantStatusCode, resp.StatusCode)
}
})
}
}
@@ -12,6 +12,7 @@ import (
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/host/static"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
@@ -21,6 +22,7 @@ import (
"github.com/hashicorp/boundary/internal/servers/controller/handlers/sessions"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/sessions"
@@ -57,7 +59,7 @@ func TestGetSession(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, p.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, p.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
sess := session.TestSession(t, conn, wrap, session.ComposedOf{
UserId: uId,
@@ -86,7 +88,7 @@ func TestGetSession(t *testing.T) {
Scope: &scopes.ScopeInfo{Id: p.GetPublicId(), Type: scope.Project.String(), ParentScopeId: o.GetPublicId()},
States: []*pb.SessionState{{Status: session.StatusPending.String(), StartTime: sess.CreateTime.GetTimestamp()}},
Certificate: sess.Certificate,
Type: target.TcpSubtype.String(),
Type: tcp.Subtype.String(),
AuthorizedActions: testAuthorizedActions,
}
@@ -174,7 +176,7 @@ func TestList_Self(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, pWithSessions.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, pWithSessions.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
// By default a user can read/cancel their own sessions.
session.TestSession(t, conn, wrap, session.ComposedOf{
@@ -210,15 +212,15 @@ func TestList_Self(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
// Setup the auth request information
req := httptest.NewRequest("GET", fmt.Sprintf("http://127.0.0.1/v1/sessions?scope_id=%s", pWithSessions.GetPublicId()), nil)
requestInfo := auth.RequestInfo{
requestInfo := authpb.RequestInfo{
Path: req.URL.Path,
Method: req.Method,
TokenFormat: auth.AuthTokenTypeBearer,
TokenFormat: uint32(auth.AuthTokenTypeBearer),
PublicId: tc.requester.GetPublicId(),
Token: tc.requester.GetToken(),
}
ctx := auth.NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, requestInfo)
ctx := auth.NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, kms, &requestInfo)
got, err := s.ListSessions(ctx, &pbs.ListSessionsRequest{ScopeId: pWithSessions.GetPublicId()})
require.NoError(t, err)
assert.Equal(t, tc.count, len(got.GetItems()), got.GetItems())
@@ -258,13 +260,13 @@ func TestList(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, pWithSessions.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, pWithSessions.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
hcOther := static.TestCatalogs(t, conn, pWithOtherSessions.GetPublicId(), 1)[0]
hsOther := static.TestSets(t, conn, hcOther.GetPublicId(), 1)[0]
hOther := static.TestHosts(t, conn, hcOther.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hsOther.GetPublicId(), []*static.Host{hOther})
tarOther := target.TestTcpTarget(t, conn, pWithOtherSessions.GetPublicId(), "test", target.WithHostSources([]string{hsOther.GetPublicId()}))
tarOther := tcp.TestTarget(t, conn, pWithOtherSessions.GetPublicId(), "test", target.WithHostSources([]string{hsOther.GetPublicId()}))
var wantSession []*pb.Session
var totalSession []*pb.Session
@@ -298,7 +300,7 @@ func TestList(t *testing.T) {
Status: status,
States: states,
Certificate: sess.Certificate,
Type: target.TcpSubtype.String(),
Type: tcp.Subtype.String(),
AuthorizedActions: testAuthorizedActions,
})
@@ -333,7 +335,7 @@ func TestList(t *testing.T) {
Status: status,
States: states,
Certificate: sess.Certificate,
Type: target.TcpSubtype.String(),
Type: tcp.Subtype.String(),
AuthorizedActions: testAuthorizedActions,
})
}
@@ -469,7 +471,7 @@ func TestCancel(t *testing.T) {
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h})
tar := target.TestTcpTarget(t, conn, p.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
tar := tcp.TestTarget(t, conn, p.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()}))
sess := session.TestSession(t, conn, wrap, session.ComposedOf{
UserId: uId,
@@ -496,7 +498,7 @@ func TestCancel(t *testing.T) {
Scope: &scopes.ScopeInfo{Id: p.GetPublicId(), Type: scope.Project.String(), ParentScopeId: o.GetPublicId()},
Status: session.StatusCanceling.String(),
Certificate: sess.Certificate,
Type: target.TcpSubtype.String(),
Type: tcp.Subtype.String(),
AuthorizedActions: testAuthorizedActions,
}
@@ -30,7 +30,8 @@ import (
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/hashicorp/boundary/internal/target/tcp"
tcpStore "github.com/hashicorp/boundary/internal/target/tcp/store"
"github.com/hashicorp/boundary/internal/types/action"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/internal/types/scope"
@@ -78,7 +79,10 @@ var (
func init() {
var err error
if maskManager, err = handlers.NewMaskManager(handlers.MaskDestination{&store.TcpTarget{}}, handlers.MaskSource{&pb.Target{}, &pb.TcpTargetAttributes{}}); err != nil {
if maskManager, err = handlers.NewMaskManager(
handlers.MaskDestination{&tcpStore.Target{}},
handlers.MaskSource{&pb.Target{}, &pb.TcpTargetAttributes{}},
); err != nil {
panic(err)
}
}
@@ -1010,7 +1014,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
// Generate the endpoint URL
endpointUrl := &url.URL{
Scheme: t.GetType(),
Scheme: t.GetType().String(),
}
defaultPort := t.GetDefaultPort()
if defaultPort != 0 {
@@ -1124,7 +1128,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
TargetId: t.GetPublicId(),
Scope: authResults.Scope,
CreatedTime: sess.CreateTime.GetTimestamp(),
Type: t.GetType(),
Type: t.GetType().String(),
Certificate: sess.Certificate,
PrivateKey: privKey,
HostId: chosenEndpoint.HostId,
@@ -1143,7 +1147,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
TargetId: t.GetPublicId(),
Scope: authResults.Scope,
CreatedTime: sess.CreateTime.GetTimestamp(),
Type: t.GetType(),
Type: t.GetType().String(),
AuthorizationToken: string(encodedMarshaledSad),
UserId: authResults.UserId,
HostId: chosenEndpoint.HostId,
@@ -1194,7 +1198,7 @@ func (s Service) createInRepo(ctx context.Context, item *pb.Target) (target.Targ
if tcpAttrs.GetDefaultPort().GetValue() != 0 {
opts = append(opts, target.WithDefaultPort(tcpAttrs.GetDefaultPort().GetValue()))
}
u, err := target.NewTcpTarget(item.GetScopeId(), opts...)
u, err := tcp.New(item.GetScopeId(), opts...)
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to build target for creation: %v.", err)
}
@@ -1202,7 +1206,7 @@ func (s Service) createInRepo(ctx context.Context, item *pb.Target) (target.Targ
if err != nil {
return nil, nil, nil, err
}
out, hs, cl, err := repo.CreateTcpTarget(ctx, u)
out, hs, cl, err := repo.CreateTarget(ctx, u)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create target"))
}
@@ -1238,7 +1242,7 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st
opts = append(opts, target.WithDefaultPort(tcpAttrs.GetDefaultPort().GetValue()))
}
version := item.GetVersion()
u, err := target.NewTcpTarget(scopeId, opts...)
u, err := tcp.New(scopeId, opts...)
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to build target for update: %v.", err)
}
@@ -1251,7 +1255,7 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st
if err != nil {
return nil, nil, nil, err
}
out, hs, cl, rowsUpdated, err := repo.UpdateTcpTarget(ctx, u, version, dbMask)
out, hs, cl, rowsUpdated, err := repo.UpdateTarget(ctx, u, version, dbMask)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to update target"))
}
@@ -1476,7 +1480,7 @@ func toProto(ctx context.Context, in target.Target, hostSources []target.HostSou
out.ScopeId = in.GetScopeId()
}
if outputFields.Has(globals.TypeField) {
out.Type = target.TcpTargetType.String()
out.Type = in.GetType().String()
}
if outputFields.Has(globals.DescriptionField) && in.GetDescription() != "" {
out.Description = wrapperspb.String(in.GetDescription())
@@ -1594,7 +1598,7 @@ func toProto(ctx context.Context, in target.Target, hostSources []target.HostSou
// * All required parameters are set
// * There are no conflicting parameters provided
func validateGetRequest(req *pbs.GetTargetRequest) error {
return handlers.ValidateGetRequest(handlers.NoopValidatorFn, req, target.TcpTargetPrefix)
return handlers.ValidateGetRequest(handlers.NoopValidatorFn, req, tcp.TargetPrefix)
}
func validateCreateRequest(req *pbs.CreateTargetRequest) error {
@@ -1619,7 +1623,7 @@ func validateCreateRequest(req *pbs.CreateTargetRequest) error {
badFields[globals.SessionMaxSecondsField] = "This must be greater than zero."
}
switch target.SubtypeFromType(req.GetItem().GetType()) {
case target.TcpSubtype:
case tcp.Subtype:
tcpAttrs := &pb.TcpTargetAttributes{}
if err := handlers.StructToProto(req.GetItem().GetAttributes(), tcpAttrs); err != nil {
badFields[globals.AttributesField] = "Attribute fields do not match the expected format."
@@ -1628,11 +1632,9 @@ func validateCreateRequest(req *pbs.CreateTargetRequest) error {
badFields["attributes.default_port"] = "This optional field cannot be set to 0."
}
}
switch req.GetItem().GetType() {
case target.TcpTargetType.String():
case "":
if req.GetItem().GetType() == "" {
badFields[globals.TypeField] = "This is a required field."
default:
} else if target.SubtypeFromType(req.GetItem().GetType()) == "" {
badFields[globals.TypeField] = "Unknown type provided."
}
if filter := req.GetItem().GetWorkerFilter(); filter != nil {
@@ -1663,8 +1665,8 @@ func validateUpdateRequest(req *pbs.UpdateTargetRequest) error {
badFields[globals.SessionMaxSecondsField] = "This must be greater than zero."
}
switch target.SubtypeFromId(req.GetItem().GetType()) {
case target.TcpSubtype:
if req.GetItem().GetType() != "" && target.SubtypeFromType(req.GetItem().GetType()) != target.TcpSubtype {
case tcp.Subtype:
if req.GetItem().GetType() != "" && target.SubtypeFromType(req.GetItem().GetType()) != tcp.Subtype {
badFields[globals.TypeField] = "Cannot modify the resource type."
}
tcpAttrs := &pb.TcpTargetAttributes{}
@@ -1681,11 +1683,11 @@ func validateUpdateRequest(req *pbs.UpdateTargetRequest) error {
}
}
return badFields
}, target.TcpTargetPrefix)
}, tcp.TargetPrefix)
}
func validateDeleteRequest(req *pbs.DeleteTargetRequest) error {
return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, target.TcpTargetPrefix)
return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, tcp.TargetPrefix)
}
func validateListRequest(req *pbs.ListTargetsRequest) error {
@@ -1705,7 +1707,7 @@ func validateListRequest(req *pbs.ListTargetsRequest) error {
func validateAddSetsRequest(req *pbs.AddTargetHostSetsRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1729,7 +1731,7 @@ func validateAddSetsRequest(req *pbs.AddTargetHostSetsRequest) error {
func validateSetSetsRequest(req *pbs.SetTargetHostSetsRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1750,7 +1752,7 @@ func validateSetSetsRequest(req *pbs.SetTargetHostSetsRequest) error {
func validateRemoveSetsRequest(req *pbs.RemoveTargetHostSetsRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1774,7 +1776,7 @@ func validateRemoveSetsRequest(req *pbs.RemoveTargetHostSetsRequest) error {
func validateAddHostSourcesRequest(req *pbs.AddTargetHostSourcesRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1798,7 +1800,7 @@ func validateAddHostSourcesRequest(req *pbs.AddTargetHostSourcesRequest) error {
func validateSetHostSourcesRequest(req *pbs.SetTargetHostSourcesRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1819,7 +1821,7 @@ func validateSetHostSourcesRequest(req *pbs.SetTargetHostSourcesRequest) error {
func validateRemoveHostSourcesRequest(req *pbs.RemoveTargetHostSourcesRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1843,7 +1845,7 @@ func validateRemoveHostSourcesRequest(req *pbs.RemoveTargetHostSourcesRequest) e
func validateAddLibrariesRequest(req *pbs.AddTargetCredentialLibrariesRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1866,7 +1868,7 @@ func validateAddLibrariesRequest(req *pbs.AddTargetCredentialLibrariesRequest) e
func validateSetLibrariesRequest(req *pbs.SetTargetCredentialLibrariesRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1886,7 +1888,7 @@ func validateSetLibrariesRequest(req *pbs.SetTargetCredentialLibrariesRequest) e
func validateRemoveLibrariesRequest(req *pbs.RemoveTargetCredentialLibrariesRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1909,7 +1911,7 @@ func validateRemoveLibrariesRequest(req *pbs.RemoveTargetCredentialLibrariesRequ
func validateAddCredentialSourcesRequest(req *pbs.AddTargetCredentialSourcesRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1932,7 +1934,7 @@ func validateAddCredentialSourcesRequest(req *pbs.AddTargetCredentialSourcesRequ
func validateSetCredentialSourcesRequest(req *pbs.SetTargetCredentialSourcesRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1952,7 +1954,7 @@ func validateSetCredentialSourcesRequest(req *pbs.SetTargetCredentialSourcesRequ
func validateRemoveCredentialSourcesRequest(req *pbs.RemoveTargetCredentialSourcesRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
@@ -1979,7 +1981,7 @@ func validateAuthorizeSessionRequest(req *pbs.AuthorizeSessionRequest) error {
scopeIdEmpty := req.GetScopeId() == ""
scopeNameEmpty := req.GetScopeName() == ""
if nameEmpty {
if !handlers.ValidId(handlers.Id(req.GetId()), target.TcpTargetPrefix) {
if !handlers.ValidId(handlers.Id(req.GetId()), tcp.TargetPrefix) {
badFields[globals.IdField] = "Incorrectly formatted identifier."
}
if !scopeIdEmpty {
@@ -17,6 +17,7 @@ import (
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
spbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
"github.com/hashicorp/boundary/internal/host/plugin"
"github.com/hashicorp/boundary/internal/host/static"
@@ -34,6 +35,7 @@ import (
"github.com/hashicorp/boundary/internal/servers/controller/handlers/workers"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/hashicorp/boundary/internal/types/scope"
credpb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentiallibraries"
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
@@ -112,7 +114,7 @@ func TestGet(t *testing.T) {
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
hs := static.TestSets(t, conn, hc.GetPublicId(), 2)
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()}))
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()}))
pTar := &pb.Target{
Id: tar.GetPublicId(),
@@ -121,7 +123,7 @@ func TestGet(t *testing.T) {
CreatedTime: tar.CreateTime.GetTimestamp(),
UpdatedTime: tar.UpdateTime.GetTimestamp(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: o.GetPublicId()},
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
HostSetIds: []string{hs[0].GetPublicId(), hs[1].GetPublicId()},
HostSourceIds: []string{hs[0].GetPublicId(), hs[1].GetPublicId()},
Attributes: new(structpb.Struct),
@@ -147,7 +149,7 @@ func TestGet(t *testing.T) {
},
{
name: "Get a non existing Target",
req: &pbs.GetTargetRequest{Id: target.TcpTargetPrefix + "_DoesntExis"},
req: &pbs.GetTargetRequest{Id: tcp.TargetPrefix + "_DoesntExis"},
res: nil,
err: handlers.ApiErrorWithCode(codes.NotFound),
},
@@ -159,7 +161,7 @@ func TestGet(t *testing.T) {
},
{
name: "space in id",
req: &pbs.GetTargetRequest{Id: target.TcpTargetPrefix + "_1 23456789"},
req: &pbs.GetTargetRequest{Id: tcp.TargetPrefix + "_1 23456789"},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
@@ -207,7 +209,7 @@ func TestList(t *testing.T) {
var totalTars []*pb.Target
for i := 0; i < 5; i++ {
name := fmt.Sprintf("tar%d", i)
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), name, target.WithHostSources([]string{hss[0].GetPublicId(), hss[1].GetPublicId()}))
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), name, target.WithHostSources([]string{hss[0].GetPublicId(), hss[1].GetPublicId()}))
wantTars = append(wantTars, &pb.Target{
Id: tar.GetPublicId(),
ScopeId: proj.GetPublicId(),
@@ -216,14 +218,14 @@ func TestList(t *testing.T) {
CreatedTime: tar.GetCreateTime().GetTimestamp(),
UpdatedTime: tar.GetUpdateTime().GetTimestamp(),
Version: tar.GetVersion(),
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
Attributes: new(structpb.Struct),
SessionMaxSeconds: wrapperspb.UInt32(28800),
SessionConnectionLimit: wrapperspb.Int32(1),
AuthorizedActions: testAuthorizedActions,
})
totalTars = append(totalTars, wantTars[i])
tar = target.TestTcpTarget(t, conn, otherProj.GetPublicId(), name, target.WithHostSources([]string{otherHss[0].GetPublicId(), otherHss[1].GetPublicId()}))
tar = tcp.TestTarget(t, conn, otherProj.GetPublicId(), name, target.WithHostSources([]string{otherHss[0].GetPublicId(), otherHss[1].GetPublicId()}))
totalTars = append(totalTars, &pb.Target{
Id: tar.GetPublicId(),
ScopeId: otherProj.GetPublicId(),
@@ -232,7 +234,7 @@ func TestList(t *testing.T) {
CreatedTime: tar.GetCreateTime().GetTimestamp(),
UpdatedTime: tar.GetUpdateTime().GetTimestamp(),
Version: tar.GetVersion(),
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
Attributes: new(structpb.Struct),
SessionMaxSeconds: wrapperspb.UInt32(28800),
SessionConnectionLimit: wrapperspb.Int32(1),
@@ -322,7 +324,7 @@ func TestDelete(t *testing.T) {
}
_, proj := iam.TestScopes(t, iamRepo)
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test")
s, err := testService(t, conn, kms, wrapper)
require.NoError(t, err, "Couldn't create a new target service.")
@@ -345,7 +347,7 @@ func TestDelete(t *testing.T) {
name: "Delete Not Existing Target",
scopeId: proj.GetPublicId(),
req: &pbs.DeleteTargetRequest{
Id: target.TcpTargetPrefix + "_doesntexis",
Id: tcp.TargetPrefix + "_doesntexis",
},
err: handlers.ApiErrorWithCode(codes.NotFound),
},
@@ -353,7 +355,7 @@ func TestDelete(t *testing.T) {
name: "Bad target id formatting",
scopeId: proj.GetPublicId(),
req: &pbs.DeleteTargetRequest{
Id: target.TcpTargetPrefix + "_bad_format",
Id: tcp.TargetPrefix + "_bad_format",
},
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
@@ -385,7 +387,7 @@ func TestDelete_twice(t *testing.T) {
_, proj := iam.TestScopes(t, iamRepo)
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test")
s, err := testService(t, conn, kms, wrapper)
require.NoError(err, "Couldn't create a new target service.")
@@ -425,20 +427,20 @@ func TestCreate(t *testing.T) {
ScopeId: proj.GetPublicId(),
Name: wrapperspb.String("name"),
Description: wrapperspb.String("desc"),
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"default_port": structpb.NewNumberValue(2),
}},
WorkerFilter: wrapperspb.String(`type == "bar"`),
}},
res: &pbs.CreateTargetResponse{
Uri: fmt.Sprintf("targets/%s_", target.TcpTargetPrefix),
Uri: fmt.Sprintf("targets/%s_", tcp.TargetPrefix),
Item: &pb.Target{
ScopeId: proj.GetPublicId(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: org.GetPublicId()},
Name: wrapperspb.String("name"),
Description: wrapperspb.String("desc"),
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"default_port": structpb.NewNumberValue(2),
}},
@@ -454,7 +456,7 @@ func TestCreate(t *testing.T) {
req: &pbs.CreateTargetRequest{Item: &pb.Target{
Name: wrapperspb.String("name"),
Description: wrapperspb.String("desc"),
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"default_port": structpb.NewNumberValue(0),
}},
@@ -528,7 +530,7 @@ func TestCreate(t *testing.T) {
if got != nil {
assert.Contains(got.GetUri(), tc.res.GetUri())
assert.True(strings.HasPrefix(got.GetItem().GetId(), target.TcpTargetPrefix), got.GetItem().GetId())
assert.True(strings.HasPrefix(got.GetItem().GetId(), tcp.TargetPrefix), got.GetItem().GetId())
// Clear all values which are hard to compare against.
got.Uri, tc.res.Uri = "", ""
@@ -576,18 +578,18 @@ func TestUpdate(t *testing.T) {
{Id: hs[1].GetPublicId(), HostCatalogId: hs[1].GetCatalogId()},
}
tar, err := target.NewTcpTarget(proj.GetPublicId(), target.WithName("default"), target.WithDescription("default"))
tar, err := tcp.New(proj.GetPublicId(), target.WithName("default"), target.WithDescription("default"))
tar.DefaultPort = 2
require.NoError(t, err)
gtar, _, _, err := repo.CreateTcpTarget(context.Background(), tar, target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()}))
gtar, _, _, err := repo.CreateTarget(context.Background(), tar, target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()}))
require.NoError(t, err)
tar = gtar.(*target.TcpTarget)
tar = gtar.(*tcp.Target)
var version uint32 = 1
resetTarget := func() {
version++
_, _, _, _, err = repo.UpdateTcpTarget(context.Background(), tar, version, []string{"Name", "Description"})
_, _, _, _, err = repo.UpdateTarget(context.Background(), tar, version, []string{"Name", "Description"})
require.NoError(t, err, "Failed to reset target.")
version++
}
@@ -617,7 +619,7 @@ func TestUpdate(t *testing.T) {
Description: wrapperspb.String("desc"),
SessionMaxSeconds: wrapperspb.UInt32(3600),
SessionConnectionLimit: wrapperspb.Int32(5),
Type: target.TcpSubtype.String(),
Type: tcp.Subtype.String(),
},
},
res: &pbs.UpdateTargetResponse{
@@ -627,7 +629,7 @@ func TestUpdate(t *testing.T) {
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: org.GetPublicId()},
Name: wrapperspb.String("name"),
Description: wrapperspb.String("desc"),
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"default_port": structpb.NewNumberValue(2),
}},
@@ -651,7 +653,7 @@ func TestUpdate(t *testing.T) {
Item: &pb.Target{
Name: wrapperspb.String("name"),
Description: wrapperspb.String("desc"),
Type: target.TcpSubtype.String(),
Type: tcp.Subtype.String(),
},
},
res: &pbs.UpdateTargetResponse{
@@ -662,7 +664,7 @@ func TestUpdate(t *testing.T) {
Name: wrapperspb.String("name"),
Description: wrapperspb.String("desc"),
CreatedTime: tar.GetCreateTime().GetTimestamp(),
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"default_port": structpb.NewNumberValue(2),
}},
@@ -749,7 +751,7 @@ func TestUpdate(t *testing.T) {
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: org.GetPublicId()},
Name: wrapperspb.String("default"),
CreatedTime: tar.GetCreateTime().GetTimestamp(),
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"default_port": structpb.NewNumberValue(2),
}},
@@ -782,7 +784,7 @@ func TestUpdate(t *testing.T) {
Name: wrapperspb.String("updated"),
Description: wrapperspb.String("default"),
CreatedTime: tar.GetCreateTime().GetTimestamp(),
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"default_port": structpb.NewNumberValue(2),
}},
@@ -818,7 +820,7 @@ func TestUpdate(t *testing.T) {
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"default_port": structpb.NewNumberValue(2),
}},
Type: target.TcpTargetType.String(),
Type: tcp.Subtype.String(),
HostSetIds: hsIds,
HostSets: hostSets,
HostSourceIds: hostSourceIds,
@@ -832,7 +834,7 @@ func TestUpdate(t *testing.T) {
{
name: "Update a Non Existing Target",
req: &pbs.UpdateTargetRequest{
Id: target.TcpTargetPrefix + "_DoesntExis",
Id: tcp.TargetPrefix + "_DoesntExis",
UpdateMask: &field_mask.FieldMask{
Paths: []string{"description"},
},
@@ -944,10 +946,10 @@ func TestUpdate_BadVersion(t *testing.T) {
repo, err := repoFn()
require.NoError(t, err, "Couldn't create new target repo.")
tar, err := target.NewTcpTarget(proj.GetPublicId(), target.WithName("default"), target.WithDescription("default"))
tar, err := tcp.New(proj.GetPublicId(), target.WithName("default"), target.WithDescription("default"))
tar.DefaultPort = 2
require.NoError(t, err)
gtar, _, _, err := repo.CreateTcpTarget(context.Background(), tar)
gtar, _, _, err := repo.CreateTarget(context.Background(), tar)
require.NoError(t, err)
tested, err := testService(t, conn, kms, wrapper)
@@ -992,37 +994,37 @@ func TestAddTargetHostSets(t *testing.T) {
addCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
addHostSets []string
resultHostSets []string
}{
{
name: "Add set on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
addHostSets: []string{hs[1].GetPublicId()},
resultHostSets: []string{hs[1].GetPublicId()},
},
{
name: "Add set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
addHostSets: []string{hs[1].GetPublicId()},
resultHostSets: []string{hs[0].GetPublicId(), hs[1].GetPublicId()},
},
{
name: "Add duplicated sets on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "duplicated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated", target.WithHostSources([]string{hs[0].GetPublicId()})),
addHostSets: []string{hs[1].GetPublicId(), hs[1].GetPublicId()},
resultHostSets: []string{hs[0].GetPublicId(), hs[1].GetPublicId()},
},
{
name: "Add plugin set on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "plugin empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "plugin empty"),
addHostSets: []string{pluginHs.GetPublicId()},
resultHostSets: []string{pluginHs.GetPublicId()},
},
{
name: "Add plugin set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "plugin populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "plugin populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
addHostSets: []string{pluginHs.GetPublicId()},
resultHostSets: []string{hs[0].GetPublicId(), pluginHs.GetPublicId()},
},
@@ -1045,7 +1047,7 @@ func TestAddTargetHostSets(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test")
failCases := []struct {
name string
@@ -1126,43 +1128,43 @@ func TestSetTargetHostSets(t *testing.T) {
setCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
setHostSets []string
resultHostSets []string
}{
{
name: "Set on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
setHostSets: []string{hs[1].GetPublicId()},
resultHostSets: []string{hs[1].GetPublicId()},
},
{
name: "Set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
setHostSets: []string{hs[1].GetPublicId()},
resultHostSets: []string{hs[1].GetPublicId()},
},
{
name: "Set duplicate host set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithHostSources([]string{hs[0].GetPublicId()})),
setHostSets: []string{hs[1].GetPublicId(), hs[1].GetPublicId()},
resultHostSets: []string{hs[1].GetPublicId()},
},
{
name: "Set empty on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "another populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
setHostSets: []string{},
resultHostSets: nil,
},
{
name: "Set plugin set on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "plugin empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "plugin empty"),
setHostSets: []string{pluginHs.GetPublicId()},
resultHostSets: []string{pluginHs.GetPublicId()},
},
{
name: "Set plugin set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "plugin populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "plugin populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
setHostSets: []string{pluginHs.GetPublicId()},
resultHostSets: []string{pluginHs.GetPublicId()},
},
@@ -1181,7 +1183,7 @@ func TestSetTargetHostSets(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test name")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test name")
failCases := []struct {
name string
@@ -1254,38 +1256,38 @@ func TestRemoveTargetHostSets(t *testing.T) {
removeCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
removeHosts []string
resultHosts []string
wantErr bool
}{
{
name: "Remove from empty",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
removeHosts: []string{hs[1].GetPublicId()},
wantErr: true,
},
{
name: "Remove 1 of 2 sets",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
removeHosts: []string{hs[1].GetPublicId()},
resultHosts: []string{hs[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 sets",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
removeHosts: []string{hs[1].GetPublicId(), hs[1].GetPublicId()},
resultHosts: []string{hs[0].GetPublicId()},
},
{
name: "Remove all hosts from set",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove all", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
removeHosts: []string{hs[0].GetPublicId(), hs[1].GetPublicId()},
resultHosts: []string{},
},
{
name: "Remove 1 plugin of 2 sets",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove plugin partial", target.WithHostSources([]string{hs[0].GetPublicId(), pluginHs.GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove plugin partial", target.WithHostSources([]string{hs[0].GetPublicId(), pluginHs.GetPublicId()})),
removeHosts: []string{pluginHs.GetPublicId()},
resultHosts: []string{hs[0].GetPublicId()},
},
@@ -1312,7 +1314,7 @@ func TestRemoveTargetHostSets(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "testing")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "testing")
failCases := []struct {
name string
@@ -1394,37 +1396,37 @@ func TestAddTargetHostSources(t *testing.T) {
addCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
addHostSources []string
resultHostSources []string
}{
{
name: "Add set on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
addHostSources: []string{hs[1].GetPublicId()},
resultHostSources: []string{hs[1].GetPublicId()},
},
{
name: "Add set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
addHostSources: []string{hs[1].GetPublicId()},
resultHostSources: []string{hs[0].GetPublicId(), hs[1].GetPublicId()},
},
{
name: "Add duplicated sets on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "duplicated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated", target.WithHostSources([]string{hs[0].GetPublicId()})),
addHostSources: []string{hs[1].GetPublicId(), hs[1].GetPublicId()},
resultHostSources: []string{hs[0].GetPublicId(), hs[1].GetPublicId()},
},
{
name: "Add plugin set on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "plugin empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "plugin empty"),
addHostSources: []string{pluginHs.GetPublicId()},
resultHostSources: []string{pluginHs.GetPublicId()},
},
{
name: "Add plugin set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "plugin populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "plugin populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
addHostSources: []string{pluginHs.GetPublicId()},
resultHostSources: []string{hs[0].GetPublicId(), pluginHs.GetPublicId()},
},
@@ -1447,7 +1449,7 @@ func TestAddTargetHostSources(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test")
failCases := []struct {
name string
@@ -1528,37 +1530,37 @@ func TestSetTargetHostSources(t *testing.T) {
setCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
setHostSources []string
resultHostSources []string
}{
{
name: "Set on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
setHostSources: []string{hs[1].GetPublicId()},
resultHostSources: []string{hs[1].GetPublicId()},
},
{
name: "Set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
setHostSources: []string{hs[1].GetPublicId()},
resultHostSources: []string{hs[1].GetPublicId()},
},
{
name: "Set plugin set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "plugin populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "plugin populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
setHostSources: []string{pluginHs.GetPublicId()},
resultHostSources: []string{pluginHs.GetPublicId()},
},
{
name: "Set duplicate host set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithHostSources([]string{hs[0].GetPublicId()})),
setHostSources: []string{hs[1].GetPublicId(), hs[1].GetPublicId()},
resultHostSources: []string{hs[1].GetPublicId()},
},
{
name: "Set empty on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "another populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithHostSources([]string{hs[0].GetPublicId()})),
setHostSources: []string{},
resultHostSources: nil,
},
@@ -1577,7 +1579,7 @@ func TestSetTargetHostSources(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test name")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test name")
failCases := []struct {
name string
@@ -1650,38 +1652,38 @@ func TestRemoveTargetHostSources(t *testing.T) {
removeCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
removeHostSources []string
resultHostSources []string
wantErr bool
}{
{
name: "Remove from empty",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
removeHostSources: []string{hs[1].GetPublicId()},
wantErr: true,
},
{
name: "Remove 1 of 2 sets",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
removeHostSources: []string{hs[1].GetPublicId()},
resultHostSources: []string{hs[0].GetPublicId()},
},
{
name: "Remove 1 plugin set of 2 sets",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove plugin partial", target.WithHostSources([]string{hs[0].GetPublicId(), pluginHs.GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove plugin partial", target.WithHostSources([]string{hs[0].GetPublicId(), pluginHs.GetPublicId()})),
removeHostSources: []string{pluginHs.GetPublicId()},
resultHostSources: []string{hs[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 sets",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
removeHostSources: []string{hs[1].GetPublicId(), hs[1].GetPublicId()},
resultHostSources: []string{hs[0].GetPublicId()},
},
{
name: "Remove all hosts from set",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove all", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})),
removeHostSources: []string{hs[0].GetPublicId(), hs[1].GetPublicId()},
resultHostSources: []string{},
},
@@ -1708,7 +1710,7 @@ func TestRemoveTargetHostSources(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "testing")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "testing")
failCases := []struct {
name string
@@ -1784,25 +1786,25 @@ func TestAddTargetLibraries(t *testing.T) {
addCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
addLibraries []string
resultLibraryIds []string
}{
{
name: "Add library on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty for libraries"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty for libraries"),
addLibraries: []string{cls[1].GetPublicId()},
resultLibraryIds: []string{cls[1].GetPublicId()},
},
{
name: "Add library on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "populated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
addLibraries: []string{cls[1].GetPublicId()},
resultLibraryIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
{
name: "Add duplicated libraries on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "duplicated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
addLibraries: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultLibraryIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
@@ -1833,7 +1835,7 @@ func TestAddTargetLibraries(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test")
failCases := []struct {
name string
@@ -1919,32 +1921,32 @@ func TestSetTargetLibraries(t *testing.T) {
setCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
setLibraries []string
resultLibraryIds []string
resultLibraries []*pb.CredentialLibrary
}{
{
name: "Set on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
setLibraries: []string{cls[1].GetPublicId()},
resultLibraryIds: []string{cls[1].GetPublicId()},
},
{
name: "Set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
setLibraries: []string{cls[1].GetPublicId()},
resultLibraryIds: []string{cls[1].GetPublicId()},
},
{
name: "Set duplicate libraries on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
setLibraries: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultLibraryIds: []string{cls[1].GetPublicId()},
},
{
name: "Set empty on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
setLibraries: []string{},
resultLibraryIds: nil,
},
@@ -1978,7 +1980,7 @@ func TestSetTargetLibraries(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test name")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test name")
failCases := []struct {
name string
@@ -2045,26 +2047,26 @@ func TestRemoveTargetLibraries(t *testing.T) {
removeCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
removeLibs []string
resultLibIds []string
wantErr bool
}{
{
name: "Remove from empty",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
removeLibs: []string{cls[1].GetPublicId()},
wantErr: true,
},
{
name: "Remove 1 of 2 libraries",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
removeLibs: []string{cls[1].GetPublicId()},
resultLibIds: []string{cls[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 libraries",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
removeLibs: []string{
cls[1].GetPublicId(), cls[1].GetPublicId(),
},
@@ -2072,7 +2074,7 @@ func TestRemoveTargetLibraries(t *testing.T) {
},
{
name: "Remove all libraries from target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
removeLibs: []string{
cls[0].GetPublicId(), cls[1].GetPublicId(),
},
@@ -2099,7 +2101,7 @@ func TestRemoveTargetLibraries(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "testing")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "testing")
failCases := []struct {
name string
@@ -2181,25 +2183,25 @@ func TestAddTargetSources(t *testing.T) {
addCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
addSources []string
resultSourceIds []string
}{
{
name: "Add source on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty for sources"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty for sources"),
addSources: []string{cls[1].GetPublicId()},
resultSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Add source on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "populated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
addSources: []string{cls[1].GetPublicId()},
resultSourceIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
{
name: "Add duplicated sources on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "duplicated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
addSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultSourceIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
@@ -2230,7 +2232,7 @@ func TestAddTargetSources(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test")
failCases := []struct {
name string
@@ -2316,32 +2318,32 @@ func TestSetTargetCredentialSources(t *testing.T) {
setCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
setCredentialSources []string
resultCredentialSourceIds []string
resultCredentialSources []*pb.CredentialLibrary
}{
{
name: "Set on empty target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
setCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Set on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
setCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Set duplicate sources on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
setCredentialSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Set empty on populated target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
setCredentialSources: []string{},
resultCredentialSourceIds: nil,
},
@@ -2375,7 +2377,7 @@ func TestSetTargetCredentialSources(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test name")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test name")
failCases := []struct {
name string
@@ -2442,26 +2444,26 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
removeCases := []struct {
name string
tar *target.TcpTarget
tar *tcp.Target
removeCredentialSources []string
resultCredentialSourceIds []string
wantErr bool
}{
{
name: "Remove from empty",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "empty"),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "empty"),
removeCredentialSources: []string{cls[1].GetPublicId()},
wantErr: true,
},
{
name: "Remove 1 of 2 sources",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
removeCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 sources",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
removeCredentialSources: []string{
cls[1].GetPublicId(), cls[1].GetPublicId(),
},
@@ -2469,7 +2471,7 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
},
{
name: "Remove all sources from target",
tar: target.TestTcpTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
removeCredentialSources: []string{
cls[0].GetPublicId(), cls[1].GetPublicId(),
},
@@ -2496,7 +2498,7 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
})
}
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "testing")
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "testing")
failCases := []struct {
name string
@@ -2622,9 +2624,9 @@ func TestAuthorizeSession(t *testing.T) {
atRepoFn,
serversRepoFn,
kms,
auth.RequestInfo{
&authpb.RequestInfo{
Token: at.GetToken(),
TokenFormat: auth.AuthTokenTypeBearer,
TokenFormat: uint32(auth.AuthTokenTypeBearer),
PublicId: at.GetPublicId(),
})
@@ -2635,6 +2637,7 @@ func TestAuthorizeSession(t *testing.T) {
s, err := targets.NewService(ctx, kms, repoFn, iamRepoFn, serversRepoFn, sessionRepoFn, pluginHostRepoFn, staticHostRepoFn, credentialRepoFn)
require.NoError(t, err)
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), "test")
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
shs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
@@ -2687,7 +2690,6 @@ func TestAuthorizeSession(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), tc.name)
apiTar, err := s.AddTargetHostSets(ctx, &pbs.AddTargetHostSetsRequest{
Id: tar.GetPublicId(),
Version: tar.GetVersion(),
@@ -2834,9 +2836,9 @@ func TestAuthorizeSession_Errors(t *testing.T) {
atRepoFn,
serversRepoFn,
kms,
auth.RequestInfo{
&authpb.RequestInfo{
Token: at.GetToken(),
TokenFormat: auth.AuthTokenTypeBearer,
TokenFormat: uint32(auth.AuthTokenTypeBearer),
PublicId: at.GetPublicId(),
})
r := iam.TestRole(t, conn, proj.GetPublicId())
@@ -2848,7 +2850,7 @@ func TestAuthorizeSession_Errors(t *testing.T) {
sec, tok := v.CreateToken(t, vault.WithPolicies([]string{"default", "database"}))
store := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor)
workerExists := func(tar *target.TcpTarget) (version uint32) {
workerExists := func(tar *tcp.Target) (version uint32) {
workerService := workers.NewWorkerServiceServer(serversRepoFn, sessionRepoFn, &sync.Map{}, kms)
_, err := workerService.Status(context.Background(), &spbs.StatusRequest{
Worker: &spb.Server{
@@ -2860,7 +2862,7 @@ func TestAuthorizeSession_Errors(t *testing.T) {
return tar.GetVersion()
}
hostSetNoHostExists := func(tar *target.TcpTarget) (version uint32) {
hostSetNoHostExists := func(tar *tcp.Target) (version uint32) {
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
@@ -2873,7 +2875,7 @@ func TestAuthorizeSession_Errors(t *testing.T) {
return tr.GetItem().GetVersion()
}
hostExists := func(tar *target.TcpTarget) (version uint32) {
hostExists := func(tar *tcp.Target) (version uint32) {
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
@@ -2887,7 +2889,7 @@ func TestAuthorizeSession_Errors(t *testing.T) {
return apiTar.GetItem().GetVersion()
}
libraryExists := func(tar *target.TcpTarget) (version uint32) {
libraryExists := func(tar *tcp.Target) (version uint32) {
credService, err := credentiallibraries.NewService(credentialRepoFn, iamRepoFn)
require.NoError(t, err)
clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credpb.CredentialLibrary{
@@ -2909,7 +2911,7 @@ func TestAuthorizeSession_Errors(t *testing.T) {
return tr.GetItem().GetVersion()
}
misConfiguredlibraryExists := func(tar *target.TcpTarget) (version uint32) {
misConfiguredlibraryExists := func(tar *tcp.Target) (version uint32) {
credService, err := credentiallibraries.NewService(credentialRepoFn, iamRepoFn)
require.NoError(t, err)
clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credpb.CredentialLibrary{
@@ -2933,33 +2935,33 @@ func TestAuthorizeSession_Errors(t *testing.T) {
cases := []struct {
name string
setup []func(*target.TcpTarget) uint32
setup []func(*tcp.Target) uint32
err bool
}{
{
// This one must be run first since it relies on the DB not having any worker details
name: "no worker",
setup: []func(tcpTarget *target.TcpTarget) uint32{hostExists, libraryExists},
setup: []func(tcpTarget *tcp.Target) uint32{hostExists, libraryExists},
err: true,
},
{
name: "success",
setup: []func(tcpTarget *target.TcpTarget) uint32{workerExists, hostExists, libraryExists},
setup: []func(tcpTarget *tcp.Target) uint32{workerExists, hostExists, libraryExists},
},
{
name: "no hosts",
setup: []func(tcpTarget *target.TcpTarget) uint32{workerExists, hostSetNoHostExists, libraryExists},
setup: []func(tcpTarget *tcp.Target) uint32{workerExists, hostSetNoHostExists, libraryExists},
err: true,
},
{
name: "bad library configuration",
setup: []func(tcpTarget *target.TcpTarget) uint32{workerExists, hostExists, misConfiguredlibraryExists},
setup: []func(tcpTarget *tcp.Target) uint32{workerExists, hostExists, misConfiguredlibraryExists},
err: true,
},
}
for i, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), fmt.Sprintf("test-%d", i))
tar := tcp.TestTarget(t, conn, proj.GetPublicId(), fmt.Sprintf("test-%d", i))
for _, fn := range tc.setup {
ver := fn(tar)
@@ -183,7 +183,7 @@ func ValidId(i Id, prefixes ...string) bool {
continue
}
id = strings.TrimPrefix(id, prefix)
if !reInvalidID.Match([]byte(id)) {
if !reInvalidID.MatchString(id) {
return true
}
}
@@ -15,10 +15,10 @@ import (
func errorIncludesFields(t *testing.T, err error, wantFields []string) {
t.Helper()
var apiErr *apiError
var apiErr *ApiError
require.True(t, errors.As(err, &apiErr))
var gotFields []string
for _, d := range apiErr.inner.GetDetails().GetRequestFields() {
for _, d := range apiErr.Inner.GetDetails().GetRequestFields() {
gotFields = append(gotFields, d.GetName())
}
assert.ElementsMatch(t, gotFields, wantFields)
+207
View File
@@ -0,0 +1,207 @@
package controller
import (
"context"
"fmt"
"net/http"
"reflect"
"github.com/hashicorp/boundary/internal/errors"
pb "github.com/hashicorp/boundary/internal/gen/controller/api"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
pberrors "github.com/hashicorp/boundary/internal/gen/errors"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/requests"
"github.com/hashicorp/boundary/internal/servers/controller/auth"
"github.com/hashicorp/boundary/internal/servers/controller/common"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"github.com/mr-tron/base58"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
const (
requestInfoMdKey = "request-info"
// domainErrHeader defines an http header for encoded domain errors from the
// grpc server.
domainErrHeader = "x-domain-err"
// apiErrHeader defines an http header for encoded api errors from the
// grpc server.
apiErrHeader = "x-api-err"
)
// requestCtxInterceptor creates an unary server interceptor that pulls grpc
// metadata into a ctx for the request. The metadata must be set in an upstream
// http handler/middleware by marshalling a RequestInfo protobuf into the
// requestInfoMdKey header (see: controller.wrapHandlerWithCommonFuncs).
func requestCtxInterceptor(
ctx context.Context,
iamRepoFn common.IamRepoFactory,
authTokenRepoFn common.AuthTokenRepoFactory,
serversRepoFn common.ServersRepoFactory,
kms *kms.Kms,
ticket string,
) (grpc.UnaryServerInterceptor, error) {
const op = "controller.requestCtxInterceptor"
if iamRepoFn == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing iam repo function")
}
if authTokenRepoFn == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing auth token repo function")
}
if serversRepoFn == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing servers repo function")
}
if kms == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing kms")
}
if ticket == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing ticket")
}
// Authorization unary interceptor function to handle authorize per RPC call
return func(interceptorCtx context.Context,
req interface{},
_ *grpc.UnaryServerInfo,
handler grpc.UnaryHandler) (interface{}, error) {
md, ok := metadata.FromIncomingContext(interceptorCtx)
if !ok {
return nil, errors.New(interceptorCtx, errors.Internal, op, "No metadata")
}
values := md.Get(requestInfoMdKey)
if len(values) == 0 {
return nil, errors.New(interceptorCtx, errors.Internal, op, "Missing request metadata")
}
if len(values) > 1 {
return nil, errors.New(interceptorCtx, errors.Internal, op, fmt.Sprintf("expected 1 value for %s metadata and got %d", requestInfoMdKey, len(values)))
}
decoded, err := base58.FastBase58Decoding(values[0])
if err != nil {
return nil, errors.Wrap(interceptorCtx, err, op, errors.WithCode(errors.Internal), errors.WithMsg("unable to decode request info"))
}
var requestInfo authpb.RequestInfo
if err := proto.Unmarshal(decoded, &requestInfo); err != nil {
return nil, errors.Wrap(interceptorCtx, err, op, errors.WithCode(errors.Internal), errors.WithMsg("unable to unmarshal request info"))
}
switch {
case requestInfo.Ticket == "":
return nil, errors.New(interceptorCtx, errors.Internal, op, "Invalid context (missing ticket)")
case requestInfo.Ticket != ticket:
return nil, errors.New(interceptorCtx, errors.Internal, op, "Invalid context (bad ticket)")
}
interceptorCtx = auth.NewVerifierContext(interceptorCtx, iamRepoFn, authTokenRepoFn, serversRepoFn, kms, &requestInfo)
// Add general request information to the context. The information from
// the auth verifier context is pretty specifically curated to
// authentication/authorization verification so this is more
// general-purpose.
//
// We could use requests.NewRequestContext but this saves an immediate
// lookup.
interceptorCtx = context.WithValue(interceptorCtx, requests.ContextRequestInformationKey, &requests.RequestContext{
Path: requestInfo.Path,
Method: requestInfo.Method,
})
// Calls the handler
h, err := handler(interceptorCtx, req)
return h, err // not convinced we want to wrap every error and turn them into domain errors...
}, nil
}
func errorInterceptor(
_ context.Context,
) grpc.UnaryServerInterceptor {
const op = "controller.errorInterceptor"
return func(interceptorCtx context.Context,
req interface{},
_ *grpc.UnaryServerInfo,
handler grpc.UnaryHandler) (interface{}, error) {
// call the handler...
h, handlerErr := handler(interceptorCtx, req)
// if there's an error and it's a domain err, then encode it into the
if handlerErr != nil {
var domainErr *errors.Err
isDomainErr := errors.As(handlerErr, &domainErr)
if isDomainErr {
pbErr := errors.ToPbErrors(domainErr)
var buf []byte
var err error
if buf, err = proto.Marshal(pbErr); err != nil {
return h, status.Errorf(codes.Internal, "unable to marshal domain error: %s", err)
}
if err := grpc.SetHeader(interceptorCtx, metadata.Pairs(domainErrHeader, base58.FastBase58Encoding(buf))); err != nil {
return h, status.Errorf(codes.Internal, "unable to set domain error header: %s", err)
}
return h, handlerErr
}
var apiErr *handlers.ApiError
isApiError := errors.As(handlerErr, &apiErr)
if isApiError {
pbErr := &pberrors.ApiError{
ApiError: apiErr.Inner,
Status: apiErr.Status,
}
var buf []byte
var err error
if buf, err = proto.Marshal(pbErr); err != nil {
return h, status.Errorf(codes.Internal, "unable to marshal api error: %s", err)
}
if err := grpc.SetHeader(interceptorCtx, metadata.Pairs(apiErrHeader, base58.FastBase58Encoding(buf))); err != nil {
return h, status.Errorf(codes.Internal, "unable to set api error header: %s", err)
}
return h, handlerErr
}
}
return h, handlerErr
}
}
func statusCodeInterceptor(
_ context.Context,
) grpc.UnaryServerInterceptor {
const op = "controller.statusCodeInterceptor"
return func(interceptorCtx context.Context,
req interface{},
_ *grpc.UnaryServerInfo,
handler grpc.UnaryHandler) (interface{}, error) {
// call the handler...
h, handlerErr := handler(interceptorCtx, req)
// if a service handler returns nil, nil then we want to single a 204
// response to the proxy with no resp msg
if isNil(h) && handlerErr == nil {
if err := handlers.SetStatusCode(interceptorCtx, http.StatusNoContent); err != nil {
return &pb.EmptyResponse{}, err
}
return &pb.EmptyResponse{}, nil
}
return h, handlerErr
}
}
func isNil(i interface{}) bool {
if i == nil {
return true
}
switch reflect.TypeOf(i).Kind() {
case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice:
return reflect.ValueOf(i).IsNil()
}
return false
}
@@ -0,0 +1,453 @@
package controller
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
pb_api "github.com/hashicorp/boundary/internal/gen/controller/api"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
pberrors "github.com/hashicorp/boundary/internal/gen/errors"
"github.com/hashicorp/boundary/internal/gen/testing/interceptor"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/servers"
"github.com/hashicorp/boundary/internal/servers/controller/auth"
"github.com/hashicorp/boundary/internal/servers/controller/common"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"github.com/mr-tron/base58"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
)
func Test_requestCtxInterceptor(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
atRepoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(rw, rw, kmsCache)
}
serversRepoFn := func() (*servers.Repository, error) {
return servers.NewRepository(rw, rw, kmsCache)
}
validGatewayTicket := "valid-ticket"
o, _ := iam.TestScopes(t, iamRepo)
at := authtoken.TestAuthToken(t, conn, kmsCache, o.GetPublicId())
encToken, err := authtoken.EncryptToken(context.Background(), kmsCache, o.GetPublicId(), at.GetPublicId(), at.GetToken())
require.NoError(t, err)
tokValue := at.GetPublicId() + "_" + encToken
newReqCtx := func(gwTicket string) context.Context {
req := httptest.NewRequest("GET", "http://127.0.0.1/v1/scopes/o_1", nil)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tokValue))
// Add values for authn/authz checking
requestInfo := authpb.RequestInfo{
Path: req.URL.Path,
Method: req.Method,
}
requestInfo.PublicId, requestInfo.EncryptedToken, requestInfo.TokenFormat = auth.GetTokenFromRequest(context.TODO(), kmsCache, req)
requestInfo.Ticket = gwTicket // allows the grpc-gateway to verify the request info came from it's in-memory companion http proxy
marshalledRequestInfo, err := proto.Marshal(&requestInfo)
require.NoError(t, err)
md := metadata.Pairs(requestInfoMdKey, base58.FastBase58Encoding(marshalledRequestInfo))
mdCtx := metadata.NewIncomingContext(context.Background(), md)
md, ok := metadata.FromIncomingContext(mdCtx)
require.True(t, ok)
require.NotNil(t, md)
return mdCtx
}
factoryCtx := context.Background()
returnCtxHandler := func(ctx context.Context, req interface{}) (interface{}, error) {
return ctx, nil
}
tests := []struct {
name string
requestCtx context.Context
iamRepoFn common.IamRepoFactory
authTokenRepoFn common.AuthTokenRepoFactory
serversRepoFn common.ServersRepoFactory
kms *kms.Kms
ticket string
wantFactoryErr bool
wantFactoryErrMatch *errors.Template
wantFactoryErrContains string
wantRequestErr bool
wantRequestErrMatch *errors.Template
wantRequestErrContains string
}{
{
name: "missing-iam-repo",
requestCtx: newReqCtx(validGatewayTicket),
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
wantFactoryErr: true,
wantFactoryErrMatch: errors.T(errors.InvalidParameter),
wantFactoryErrContains: "missing iam repo",
},
{
name: "missing-at-repo",
requestCtx: newReqCtx(validGatewayTicket),
iamRepoFn: iamRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
wantFactoryErr: true,
wantFactoryErrMatch: errors.T(errors.InvalidParameter),
wantFactoryErrContains: "missing auth token repo",
},
{
name: "missing-servers-repo",
requestCtx: newReqCtx(validGatewayTicket),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
kms: kmsCache,
wantFactoryErr: true,
wantFactoryErrMatch: errors.T(errors.InvalidParameter),
wantFactoryErrContains: "missing servers repo function",
},
{
name: "missing-kms",
requestCtx: newReqCtx(validGatewayTicket),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
wantFactoryErr: true,
wantFactoryErrMatch: errors.T(errors.InvalidParameter),
wantFactoryErrContains: "missing kms",
},
{
name: "missing-factory-ticket",
requestCtx: newReqCtx(validGatewayTicket),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
wantFactoryErr: true,
wantFactoryErrMatch: errors.T(errors.InvalidParameter),
wantFactoryErrContains: "missing ticket",
},
{
name: "missing-metadata",
requestCtx: context.Background(),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
ticket: validGatewayTicket,
wantRequestErr: true,
wantRequestErrMatch: errors.T(errors.Internal),
wantRequestErrContains: "No metadata",
},
{
name: "missing-request-info-metadata",
requestCtx: func() context.Context {
md := metadata.Pairs("greeter-md", "hello")
return metadata.NewIncomingContext(context.Background(), md)
}(),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
ticket: validGatewayTicket,
wantRequestErr: true,
wantRequestErrMatch: errors.T(errors.Internal),
wantRequestErrContains: "Missing request metadata",
},
{
name: "too-many-request-info-metadata",
requestCtx: func() context.Context {
md := metadata.Pairs(requestInfoMdKey, "first", requestInfoMdKey, "second")
return metadata.NewIncomingContext(context.Background(), md)
}(),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
ticket: validGatewayTicket,
wantRequestErr: true,
wantRequestErrMatch: errors.T(errors.Internal),
wantRequestErrContains: "expected 1 value",
},
{
name: "request-info-metadata-not-encoded",
requestCtx: func() context.Context {
md := metadata.Pairs(requestInfoMdKey, "hello")
return metadata.NewIncomingContext(context.Background(), md)
}(),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
ticket: validGatewayTicket,
wantRequestErr: true,
wantRequestErrMatch: errors.T(errors.Internal),
wantRequestErrContains: "unable to decode request info",
},
{
name: "request-info-metadata-not-proto",
requestCtx: func() context.Context {
md := metadata.Pairs(requestInfoMdKey, base58.FastBase58Encoding([]byte("hello")))
return metadata.NewIncomingContext(context.Background(), md)
}(),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
ticket: validGatewayTicket,
wantRequestErr: true,
wantRequestErrMatch: errors.T(errors.Internal),
wantRequestErrContains: "unable to unmarshal request info",
},
{
name: "request-info-metadata-not-proto",
requestCtx: func() context.Context {
md := metadata.Pairs(requestInfoMdKey, base58.FastBase58Encoding([]byte("hello")))
return metadata.NewIncomingContext(context.Background(), md)
}(),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
ticket: validGatewayTicket,
wantRequestErr: true,
wantRequestErrMatch: errors.T(errors.Internal),
wantRequestErrContains: "unable to unmarshal request info",
},
{
name: "missing-request-ticket",
requestCtx: newReqCtx(""),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
ticket: "validGatewayTicket",
wantRequestErr: true,
wantRequestErrMatch: errors.T(errors.Internal),
wantRequestErrContains: "Invalid context (missing ticket)",
},
{
name: "bad-ticket",
requestCtx: newReqCtx("bad-ticket"),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
ticket: "validGatewayTicket",
wantRequestErr: true,
wantRequestErrMatch: errors.T(errors.Internal),
wantRequestErrContains: "Invalid context (bad ticket)",
},
{
name: "valid",
requestCtx: newReqCtx(validGatewayTicket),
iamRepoFn: iamRepoFn,
authTokenRepoFn: atRepoFn,
serversRepoFn: serversRepoFn,
kms: kmsCache,
ticket: validGatewayTicket,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
interceptor, err := requestCtxInterceptor(factoryCtx, tt.iamRepoFn, tt.authTokenRepoFn, tt.serversRepoFn, tt.kms, tt.ticket)
if tt.wantFactoryErr {
require.Error(err)
assert.Nil(interceptor)
if tt.wantFactoryErrMatch != nil {
assert.Truef(errors.Match(tt.wantFactoryErrMatch, err), "want err code: %q got: %q", tt.wantFactoryErrMatch.Code, err)
}
if tt.wantFactoryErrContains != "" {
assert.Contains(err.Error(), tt.wantFactoryErrContains)
}
return
}
require.NoError(err)
assert.NotNil(interceptor)
info := &grpc.UnaryServerInfo{
FullMethod: "FakeMethod",
}
retCtx, err := interceptor(tt.requestCtx, nil, info, returnCtxHandler)
if tt.wantRequestErr {
require.Error(err)
assert.Nil(retCtx)
if tt.wantRequestErrMatch != nil {
assert.Truef(errors.Match(tt.wantRequestErrMatch, err), "want err code: %q got: %q", tt.wantRequestErrMatch.Code, err)
}
if tt.wantRequestErrContains != "" {
assert.Contains(err.Error(), tt.wantRequestErrContains)
}
return
}
require.NoError(err)
verifyResults := auth.Verify(retCtx.(context.Context))
assert.NotEmpty(verifyResults)
})
}
}
func Test_errorInterceptor(t *testing.T) {
ctx := context.Background()
tests := []struct {
name string
factoryCtx context.Context
wantRequestErr bool
wantDomainErr bool
wantApiErr bool
}{
{
name: "domain-error",
factoryCtx: ctx,
wantRequestErr: true,
wantDomainErr: true,
},
{
name: "api-error",
factoryCtx: ctx,
wantRequestErr: true,
wantApiErr: true,
},
{
name: "success",
factoryCtx: ctx,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
require.Falsef(tt.wantApiErr && tt.wantDomainErr, "tests can't require both wantApiErr and wantDomainErr")
errInterceptor := errorInterceptor(tt.factoryCtx)
client := startTestGreeterService(t, &testGreeter{}, errInterceptor)
var header metadata.MD
resp, err := client.SayHello(
context.Background(),
&interceptor.SayHelloRequest{Name: tt.name},
grpc.Header(&header),
)
if tt.wantRequestErr {
require.Error(err)
domainHdr := header.Get(domainErrHeader)
apiErrHdr := header.Get(apiErrHeader)
require.Error(err)
assert.Nil(resp)
if tt.wantDomainErr {
require.Len(domainHdr, 1)
assert.Len(apiErrHdr, 0)
decoded, err := base58.FastBase58Decoding(domainHdr[0])
require.NoError(err)
var pbErr pberrors.Err
err = proto.Unmarshal(decoded, &pbErr)
require.NoError(err)
}
if tt.wantApiErr {
require.Len(apiErrHdr, 1)
assert.Len(domainHdr, 0)
decoded, err := base58.FastBase58Decoding(apiErrHdr[0])
require.NoError(err)
var pbErr pberrors.ApiError
err = proto.Unmarshal(decoded, &pbErr)
require.NoError(err)
}
return
}
require.NoError(err)
})
}
}
func Test_statusCodeInterceptor(t *testing.T) {
ctx := context.Background()
tests := []struct {
name string
wantStatusCode int
wantErr bool
}{
{
name: "nil-nil",
wantStatusCode: http.StatusNoContent,
},
{
name: "nil-err",
wantErr: true,
},
{
name: "hello",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
statusInterceptor := statusCodeInterceptor(ctx)
client := startTestGreeterService(t, &testGreeter{}, statusInterceptor)
var header metadata.MD
_, err := client.SayHello(
context.Background(),
&interceptor.SayHelloRequest{Name: tt.name},
grpc.Header(&header),
)
if tt.wantErr {
assert.Error(err)
}
statusHdr := header.Get(handlers.StatusCodeHeader)
if tt.wantStatusCode > 0 {
require.Len(statusHdr, 1)
code, err := strconv.Atoi(statusHdr[0])
require.NoError(err)
assert.Equal(tt.wantStatusCode, code)
} else {
require.Len(statusHdr, 0)
}
})
}
}
type testGreeter struct {
interceptor.UnimplementedGreeterServiceServer
}
func (g *testGreeter) SayHello(ctx context.Context, req *interceptor.SayHelloRequest) (*interceptor.SayHelloResponse, error) {
const op = "SayHello"
switch req.GetName() {
case "api-error":
return &interceptor.SayHelloResponse{}, &handlers.ApiError{
Status: http.StatusInternalServerError,
Inner: &pb_api.Error{
Kind: "internal",
Op: op,
Message: "api error msg",
},
}
case "domain-error":
return &interceptor.SayHelloResponse{Message: "hello"}, errors.New(ctx, errors.Internal, op, "domain error msg")
case "nil-nil":
return nil, nil
case "nil-err":
return nil, errors.New(ctx, errors.Internal, op, "nil response error msg")
default:
return &interceptor.SayHelloResponse{Message: "hello"}, nil
}
}
+28 -1
View File
@@ -12,6 +12,7 @@ import (
"sync"
"time"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/cmd/base"
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
"github.com/hashicorp/boundary/internal/libs/alpnmux"
@@ -20,10 +21,16 @@ import (
"google.golang.org/grpc"
)
func (c *Controller) startListeners() error {
func (c *Controller) startListeners(ctx context.Context) error {
servers := make([]func(), 0, len(c.conf.Listeners))
configureForAPI := func(ln *base.ServerListener) error {
var err error
if c.gatewayServer, c.gatewayTicket, err = newGatewayServer(ctx, c.IamRepoFn, c.AuthTokenRepoFn, c.ServersRepoFn, c.kms); err != nil {
return err
}
c.gatewayMux = newGatewayMux()
handler, err := c.handler(HandlerProperties{
ListenerConfig: ln.Config,
CancelCtx: c.baseContext,
@@ -134,6 +141,11 @@ func (c *Controller) startListeners() error {
return nil
}
c.gatewayListener, _ = newGatewayListener()
servers = append(servers, func() {
go c.gatewayServer.Serve(c.gatewayListener)
})
for _, ln := range c.conf.Listeners {
var err error
for _, purpose := range ln.Config.Purpose {
@@ -184,6 +196,21 @@ func (c *Controller) stopListeners(serversOnly bool) error {
}
}()
}
if c.gatewayServer != nil {
serverWg.Add(1)
go func() {
defer serverWg.Done()
shutdownKill, shutdownKillCancel := context.WithTimeout(c.baseContext, globals.DefaultMaxRequestDuration)
defer shutdownKillCancel()
go func() {
<-shutdownKill.Done()
c.gatewayServer.Stop()
}()
c.gatewayServer.GracefulStop()
}()
}
serverWg.Wait()
if serversOnly {
return nil
+41
View File
@@ -10,6 +10,7 @@ import (
"testing"
"time"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/api/authtokens"
@@ -18,6 +19,7 @@ import (
"github.com/hashicorp/boundary/internal/cmd/config"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/schema"
"github.com/hashicorp/boundary/internal/gen/testing/interceptor"
"github.com/hashicorp/boundary/internal/host/plugin"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/intglobals"
@@ -28,6 +30,9 @@ import (
wrapping "github.com/hashicorp/go-kms-wrapping"
"github.com/hashicorp/go-secure-stdlib/base62"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/test/bufconn"
)
const (
@@ -718,3 +723,39 @@ func (tc *TestController) WaitForNextWorkerStatusUpdate(workerId string) error {
event.WriteSysEvent(ctx, op, "waiting for next status report from worker received successfully", "worker", workerId)
return nil
}
// startTestGreeterService is intended to facilitate the testing of
// interceptors. You provide a greeter service that produces appropriate
// responses to test your interceptor(s). This test function will start up a
// test greeter service wrapped with the specified interceptors and return an
// initialized client for the service. The test service will be stopped/cleaned
// up after the test (or subtests) have completed.
func startTestGreeterService(t *testing.T, greeter interceptor.GreeterServiceServer, interceptors ...grpc.UnaryServerInterceptor) interceptor.GreeterServiceClient {
t.Helper()
require := require.New(t)
dialCtx := context.Background()
buffer := 1024 * 1024
listener := bufconn.Listen(buffer)
s := grpc.NewServer(
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(interceptors...)),
)
interceptor.RegisterGreeterServiceServer(s, greeter)
go func() {
err := s.Serve(listener)
require.NoError(err)
}()
conn, _ := grpc.DialContext(dialCtx, "", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
return listener.Dial()
}), grpc.WithInsecure())
t.Cleanup(func() {
listener.Close()
s.Stop()
})
client := interceptor.NewGreeterServiceClient(conn)
return client
}
-12
View File
@@ -1,18 +1,6 @@
package servers
const (
serverUpsertQuery = `
insert into server
(private_id, type, description, address, update_time)
values
(@private_id, @type, @description, @address, now())
on conflict on constraint server_pkey
do update set
type = @type,
description = @description,
address = @address,
update_time = now();
`
deleteWhereCreateTimeSql = `create_time < ?`
deleteTagsSql = `server_id = ?`
)
+7 -11
View File
@@ -2,7 +2,6 @@ package servers
import (
"context"
"database/sql"
"fmt"
"time"
@@ -138,7 +137,7 @@ func (r *Repository) UpsertServer(ctx context.Context, server *Server, opt ...Op
opts := getOpts(opt...)
var rowsUpdated int
var rowsUpdated int64
var controllers []*Server
_, err := r.writer.DoTx(
ctx,
@@ -146,14 +145,11 @@ func (r *Repository) UpsertServer(ctx context.Context, server *Server, opt ...Op
db.ExpBackoff{},
func(read db.Reader, w db.Writer) error {
var err error
rowsUpdated, err = w.Exec(ctx,
serverUpsertQuery,
[]interface{}{
sql.Named("private_id", server.PrivateId),
sql.Named("type", server.Type),
sql.Named("description", server.Description),
sql.Named("address", server.Address),
})
onConflict := &db.OnConflict{
Target: db.Constraint("server_pkey"),
Action: append(db.SetColumns([]string{"type", "description", "address"}), db.SetColumnValues(map[string]interface{}{"update_time": "now()"})...),
}
err = w.Create(ctx, server, db.WithOnConflict(onConflict), db.WithReturnRowsAffected(&rowsUpdated))
if err != nil {
return errors.Wrap(ctx, err, op+":Upsert")
}
@@ -208,7 +204,7 @@ func (r *Repository) UpsertServer(ctx context.Context, server *Server, opt ...Op
return nil, db.NoRowsAffected, err
}
return controllers, rowsUpdated, nil
return controllers, int(rowsUpdated), nil
}
type RecoveryNonce struct {
+2 -1
View File
@@ -35,9 +35,10 @@ type Server struct {
// private ID and name to be identical, and there is currently no reason we
// can think of to allow a given server's name to match another within the
// same cluster. So we simply use the private ID and deprecate this.
// @inject_tag: `gorm:"-"`
//
// Deprecated: Do not use.
Name string `protobuf:"bytes,30,opt,name=name,proto3" json:"name,omitempty"`
Name string `protobuf:"bytes,30,opt,name=name,proto3" json:"name,omitempty" gorm:"-"`
// Description of the resource
Description string `protobuf:"bytes,40,opt,name=description,proto3" json:"description,omitempty"`
// Address for the server
+4 -3
View File
@@ -15,7 +15,8 @@ import (
"github.com/hashicorp/boundary/internal/host/static"
staticStore "github.com/hashicorp/boundary/internal/host/static/store"
"github.com/hashicorp/boundary/internal/target"
targetStore "github.com/hashicorp/boundary/internal/target/store"
"github.com/hashicorp/boundary/internal/target/tcp"
tcpStore "github.com/hashicorp/boundary/internal/target/tcp/store"
wrapping "github.com/hashicorp/go-kms-wrapping"
"github.com/jackc/pgconn"
"google.golang.org/protobuf/types/known/timestamppb"
@@ -1314,8 +1315,8 @@ func TestRepository_CancelSessionViaFKNull(t *testing.T) {
cancelFk: func() cancelFk {
s := setupFn()
t := &target.TcpTarget{
TcpTarget: &targetStore.TcpTarget{
t := &tcp.Target{
Target: &tcpStore.Target{
PublicId: s.TargetId,
},
}
+2 -1
View File
@@ -15,6 +15,7 @@ import (
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/servers"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
wrapping "github.com/hashicorp/go-kms-wrapping"
"github.com/hashicorp/go-secure-stdlib/base62"
"github.com/hashicorp/go-uuid"
@@ -132,7 +133,7 @@ func TestSessionParams(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, iamR
sets := static.TestSets(t, conn, cats[0].PublicId, 1)
_ = static.TestSetMembers(t, conn, sets[0].PublicId, hosts)
tcpTarget := target.TestTcpTarget(t, conn, proj.PublicId, "test target")
tcpTarget := tcp.TestTarget(t, conn, proj.PublicId, "test target")
kms := kms.TestKms(t, conn, wrapper)
targetRepo, err := target.NewRepository(rw, rw, kms)
+5 -4
View File
@@ -1,10 +1,11 @@
package target
package target_test
import (
"testing"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -18,7 +19,7 @@ func TestCredentialLibrary_New(t *testing.T) {
tests := []struct {
name string
args args
want *CredentialLibrary
want *target.CredentialLibrary
wantErr errors.Code
}{
{
@@ -41,7 +42,7 @@ func TestCredentialLibrary_New(t *testing.T) {
targetId: "targ_0000000",
libraryId: "lib_0000000",
},
want: &CredentialLibrary{
want: &target.CredentialLibrary{
CredentialLibrary: &store.CredentialLibrary{
TargetId: "targ_0000000",
CredentialLibraryId: "lib_0000000",
@@ -54,7 +55,7 @@ func TestCredentialLibrary_New(t *testing.T) {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
got, err := NewCredentialLibrary(tt.args.targetId, tt.args.libraryId)
got, err := target.NewCredentialLibrary(tt.args.targetId, tt.args.libraryId)
if tt.wantErr != 0 {
assert.Truef(errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err)
assert.Nil(got)
+7
View File
@@ -0,0 +1,7 @@
package target
// Expose functions for use in tests.
var (
AllocTargetView = allocTargetView
TargetsViewDefaultTable = targetsViewDefaultTable
)
-7
View File
@@ -44,13 +44,6 @@ func NewTargetHostSet(targetId, hostSetId string, _ ...Option) (*TargetHostSet,
return t, nil
}
// allocTargetHostSet will allocate a target host set
func allocTargetHostSet() TargetHostSet {
return TargetHostSet{
TargetHostSet: &store.TargetHostSet{},
}
}
// Clone creates a clone of the target host set
func (t *TargetHostSet) Clone() interface{} {
cp := proto.Clone(t.TargetHostSet)
-19
View File
@@ -1,19 +0,0 @@
package target
import (
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
)
const (
TcpTargetPrefix = "ttcp"
)
func newTcpTargetId() (string, error) {
const op = "target.newTcpTargetId"
id, err := db.NewPublicId(TcpTargetPrefix)
if err != nil {
return "", errors.WrapDeprecated(err, op)
}
return id, nil
}
-18
View File
@@ -1,18 +0,0 @@
package target
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_Ids(t *testing.T) {
t.Parallel()
t.Run("tcp", func(t *testing.T) {
id, err := newTcpTargetId()
require.NoError(t, err)
assert.True(t, strings.HasPrefix(id, TcpTargetPrefix+"_"))
})
}
+54 -50
View File
@@ -1,9 +1,13 @@
package target
import "time"
import (
"time"
// getOpts - iterate the inbound Options and return a struct
func getOpts(opt ...Option) options {
"github.com/hashicorp/boundary/internal/types/subtypes"
)
// GetOpts - iterate the inbound Options and return a struct
func GetOpts(opt ...Option) options {
opts := getDefaultOptions()
for _, o := range opt {
o(&opts)
@@ -16,54 +20,54 @@ type Option func(*options)
// options = how options are represented
type options struct {
withName string
withDescription string
withDefaultPort uint32
withLimit int
withScopeId string
withScopeIds []string
withScopeName string
withUserId string
withTargetType *TargetType
withHostSources []string
withCredentialSources []string
withSessionMaxSeconds uint32
withSessionConnectionLimit int32
withPublicId string
withWorkerFilter string
WithName string
WithDescription string
WithDefaultPort uint32
WithLimit int
WithScopeId string
WithScopeIds []string
WithScopeName string
WithUserId string
WithType subtypes.Subtype
WithHostSources []string
WithCredentialSources []string
WithSessionMaxSeconds uint32
WithSessionConnectionLimit int32
WithPublicId string
WithWorkerFilter string
}
func getDefaultOptions() options {
return options{
withName: "",
withDescription: "",
withLimit: 0,
withDefaultPort: 0,
withScopeId: "",
withScopeIds: nil,
withScopeName: "",
withUserId: "",
withTargetType: nil,
withHostSources: nil,
withCredentialSources: nil,
withSessionMaxSeconds: uint32((8 * time.Hour).Seconds()),
withSessionConnectionLimit: 1,
withPublicId: "",
withWorkerFilter: "",
WithName: "",
WithDescription: "",
WithLimit: 0,
WithDefaultPort: 0,
WithScopeId: "",
WithScopeIds: nil,
WithScopeName: "",
WithUserId: "",
WithType: "",
WithHostSources: nil,
WithCredentialSources: nil,
WithSessionMaxSeconds: uint32((8 * time.Hour).Seconds()),
WithSessionConnectionLimit: 1,
WithPublicId: "",
WithWorkerFilter: "",
}
}
// WithDescription provides an optional description
func WithDescription(desc string) Option {
return func(o *options) {
o.withDescription = desc
o.WithDescription = desc
}
}
// WithName provides an option to search by a friendly name
func WithName(name string) Option {
return func(o *options) {
o.withName = name
o.WithName = name
}
}
@@ -72,88 +76,88 @@ func WithName(name string) Option {
// If WithLimit == 0, then default limits are used for results.
func WithLimit(limit int) Option {
return func(o *options) {
o.withLimit = limit
o.WithLimit = limit
}
}
// WithDefaultPort provides an option to specify the default target port.
func WithDefaultPort(p uint32) Option {
return func(o *options) {
o.withDefaultPort = p
o.WithDefaultPort = p
}
}
// WithScopeId provides an option to search by a scope id
func WithScopeId(scopeId string) Option {
return func(o *options) {
o.withScopeId = scopeId
o.WithScopeId = scopeId
}
}
// WithScopeId provides an option to search by multiple scope id
func WithScopeIds(scopeIds []string) Option {
return func(o *options) {
o.withScopeIds = scopeIds
o.WithScopeIds = scopeIds
}
}
// WithScopeId provides an option to search by a scope name
func WithScopeName(scopeName string) Option {
return func(o *options) {
o.withScopeName = scopeName
o.WithScopeName = scopeName
}
}
// WithUserId provides an option to search by a user public id
func WithUserId(userId string) Option {
return func(o *options) {
o.withUserId = userId
o.WithUserId = userId
}
}
// WithTargetType provides an option to search by a target type
func WithTargetType(t TargetType) Option {
// WithType provides an option to search by a target type
func WithType(t subtypes.Subtype) Option {
return func(o *options) {
o.withTargetType = &t
o.WithType = t
}
}
// WithHostSources provides an option for providing a list of host source ids
func WithHostSources(hs []string) Option {
return func(o *options) {
o.withHostSources = hs
o.WithHostSources = hs
}
}
// WithCredentialSources provides an option for providing a list of credential source ids
func WithCredentialSources(cl []string) Option {
return func(o *options) {
o.withCredentialSources = cl
o.WithCredentialSources = cl
}
}
func WithSessionMaxSeconds(dur uint32) Option {
return func(o *options) {
o.withSessionMaxSeconds = dur
o.WithSessionMaxSeconds = dur
}
}
func WithSessionConnectionLimit(limit int32) Option {
return func(o *options) {
o.withSessionConnectionLimit = limit
o.WithSessionConnectionLimit = limit
}
}
// WithPublicId provides an optional public id
func WithPublicId(id string) Option {
return func(o *options) {
o.withPublicId = id
o.WithPublicId = id
}
}
// WithWorkerFilter provides an optional worker filter
func WithWorkerFilter(filter string) Option {
return func(o *options) {
o.withWorkerFilter = filter
o.WithWorkerFilter = filter
}
}
+34 -32
View File
@@ -3,6 +3,7 @@ package target
import (
"testing"
"github.com/hashicorp/boundary/internal/types/subtypes"
"github.com/stretchr/testify/assert"
)
@@ -11,104 +12,105 @@ func Test_GetOpts(t *testing.T) {
t.Parallel()
t.Run("WithName", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithName("test"))
opts := GetOpts(WithName("test"))
testOpts := getDefaultOptions()
testOpts.withName = "test"
testOpts.WithName = "test"
assert.Equal(opts, testOpts)
})
t.Run("WithDescription", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithDescription("test desc"))
opts := GetOpts(WithDescription("test desc"))
testOpts := getDefaultOptions()
testOpts.withDescription = "test desc"
testOpts.WithDescription = "test desc"
assert.Equal(opts, testOpts)
})
t.Run("WithLimit", func(t *testing.T) {
assert := assert.New(t)
// test default of 0
opts := getOpts()
opts := GetOpts()
testOpts := getDefaultOptions()
testOpts.withLimit = 0
testOpts.WithLimit = 0
assert.Equal(opts, testOpts)
opts = getOpts(WithLimit(-1))
opts = GetOpts(WithLimit(-1))
testOpts = getDefaultOptions()
testOpts.withLimit = -1
testOpts.WithLimit = -1
assert.Equal(opts, testOpts)
opts = getOpts(WithLimit(1))
opts = GetOpts(WithLimit(1))
testOpts = getDefaultOptions()
testOpts.withLimit = 1
testOpts.WithLimit = 1
assert.Equal(opts, testOpts)
})
t.Run("WithDefaultPort", func(t *testing.T) {
assert := assert.New(t)
// test default of 0
opts := getOpts()
opts := GetOpts()
testOpts := getDefaultOptions()
testOpts.withDefaultPort = 0
testOpts.WithDefaultPort = 0
assert.Equal(opts, testOpts)
opts = getOpts(WithDefaultPort(22))
opts = GetOpts(WithDefaultPort(22))
testOpts = getDefaultOptions()
testOpts.withDefaultPort = uint32(22)
testOpts.WithDefaultPort = uint32(22)
assert.Equal(opts, testOpts)
})
t.Run("WithUserId", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithUserId("testId"))
opts := GetOpts(WithUserId("testId"))
testOpts := getDefaultOptions()
testOpts.withUserId = "testId"
testOpts.WithUserId = "testId"
assert.Equal(opts, testOpts)
})
t.Run("WithScopeId", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithScopeId("testId"))
opts := GetOpts(WithScopeId("testId"))
testOpts := getDefaultOptions()
testOpts.withScopeId = "testId"
testOpts.WithScopeId = "testId"
assert.Equal(opts, testOpts)
})
t.Run("WithScopeName", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithScopeName("testName"))
opts := GetOpts(WithScopeName("testName"))
testOpts := getDefaultOptions()
testOpts.withScopeName = "testName"
testOpts.WithScopeName = "testName"
assert.Equal(opts, testOpts)
})
t.Run("WithPublicId", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithPublicId("testId"))
opts := GetOpts(WithPublicId("testId"))
testOpts := getDefaultOptions()
testOpts.withPublicId = "testId"
testOpts.WithPublicId = "testId"
assert.Equal(opts, testOpts)
})
t.Run("WithTargetType", func(t *testing.T) {
t.Run("WithType", func(t *testing.T) {
subtype := subtypes.Subtype("testtype")
assert := assert.New(t)
opts := getOpts(WithTargetType(TcpTargetType))
opts := GetOpts(WithType(subtype))
testOpts := getDefaultOptions()
target := TcpTargetType
testOpts.withTargetType = &target
target := subtype
testOpts.WithType = target
assert.Equal(opts, testOpts)
})
t.Run("WithHostSources", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithHostSources([]string{"alice", "bob"}))
opts := GetOpts(WithHostSources([]string{"alice", "bob"}))
testOpts := getDefaultOptions()
testOpts.withHostSources = []string{"alice", "bob"}
testOpts.WithHostSources = []string{"alice", "bob"}
assert.Equal(opts, testOpts)
})
t.Run("WithWorkerFilter", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithWorkerFilter(`"/foo" == "bar"`))
opts := GetOpts(WithWorkerFilter(`"/foo" == "bar"`))
testOpts := getDefaultOptions()
testOpts.withWorkerFilter = `"/foo" == "bar"`
testOpts.WithWorkerFilter = `"/foo" == "bar"`
assert.Equal(opts, testOpts)
})
t.Run("WithCredentialSources", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithCredentialSources([]string{"alice", "bob"}))
opts := GetOpts(WithCredentialSources([]string{"alice", "bob"}))
testOpts := getDefaultOptions()
testOpts.withCredentialSources = []string{"alice", "bob"}
testOpts.WithCredentialSources = []string{"alice", "bob"}
assert.Equal(opts, testOpts)
})
}
+112
View File
@@ -0,0 +1,112 @@
package target
import (
"context"
"fmt"
"sync"
"github.com/hashicorp/boundary/internal/types/subtypes"
)
// AllocFunc is a function that creates an in-memory Target.
type AllocFunc func() Target
// VetFunc is a function that checks the given Target to ensure it can
// be used by the Repository.
type VetFunc func(context.Context, Target) error
type registryEntry struct {
alloc AllocFunc
vet VetFunc
prefix string
}
type registry struct {
m map[subtypes.Subtype]*registryEntry
subtypes *subtypes.Registry
sync.RWMutex
}
func (r *registry) set(s subtypes.Subtype, entry *registryEntry) {
r.Lock()
defer r.Unlock()
_, previouslySet := r.m[s]
if previouslySet {
panic(fmt.Sprintf("target subtype %s already registered", s))
}
if err := r.subtypes.Register(s, entry.prefix); err != nil {
panic(err)
}
r.m[s] = entry
}
func (r *registry) get(s subtypes.Subtype) (*registryEntry, bool) {
r.RLock()
defer r.RUnlock()
entry, ok := r.m[s]
if ok {
return entry, ok
}
return nil, ok
}
func (r *registry) allocFunc(s subtypes.Subtype) (AllocFunc, bool) {
entry, ok := r.get(s)
if !ok {
return nil, ok
}
return entry.alloc, ok
}
func (r *registry) vetFunc(s subtypes.Subtype) (VetFunc, bool) {
entry, ok := r.get(s)
if !ok {
return nil, ok
}
return entry.vet, ok
}
func (r *registry) idPrefix(s subtypes.Subtype) (string, bool) {
entry, ok := r.get(s)
if !ok {
return "", ok
}
return entry.prefix, ok
}
var subtypeRegistry = registry{
m: make(map[subtypes.Subtype]*registryEntry),
subtypes: subtypes.NewRegistry(),
}
// SubtypeFromType returns the Subtype from the provided string or if
// no Subtype was registered with that string Unknown is returned.
func SubtypeFromType(t string) subtypes.Subtype {
subtypeRegistry.RLock()
defer subtypeRegistry.RUnlock()
return subtypeRegistry.subtypes.SubtypeFromType(t)
}
// SubtypeFromId returns the Subtype from the provided id if the id's prefix
// was registered with a Subtype. Otherwise Unknown is returned.
func SubtypeFromId(id string) subtypes.Subtype {
subtypeRegistry.RLock()
defer subtypeRegistry.RUnlock()
return subtypeRegistry.subtypes.SubtypeFromId(id)
}
// Register registers repository hooks and the prefixes for a provided Subtype. Register
// panics if the subtype has already been registered or if any of the
// prefixes are associated with another subtype.
func Register(s subtypes.Subtype, af AllocFunc, vf VetFunc, prefix string) {
subtypeRegistry.set(s, &registryEntry{
alloc: af,
vet: vf,
prefix: prefix,
})
}
+233 -34
View File
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/hashicorp/boundary/internal/db"
dbcommon "github.com/hashicorp/boundary/internal/db/common"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
@@ -13,7 +14,7 @@ import (
// Cloneable provides a cloning interface
type Cloneable interface {
Clone() interface{}
Clone() Target
}
// Repository is the target database repository
@@ -39,16 +40,16 @@ func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms, opt ...Option) (*Repo
if kms == nil {
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "nil kms")
}
opts := getOpts(opt...)
if opts.withLimit == 0 {
opts := GetOpts(opt...)
if opts.WithLimit == 0 {
// zero signals the boundary defaults should be used.
opts.withLimit = db.DefaultLimit
opts.WithLimit = db.DefaultLimit
}
return &Repository{
reader: r,
writer: w,
kms: kms,
defaultLimit: opts.withLimit,
defaultLimit: opts.WithLimit,
}, nil
}
@@ -57,7 +58,7 @@ func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms, opt ...Option) (*Repo
// found, it will return nil, nil, nil, nil. No options are currently supported.
func (r *Repository) LookupTarget(ctx context.Context, publicIdOrName string, opt ...Option) (Target, []HostSource, []CredentialSource, error) {
const op = "target.(Repository).LookupTarget"
opts := getOpts(opt...)
opts := GetOpts(opt...)
if publicIdOrName == "" {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing public id")
@@ -65,23 +66,23 @@ func (r *Repository) LookupTarget(ctx context.Context, publicIdOrName string, op
var where []string
var whereArgs []interface{}
nameEmpty := opts.withName == ""
scopeIdEmpty := opts.withScopeId == ""
scopeNameEmpty := opts.withScopeName == ""
nameEmpty := opts.WithName == ""
scopeIdEmpty := opts.WithScopeId == ""
scopeNameEmpty := opts.WithScopeName == ""
if !nameEmpty {
if opts.withName != publicIdOrName {
if opts.WithName != publicIdOrName {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "name passed in but does not match publicId")
}
where, whereArgs = append(where, "lower(name) = lower(?)"), append(whereArgs, opts.withName)
where, whereArgs = append(where, "lower(name) = lower(?)"), append(whereArgs, opts.WithName)
switch {
case scopeIdEmpty && scopeNameEmpty:
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "using name but both scope ID and scope name are empty")
case !scopeIdEmpty && !scopeNameEmpty:
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "using name but both scope ID and scope name are set")
case !scopeIdEmpty:
where, whereArgs = append(where, "scope_id = ?"), append(whereArgs, opts.withScopeId)
where, whereArgs = append(where, "scope_id = ?"), append(whereArgs, opts.WithScopeId)
case !scopeNameEmpty:
where, whereArgs = append(where, "scope_id = (select public_id from iam_scope where lower(name) = lower(?))"), append(whereArgs, opts.withScopeName)
where, whereArgs = append(where, "scope_id = (select public_id from iam_scope where lower(name) = lower(?))"), append(whereArgs, opts.WithScopeName)
default:
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "unknown combination of parameters")
}
@@ -130,28 +131,28 @@ func (r *Repository) LookupTarget(ctx context.Context, publicIdOrName string, op
}
return nil, nil, nil, errors.Wrap(ctx, err, op)
}
subtype, err := target.targetSubtype()
subtype, err := target.targetSubtype(ctx)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op)
}
return subtype, hostSources, credSources, nil
}
// ListTargets in targets in a scope. Supports the WithScopeId, WithLimit, WithTargetType options.
// ListTargets in targets in a scope. Supports the WithScopeId, WithLimit, WithType options.
func (r *Repository) ListTargets(ctx context.Context, opt ...Option) ([]Target, error) {
const op = "target.(Repository).ListTargets"
opts := getOpts(opt...)
if len(opts.withScopeIds) == 0 && opts.withUserId == "" {
opts := GetOpts(opt...)
if len(opts.WithScopeIds) == 0 && opts.WithUserId == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "must specify either scope id or user id")
}
// TODO (jimlambrt 8/2020) - implement WithUserId() optional filtering.
var where []string
var args []interface{}
if len(opts.withScopeIds) != 0 {
where, args = append(where, "scope_id in (?)"), append(args, opts.withScopeIds)
if len(opts.WithScopeIds) != 0 {
where, args = append(where, "scope_id in (?)"), append(args, opts.WithScopeIds)
}
if opts.withTargetType != nil {
where, args = append(where, "type = ?"), append(args, opts.withTargetType.String())
if opts.WithType != "" {
where, args = append(where, "type = ?"), append(args, opts.WithType.String())
}
var foundTargets []*targetView
@@ -163,7 +164,7 @@ func (r *Repository) ListTargets(ctx context.Context, opt ...Option) ([]Target,
targets := make([]Target, 0, len(foundTargets))
for _, t := range foundTargets {
subtype, err := t.targetSubtype()
subtype, err := t.targetSubtype(ctx)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
@@ -176,12 +177,12 @@ func (r *Repository) ListTargets(ctx context.Context, opt ...Option) ([]Target,
// repo defaultLimit
func (r *Repository) list(ctx context.Context, resources interface{}, where string, args []interface{}, opt ...Option) error {
const op = "target.(Repository).list"
opts := getOpts(opt...)
opts := GetOpts(opt...)
limit := r.defaultLimit
var dbOpts []db.Option
if opts.withLimit != 0 {
if opts.WithLimit != 0 {
// non-zero signals an override of the default limit for the repo.
limit = opts.withLimit
limit = opts.WithLimit
}
dbOpts = append(dbOpts, db.WithLimit(limit))
if err := r.reader.SearchWhere(ctx, resources, where, args, dbOpts...); err != nil {
@@ -202,17 +203,16 @@ func (r *Repository) DeleteTarget(ctx context.Context, publicId string, _ ...Opt
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", publicId)))
}
var metadata oplog.Metadata
var deleteTarget interface{}
switch t.Type {
case TcpTargetType.String():
tcpT := allocTcpTarget()
tcpT.PublicId = publicId
deleteTarget = &tcpT
metadata = tcpT.oplog(oplog.OpType_OP_TYPE_DELETE)
default:
var deleteTarget Target
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
if !ok {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", publicId, t.Type))
}
deleteTarget = alloc()
deleteTarget.SetPublicId(ctx, publicId)
metadata = deleteTarget.Oplog(oplog.OpType_OP_TYPE_DELETE)
oplogWrapper, err := r.kms.GetWrapper(ctx, t.ScopeId, kms.KeyPurposeOplog)
if err != nil {
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
@@ -277,7 +277,7 @@ func (r *Repository) update(ctx context.Context, target Target, version uint32,
if err != nil {
return nil, nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
}
metadata := target.oplog(oplog.OpType_OP_TYPE_UPDATE)
metadata := target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
dbOpts = append(dbOpts, db.WithOplog(oplogWrapper, metadata))
var rowsUpdated int
@@ -320,3 +320,202 @@ func (r *Repository) update(ctx context.Context, target Target, version uint32,
}
return returnedTarget.(Target), hostSources, credSources, rowsUpdated, nil
}
// CreateTarget inserts into the repository and returns the new Target with
// its list of host sets and credential libraries.
// WithHostSources and WithCredentialSources are the only supported option.
func (r *Repository) CreateTarget(ctx context.Context, target Target, opt ...Option) (Target, []HostSource, []CredentialSource, error) {
const op = "target.(Repository).CreateTarget"
opts := GetOpts(opt...)
if target == nil {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing target")
}
vet, ok := subtypeRegistry.vetFunc(target.GetType())
if !ok {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported target type %s", target.GetType()))
}
if err := vet(ctx, target); err != nil {
return nil, nil, nil, err
}
if target.GetScopeId() == "" {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope id")
}
if target.GetName() == "" {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing name")
}
if target.GetPublicId() != "" {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "public id not empty")
}
t := target.Clone()
if opts.WithPublicId != "" {
if err := t.SetPublicId(ctx, opts.WithPublicId); err != nil {
return nil, nil, nil, err
}
} else {
prefix, ok := subtypeRegistry.idPrefix(target.GetType())
if !ok {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported target type %s", target.GetType()))
}
id, err := db.NewPublicId(prefix)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op)
}
t.SetPublicId(ctx, id)
}
oplogWrapper, err := r.kms.GetWrapper(ctx, target.GetScopeId(), kms.KeyPurposeOplog)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
}
newHostSets := make([]interface{}, 0, len(opts.WithHostSources))
for _, hsId := range opts.WithHostSources {
hostSet, err := NewTargetHostSet(t.GetPublicId(), hsId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory target host set"))
}
newHostSets = append(newHostSets, hostSet)
}
newCredLibs := make([]interface{}, 0, len(opts.WithCredentialSources))
for _, clId := range opts.WithCredentialSources {
credLib, err := NewCredentialLibrary(t.GetPublicId(), clId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory target credential library"))
}
newCredLibs = append(newCredLibs, credLib)
}
metadata := t.Oplog(oplog.OpType_OP_TYPE_CREATE)
var returnedTarget interface{}
var returnedHostSources []HostSource
var returnedCredSources []CredentialSource
_, err = r.writer.DoTx(
ctx,
db.StdRetryCnt,
db.ExpBackoff{},
func(read db.Reader, w db.Writer) error {
targetTicket, err := w.GetTicket(t)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get ticket"))
}
msgs := make([]*oplog.Message, 0, 2)
var targetOplogMsg oplog.Message
returnedTarget = t.Clone()
if err := w.Create(ctx, returnedTarget, db.NewOplogMsg(&targetOplogMsg)); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create target"))
}
msgs = append(msgs, &targetOplogMsg)
if len(newHostSets) > 0 {
hostSetOplogMsgs := make([]*oplog.Message, 0, len(newHostSets))
if err := w.CreateItems(ctx, newHostSets, db.NewOplogMsgs(&hostSetOplogMsgs)); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add host sets"))
}
if returnedHostSources, err = fetchHostSources(ctx, read, t.GetPublicId()); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to read host sources"))
}
msgs = append(msgs, hostSetOplogMsgs...)
}
if len(newCredLibs) > 0 {
credLibOplogMsgs := make([]*oplog.Message, 0, len(newCredLibs))
if err := w.CreateItems(ctx, newCredLibs, db.NewOplogMsgs(&credLibOplogMsgs)); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add credential sources"))
}
if returnedCredSources, err = fetchCredentialSources(ctx, read, t.GetPublicId()); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to read credential sources"))
}
msgs = append(msgs, credLibOplogMsgs...)
}
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, targetTicket, metadata, msgs); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write oplog"))
}
return nil
},
)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s target id", t.GetPublicId())))
}
return returnedTarget.(Target), returnedHostSources, returnedCredSources, nil
}
// UpdateTarget will update a target in the repository and return the written
// target. fieldMaskPaths provides field_mask.proto paths for fields that should
// be updated. Fields will be set to NULL if the field is a zero value and
// included in fieldMask. Name, Description, and WorkerFilter are the only
// updatable fields. If no updatable fields are included in the fieldMaskPaths,
// then an error is returned.
func (r *Repository) UpdateTarget(ctx context.Context, target Target, version uint32, fieldMaskPaths []string, _ ...Option) (Target, []HostSource, []CredentialSource, int, error) {
const op = "target.(Repository).UpdateTarget"
if target == nil {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target")
}
vet, ok := subtypeRegistry.vetFunc(target.GetType())
if !ok {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported target type %s", target.GetType()))
}
if err := vet(ctx, target); err != nil {
return nil, nil, nil, db.NoRowsAffected, err
}
if target.GetPublicId() == "" {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target public id")
}
for _, f := range fieldMaskPaths {
switch {
case strings.EqualFold("name", f):
case strings.EqualFold("description", f):
case strings.EqualFold("defaultport", f):
case strings.EqualFold("sessionmaxseconds", f):
case strings.EqualFold("sessionconnectionlimit", f):
case strings.EqualFold("workerfilter", f):
default:
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidFieldMask, op, fmt.Sprintf("invalid field mask: %s", f))
}
}
var dbMask, nullFields []string
dbMask, nullFields = dbcommon.BuildUpdatePaths(
map[string]interface{}{
"Name": target.GetName(),
"Description": target.GetDescription(),
"DefaultPort": target.GetDefaultPort(),
"SessionMaxSeconds": target.GetSessionMaxSeconds(),
"SessionConnectionLimit": target.GetSessionConnectionLimit(),
"WorkerFilter": target.GetWorkerFilter(),
},
fieldMaskPaths,
[]string{"SessionMaxSeconds", "SessionConnectionLimit"},
)
if len(dbMask) == 0 && len(nullFields) == 0 {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.EmptyFieldMask, op, "empty field mask")
}
var returnedTarget Target
var rowsUpdated int
var hostSources []HostSource
var credSources []CredentialSource
_, err := r.writer.DoTx(
ctx,
db.StdRetryCnt,
db.ExpBackoff{},
func(read db.Reader, w db.Writer) error {
var err error
t := target.Clone()
returnedTarget, hostSources, credSources, rowsUpdated, err = r.update(ctx, t, version, dbMask, nullFields)
if err != nil {
return errors.Wrap(ctx, err, op)
}
return nil
},
)
if err != nil {
if errors.IsUniqueError(err) {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.NotUnique, op, fmt.Sprintf("target %s already exists in scope %s", target.GetName(), target.GetScopeId()))
}
return nil, nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", target.GetPublicId())))
}
return returnedTarget, hostSources, credSources, rowsUpdated, nil
}
+25 -29
View File
@@ -43,19 +43,18 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", targetId)))
}
var metadata oplog.Metadata
var target interface{}
switch t.Type {
case TcpTargetType.String():
tcpT := allocTcpTarget()
tcpT.PublicId = t.PublicId
tcpT.Version = targetVersion + 1
target = &tcpT
metadata = tcpT.oplog(oplog.OpType_OP_TYPE_UPDATE)
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String())
default:
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
if !ok {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
target := alloc()
target.SetPublicId(ctx, t.PublicId)
target.SetVersion(targetVersion + 1)
metadata = target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String())
oplogWrapper, err := r.kms.GetWrapper(ctx, t.GetScopeId(), kms.KeyPurposeOplog)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
@@ -143,18 +142,16 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", targetId)))
}
var metadata oplog.Metadata
var target interface{}
switch t.Type {
case TcpTargetType.String():
tcpT := allocTcpTarget()
tcpT.PublicId = t.PublicId
tcpT.Version = targetVersion + 1
target = &tcpT
metadata = tcpT.oplog(oplog.OpType_OP_TYPE_UPDATE)
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_DELETE.String())
default:
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
if !ok {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
target := alloc()
target.SetPublicId(ctx, t.PublicId)
target.SetVersion(targetVersion + 1)
metadata = target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_DELETE.String())
oplogWrapper, err := r.kms.GetWrapper(ctx, t.GetScopeId(), kms.KeyPurposeOplog)
if err != nil {
@@ -257,17 +254,16 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", targetId)))
}
var metadata oplog.Metadata
var target interface{}
switch t.Type {
case TcpTargetType.String():
tcpT := allocTcpTarget()
tcpT.PublicId = t.PublicId
tcpT.Version = targetVersion + 1
target = &tcpT
metadata = tcpT.oplog(oplog.OpType_OP_TYPE_UPDATE)
default:
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
if !ok {
return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
target := alloc()
target.SetPublicId(ctx, t.PublicId)
target.SetVersion(targetVersion + 1)
metadata = target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
oplogWrapper, err := r.kms.GetWrapper(ctx, t.GetScopeId(), kms.KeyPurposeOplog)
if err != nil {
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
+29 -29
View File
@@ -40,18 +40,18 @@ func (r *Repository) AddTargetHostSources(ctx context.Context, targetId string,
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", targetId)))
}
var metadata oplog.Metadata
var target interface{}
switch t.Type {
case TcpTargetType.String():
tcpT := allocTcpTarget()
tcpT.PublicId = t.PublicId
tcpT.Version = targetVersion + 1
target = &tcpT
metadata = tcpT.oplog(oplog.OpType_OP_TYPE_UPDATE)
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String())
default:
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
if !ok {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
target := alloc()
target.SetPublicId(ctx, t.PublicId)
target.SetVersion(targetVersion + 1)
metadata = target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String())
oplogWrapper, err := r.kms.GetWrapper(ctx, t.GetScopeId(), kms.KeyPurposeOplog)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
@@ -137,18 +137,18 @@ func (r *Repository) DeleteTargetHostSources(ctx context.Context, targetId strin
}
var metadata oplog.Metadata
var target interface{}
switch t.Type {
case TcpTargetType.String():
tcpT := allocTcpTarget()
tcpT.PublicId = t.PublicId
tcpT.Version = targetVersion + 1
target = &tcpT
metadata = tcpT.oplog(oplog.OpType_OP_TYPE_UPDATE)
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_DELETE.String())
default:
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
if !ok {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
target := alloc()
target.SetPublicId(ctx, t.PublicId)
target.SetVersion(targetVersion + 1)
metadata = target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_DELETE.String())
oplogWrapper, err := r.kms.GetWrapper(ctx, t.GetScopeId(), kms.KeyPurposeOplog)
if err != nil {
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
@@ -260,17 +260,17 @@ func (r *Repository) SetTargetHostSources(ctx context.Context, targetId string,
}
var metadata oplog.Metadata
var target interface{}
switch t.Type {
case TcpTargetType.String():
tcpT := allocTcpTarget()
tcpT.PublicId = t.PublicId
tcpT.Version = targetVersion + 1
target = &tcpT
metadata = tcpT.oplog(oplog.OpType_OP_TYPE_UPDATE)
default:
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
if !ok {
return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
target := alloc()
target.SetPublicId(ctx, t.PublicId)
target.SetVersion(targetVersion + 1)
metadata = target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
oplogWrapper, err := r.kms.GetWrapper(ctx, t.GetScopeId(), kms.KeyPurposeOplog)
if err != nil {
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
-198
View File
@@ -1,198 +0,0 @@
package target
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/boundary/internal/db"
dbcommon "github.com/hashicorp/boundary/internal/db/common"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
)
// CreateTcpTarget inserts into the repository and returns the new Target with
// its list of host sets and credential libraries.
// WithHostSources and WithCredentialSources are the only supported option.
func (r *Repository) CreateTcpTarget(ctx context.Context, target *TcpTarget, opt ...Option) (Target, []HostSource, []CredentialSource, error) {
const op = "target.(Repository).CreateTcpTarget"
opts := getOpts(opt...)
if target == nil {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing target")
}
if target.TcpTarget == nil {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing target store")
}
if target.ScopeId == "" {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope id")
}
if target.Name == "" {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing name")
}
if target.PublicId != "" {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "public id not empty")
}
t := target.Clone().(*TcpTarget)
if opts.withPublicId != "" {
if !strings.HasPrefix(opts.withPublicId, TcpTargetPrefix+"_") {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("passed-in public ID %q has wrong prefix, should be %q", opts.withPublicId, TcpTargetPrefix))
}
t.PublicId = opts.withPublicId
} else {
id, err := newTcpTargetId()
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op)
}
t.PublicId = id
}
oplogWrapper, err := r.kms.GetWrapper(ctx, target.ScopeId, kms.KeyPurposeOplog)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
}
newHostSets := make([]interface{}, 0, len(opts.withHostSources))
for _, hsId := range opts.withHostSources {
hostSet, err := NewTargetHostSet(t.PublicId, hsId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory target host set"))
}
newHostSets = append(newHostSets, hostSet)
}
newCredLibs := make([]interface{}, 0, len(opts.withCredentialSources))
for _, clId := range opts.withCredentialSources {
credLib, err := NewCredentialLibrary(t.PublicId, clId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory target credential library"))
}
newCredLibs = append(newCredLibs, credLib)
}
metadata := t.oplog(oplog.OpType_OP_TYPE_CREATE)
var returnedTarget interface{}
var returnedHostSources []HostSource
var returnedCredSources []CredentialSource
_, err = r.writer.DoTx(
ctx,
db.StdRetryCnt,
db.ExpBackoff{},
func(read db.Reader, w db.Writer) error {
targetTicket, err := w.GetTicket(t)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get ticket"))
}
msgs := make([]*oplog.Message, 0, 2)
var targetOplogMsg oplog.Message
returnedTarget = t.Clone()
if err := w.Create(ctx, returnedTarget, db.NewOplogMsg(&targetOplogMsg)); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create target"))
}
msgs = append(msgs, &targetOplogMsg)
if len(newHostSets) > 0 {
hostSetOplogMsgs := make([]*oplog.Message, 0, len(newHostSets))
if err := w.CreateItems(ctx, newHostSets, db.NewOplogMsgs(&hostSetOplogMsgs)); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add host sets"))
}
if returnedHostSources, err = fetchHostSources(ctx, read, t.PublicId); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to read host sources"))
}
msgs = append(msgs, hostSetOplogMsgs...)
}
if len(newCredLibs) > 0 {
credLibOplogMsgs := make([]*oplog.Message, 0, len(newCredLibs))
if err := w.CreateItems(ctx, newCredLibs, db.NewOplogMsgs(&credLibOplogMsgs)); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add credential sources"))
}
if returnedCredSources, err = fetchCredentialSources(ctx, read, t.PublicId); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to read credential sources"))
}
msgs = append(msgs, credLibOplogMsgs...)
}
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, targetTicket, metadata, msgs); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write oplog"))
}
return nil
},
)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s target id", t.PublicId)))
}
return returnedTarget.(*TcpTarget), returnedHostSources, returnedCredSources, nil
}
// UpdateTcpTarget will update a target in the repository and return the written
// target. fieldMaskPaths provides field_mask.proto paths for fields that should
// be updated. Fields will be set to NULL if the field is a zero value and
// included in fieldMask. Name, Description, and WorkerFilter are the only
// updatable fields. If no updatable fields are included in the fieldMaskPaths,
// then an error is returned.
func (r *Repository) UpdateTcpTarget(ctx context.Context, target *TcpTarget, version uint32, fieldMaskPaths []string, _ ...Option) (Target, []HostSource, []CredentialSource, int, error) {
const op = "target.(Repository).UpdateTcpTarget"
if target == nil {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target")
}
if target.TcpTarget == nil {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target store")
}
if target.PublicId == "" {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target public id")
}
for _, f := range fieldMaskPaths {
switch {
case strings.EqualFold("name", f):
case strings.EqualFold("description", f):
case strings.EqualFold("defaultport", f):
case strings.EqualFold("sessionmaxseconds", f):
case strings.EqualFold("sessionconnectionlimit", f):
case strings.EqualFold("workerfilter", f):
default:
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidFieldMask, op, fmt.Sprintf("invalid field mask: %s", f))
}
}
var dbMask, nullFields []string
dbMask, nullFields = dbcommon.BuildUpdatePaths(
map[string]interface{}{
"Name": target.Name,
"Description": target.Description,
"DefaultPort": target.DefaultPort,
"SessionMaxSeconds": target.SessionMaxSeconds,
"SessionConnectionLimit": target.SessionConnectionLimit,
"WorkerFilter": target.WorkerFilter,
},
fieldMaskPaths,
[]string{"SessionMaxSeconds", "SessionConnectionLimit"},
)
if len(dbMask) == 0 && len(nullFields) == 0 {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.EmptyFieldMask, op, "empty field mask")
}
var returnedTarget Target
var rowsUpdated int
var hostSources []HostSource
var credSources []CredentialSource
_, err := r.writer.DoTx(
ctx,
db.StdRetryCnt,
db.ExpBackoff{},
func(read db.Reader, w db.Writer) error {
var err error
t := target.Clone().(*TcpTarget)
returnedTarget, hostSources, credSources, rowsUpdated, err = r.update(ctx, t, version, dbMask, nullFields)
if err != nil {
return errors.Wrap(ctx, err, op)
}
return nil
},
)
if err != nil {
if errors.IsUniqueError(err) {
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.NotUnique, op, fmt.Sprintf("target %s already exists in scope %s", target.Name, target.ScopeId))
}
return nil, nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", target.PublicId)))
}
return returnedTarget, hostSources, credSources, rowsUpdated, nil
}
+1 -336
View File
@@ -1,17 +1,10 @@
package target
import (
"context"
"fmt"
"strconv"
"testing"
"time"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -93,336 +86,8 @@ func TestNewRepository(t *testing.T) {
return
}
require.NoError(err)
assert.NotNil(got)
assert.Equal(tt.want, got)
})
}
}
func TestRepository_LookupTarget(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, proj := iam.TestScopes(t, iamRepo)
proj.Name = "project-name"
_, _, err := iamRepo.UpdateScope(context.Background(), proj, 1, []string{"name"})
require.NoError(t, err)
rw := db.New(conn)
repo, err := NewRepository(rw, rw, testKms)
require.NoError(t, err)
tgt := TestTcpTarget(t, conn, proj.PublicId, "target-name")
tests := []struct {
testName string
id string
name string
scopeId string
scopeName string
wantErr bool
}{
{
testName: "id",
id: tgt.PublicId,
wantErr: false,
},
{
testName: "name only",
name: tgt.Name,
wantErr: true,
},
{
testName: "scope id only",
scopeId: proj.PublicId,
wantErr: true,
},
{
testName: "scope name only",
scopeName: proj.Name,
wantErr: true,
},
{
testName: "scope name and id",
scopeId: proj.PublicId,
scopeName: proj.Name,
wantErr: true,
},
{
testName: "everything",
name: tgt.Name,
scopeId: proj.PublicId,
scopeName: proj.Name,
wantErr: true,
},
{
testName: "name and scope name",
name: tgt.Name,
scopeName: proj.Name,
wantErr: false,
},
{
testName: "name and scope id",
name: tgt.Name,
scopeId: proj.PublicId,
wantErr: false,
},
{
testName: "id and name",
id: tgt.PublicId,
name: tgt.Name,
scopeId: proj.PublicId,
wantErr: true,
},
{
testName: "id and scope name",
id: tgt.PublicId,
scopeName: proj.Name,
wantErr: true,
},
{
testName: "id and scope id",
id: tgt.PublicId,
scopeId: proj.PublicId,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.testName, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
id := tt.id
if tt.name != "" && tt.id == "" {
id = tt.name
}
var opts []Option
if tt.name != "" {
opts = append(opts, WithName(tt.name))
}
if tt.scopeId != "" {
opts = append(opts, WithScopeId(tt.scopeId))
}
if tt.scopeName != "" {
opts = append(opts, WithScopeName(tt.scopeName))
}
got, _, _, err := repo.LookupTarget(context.Background(), id, opts...)
if tt.wantErr {
require.Error(err)
return
}
require.NoError(err)
assert.Equal(tgt.PublicId, got.GetPublicId())
})
}
}
func TestRepository_ListTargets(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
const testLimit = 10
wrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, proj := iam.TestScopes(t, iamRepo)
rw := db.New(conn)
repo, err := NewRepository(rw, rw, testKms)
require.NoError(t, err)
repo.defaultLimit = testLimit
type args struct {
opt []Option
}
tests := []struct {
name string
createCnt int
createScopeId string
createScopeId2 string
grantUserId string
args args
wantCnt int
wantErr bool
}{
{
name: "tcp-target",
createCnt: 5,
createScopeId: proj.PublicId,
args: args{
opt: []Option{WithTargetType(TcpTargetType), WithScopeIds([]string{proj.PublicId})},
},
wantCnt: 5,
wantErr: false,
},
{
name: "no-limit",
createCnt: testLimit + 1,
createScopeId: proj.PublicId,
args: args{
opt: []Option{WithLimit(-1), WithScopeIds([]string{proj.PublicId})},
},
wantCnt: testLimit + 1,
wantErr: false,
},
{
name: "default-limit",
createCnt: testLimit + 1,
createScopeId: proj.PublicId,
args: args{
opt: []Option{WithScopeIds([]string{proj.PublicId})},
},
wantCnt: testLimit,
wantErr: false,
},
{
name: "custom-limit",
createCnt: testLimit + 1,
createScopeId: proj.PublicId,
args: args{
opt: []Option{WithLimit(3), WithScopeIds([]string{proj.PublicId})},
},
wantCnt: 3,
wantErr: false,
},
{
name: "bad-org",
createCnt: 1,
createScopeId: proj.PublicId,
args: args{
opt: []Option{WithScopeIds([]string{"bad-id"})},
},
wantCnt: 0,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
require.NoError(conn.Where("1=1").Delete(allocTcpTarget()).Error)
testGroups := []*TcpTarget{}
for i := 0; i < tt.createCnt; i++ {
switch {
case tt.createScopeId2 != "" && i%2 == 0:
testGroups = append(testGroups, TestTcpTarget(t, conn, tt.createScopeId2, strconv.Itoa(i)))
default:
testGroups = append(testGroups, TestTcpTarget(t, conn, tt.createScopeId, strconv.Itoa(i)))
}
}
assert.Equal(tt.createCnt, len(testGroups))
got, err := repo.ListTargets(context.Background(), tt.args.opt...)
if tt.wantErr {
require.Error(err)
return
}
require.NoError(err)
assert.Equal(tt.wantCnt, len(got))
})
}
}
func TestRepository_ListRoles_Multiple_Scopes(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, proj1 := iam.TestScopes(t, iamRepo)
_, proj2 := iam.TestScopes(t, iamRepo)
rw := db.New(conn)
repo, err := NewRepository(rw, rw, testKms)
require.NoError(t, err)
require.NoError(t, conn.Where("1=1").Delete(allocTcpTarget()).Error)
const numPerScope = 10
var total int
for i := 0; i < numPerScope; i++ {
TestTcpTarget(t, conn, proj1.GetPublicId(), fmt.Sprintf("proj1-%d", i))
total++
TestTcpTarget(t, conn, proj2.GetPublicId(), fmt.Sprintf("proj2-%d", i))
total++
}
got, err := repo.ListTargets(context.Background(), WithScopeIds([]string{"global", proj1.GetPublicId(), proj2.GetPublicId()}))
require.NoError(t, err)
assert.Equal(t, total, len(got))
}
func TestRepository_DeleteTarget(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, proj := iam.TestScopes(t, iamRepo)
repo, err := NewRepository(rw, rw, testKms)
require.NoError(t, err)
type args struct {
target Target
opt []Option
}
tests := []struct {
name string
args args
wantRowsDeleted int
wantErr bool
wantErrMsg string
}{
{
name: "valid",
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "valid"),
},
wantRowsDeleted: 1,
wantErr: false,
},
{
name: "no-public-id",
args: args{
target: func() Target {
target := allocTcpTarget()
return &target
}(),
},
wantRowsDeleted: 0,
wantErr: true,
wantErrMsg: "target.(Repository).DeleteTarget: missing public id: parameter violation: error #100",
},
{
name: "not-found",
args: args{
target: func() Target {
id, err := newTcpTargetId()
require.NoError(t, err)
target := allocTcpTarget()
target.PublicId = id
return &target
}(),
},
wantRowsDeleted: 0,
wantErr: true,
wantErrMsg: "db.LookupById: record not found, search issue: error #1100",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
deletedRows, err := repo.DeleteTarget(context.Background(), tt.args.target.GetPublicId(), tt.args.opt...)
if tt.wantErr {
assert.Error(err)
assert.Equal(0, deletedRows)
assert.Contains(err.Error(), tt.wantErrMsg)
err = db.TestVerifyOplog(t, rw, tt.args.target.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
assert.Error(err)
assert.True(errors.IsNotFoundError(err))
return
}
assert.NoError(err)
assert.Equal(tt.wantRowsDeleted, deletedRows)
foundGroup, _, _, err := repo.LookupTarget(context.Background(), tt.args.target.GetPublicId())
assert.NoError(err)
assert.Nil(foundGroup)
err = db.TestVerifyOplog(t, rw, tt.args.target.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
assert.NoError(err)
})
}
}
+35 -246
View File
@@ -253,157 +253,6 @@ func (x *TargetHostSet) GetCreateTime() *timestamp.Timestamp {
return nil
}
type TcpTarget struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// public_id is used to access the TargetTcp via an API
// @inject_tag: gorm:"primary_key"
PublicId string `protobuf:"bytes,10,opt,name=public_id,json=publicId,proto3" json:"public_id,omitempty" gorm:"primary_key"`
// scope id for the TargetTcp
// @inject_tag: `gorm:"default:null"`
ScopeId string `protobuf:"bytes,20,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty" gorm:"default:null"`
// name is the optional friendly name used to
// access the TargetTcp via an API
// @inject_tag: `gorm:"default:null"`
Name string `protobuf:"bytes,30,opt,name=name,proto3" json:"name,omitempty" gorm:"default:null"`
// description of the TargetTcp
// @inject_tag: `gorm:"default:null"`
Description string `protobuf:"bytes,40,opt,name=description,proto3" json:"description,omitempty" gorm:"default:null"`
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
CreateTime *timestamp.Timestamp `protobuf:"bytes,50,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"`
// update_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
UpdateTime *timestamp.Timestamp `protobuf:"bytes,60,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty" gorm:"default:current_timestamp"`
// version allows optimistic locking of the TargetTcp when modifying the
// TargetTcp
// @inject_tag: `gorm:"default:null"`
Version uint32 `protobuf:"varint,70,opt,name=version,proto3" json:"version,omitempty" gorm:"default:null"`
// default port of the TargetTcp
// @inject_tag: `gorm:"default:null"`
DefaultPort uint32 `protobuf:"varint,80,opt,name=default_port,json=defaultPort,proto3" json:"default_port,omitempty" gorm:"default:null"`
// Maximum total lifetime of a created session, in seconds
// @inject_tag: `gorm:"default:null"`
SessionMaxSeconds uint32 `protobuf:"varint,100,opt,name=session_max_seconds,json=sessionMaxSeconds,proto3" json:"session_max_seconds,omitempty" gorm:"default:null"`
// Maximum number of connections in a session
// @inject_tag: `gorm:"default:null"`
SessionConnectionLimit int32 `protobuf:"varint,110,opt,name=session_connection_limit,json=sessionConnectionLimit,proto3" json:"session_connection_limit,omitempty" gorm:"default:null"`
// A boolean expression that allows filtering the workers that can handle a session
// @inject_tag: `gorm:"default:null"`
WorkerFilter string `protobuf:"bytes,120,opt,name=worker_filter,json=workerFilter,proto3" json:"worker_filter,omitempty" gorm:"default:null"`
}
func (x *TcpTarget) Reset() {
*x = TcpTarget{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TcpTarget) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TcpTarget) ProtoMessage() {}
func (x *TcpTarget) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TcpTarget.ProtoReflect.Descriptor instead.
func (*TcpTarget) Descriptor() ([]byte, []int) {
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{2}
}
func (x *TcpTarget) GetPublicId() string {
if x != nil {
return x.PublicId
}
return ""
}
func (x *TcpTarget) GetScopeId() string {
if x != nil {
return x.ScopeId
}
return ""
}
func (x *TcpTarget) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *TcpTarget) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *TcpTarget) GetCreateTime() *timestamp.Timestamp {
if x != nil {
return x.CreateTime
}
return nil
}
func (x *TcpTarget) GetUpdateTime() *timestamp.Timestamp {
if x != nil {
return x.UpdateTime
}
return nil
}
func (x *TcpTarget) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *TcpTarget) GetDefaultPort() uint32 {
if x != nil {
return x.DefaultPort
}
return 0
}
func (x *TcpTarget) GetSessionMaxSeconds() uint32 {
if x != nil {
return x.SessionMaxSeconds
}
return 0
}
func (x *TcpTarget) GetSessionConnectionLimit() int32 {
if x != nil {
return x.SessionConnectionLimit
}
return 0
}
func (x *TcpTarget) GetWorkerFilter() string {
if x != nil {
return x.WorkerFilter
}
return ""
}
type CredentialLibrary struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -426,7 +275,7 @@ type CredentialLibrary struct {
func (x *CredentialLibrary) Reset() {
*x = CredentialLibrary{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[3]
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -439,7 +288,7 @@ func (x *CredentialLibrary) String() string {
func (*CredentialLibrary) ProtoMessage() {}
func (x *CredentialLibrary) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[3]
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -452,7 +301,7 @@ func (x *CredentialLibrary) ProtoReflect() protoreflect.Message {
// Deprecated: Use CredentialLibrary.ProtoReflect.Descriptor instead.
func (*CredentialLibrary) Descriptor() ([]byte, []int) {
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{3}
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{2}
}
func (x *CredentialLibrary) GetTargetId() string {
@@ -538,70 +387,25 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61,
0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74,
0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xc6, 0x05, 0x0a, 0x09, 0x54, 0x63, 0x70, 0x54, 0x61, 0x72,
0x67, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64,
0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69,
0x6d, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65,
0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75,
0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2a, 0xc2,
0xdd, 0x29, 0x26, 0x0a, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74,
0x12, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66,
0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75,
0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x5c, 0x0a, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x64, 0x20,
0x01, 0x28, 0x0d, 0x42, 0x2c, 0xc2, 0xdd, 0x29, 0x28, 0x0a, 0x11, 0x53, 0x65, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x13, 0x73, 0x65,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64,
0x73, 0x52, 0x11, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63,
0x6f, 0x6e, 0x64, 0x73, 0x12, 0x70, 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74,
0x18, 0x6e, 0x20, 0x01, 0x28, 0x05, 0x42, 0x36, 0xc2, 0xdd, 0x29, 0x32, 0x0a, 0x16, 0x53, 0x65,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c,
0x69, 0x6d, 0x69, 0x74, 0x12, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x16,
0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x46, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xc2,
0xdd, 0x29, 0x1d, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65,
0x72, 0x12, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0xe0,
0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62,
0x72, 0x61, 0x72, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69,
0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49,
0x64, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f,
0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09,
0x52, 0x13, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72,
0x61, 0x72, 0x79, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28,
0x09, 0x52, 0x11, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x75, 0x72,
0x70, 0x6f, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d,
0x65, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61,
0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67,
0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xe0, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74,
0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x72, 0x65, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x69,
0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12,
0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f,
0x73, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x63,
0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74,
0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e,
0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -616,26 +420,23 @@ func file_controller_storage_target_store_v1_target_proto_rawDescGZIP() []byte {
return file_controller_storage_target_store_v1_target_proto_rawDescData
}
var file_controller_storage_target_store_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_controller_storage_target_store_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_controller_storage_target_store_v1_target_proto_goTypes = []interface{}{
(*TargetView)(nil), // 0: controller.storage.target.store.v1.TargetView
(*TargetHostSet)(nil), // 1: controller.storage.target.store.v1.TargetHostSet
(*TcpTarget)(nil), // 2: controller.storage.target.store.v1.TcpTarget
(*CredentialLibrary)(nil), // 3: controller.storage.target.store.v1.CredentialLibrary
(*timestamp.Timestamp)(nil), // 4: controller.storage.timestamp.v1.Timestamp
(*CredentialLibrary)(nil), // 2: controller.storage.target.store.v1.CredentialLibrary
(*timestamp.Timestamp)(nil), // 3: controller.storage.timestamp.v1.Timestamp
}
var file_controller_storage_target_store_v1_target_proto_depIdxs = []int32{
4, // 0: controller.storage.target.store.v1.TargetView.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // 1: controller.storage.target.store.v1.TargetView.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // 2: controller.storage.target.store.v1.TargetHostSet.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // 3: controller.storage.target.store.v1.TcpTarget.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // 4: controller.storage.target.store.v1.TcpTarget.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // 5: controller.storage.target.store.v1.CredentialLibrary.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
6, // [6:6] is the sub-list for method output_type
6, // [6:6] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
3, // 0: controller.storage.target.store.v1.TargetView.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
3, // 1: controller.storage.target.store.v1.TargetView.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
3, // 2: controller.storage.target.store.v1.TargetHostSet.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
3, // 3: controller.storage.target.store.v1.CredentialLibrary.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_controller_storage_target_store_v1_target_proto_init() }
@@ -669,18 +470,6 @@ func file_controller_storage_target_store_v1_target_proto_init() {
}
}
file_controller_storage_target_store_v1_target_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TcpTarget); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_storage_target_store_v1_target_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CredentialLibrary); i {
case 0:
return &v.state
@@ -699,7 +488,7 @@ func file_controller_storage_target_store_v1_target_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_storage_target_store_v1_target_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
-41
View File
@@ -1,41 +0,0 @@
package target
import (
"strings"
)
type Subtype int
const (
UnknownSubtype Subtype = iota
TcpSubtype
)
func (t Subtype) String() string {
switch t {
case TcpSubtype:
return "tcp"
}
return "unknown"
}
// SubtypeFromType converts a string to a Subtype.
// returns UnknownSubtype if no Subtype with that name is found.
func SubtypeFromType(t string) Subtype {
switch {
case strings.EqualFold(strings.TrimSpace(t), TcpSubtype.String()):
return TcpSubtype
}
return UnknownSubtype
}
// SubtypeFromId takes any public id in the target subsystem and uses the prefix to determine
// what subtype the id is for.
// Returns UnknownSubtype if no Subtype with this id's prefix is found.
func SubtypeFromId(id string) Subtype {
switch {
case strings.HasPrefix(strings.TrimSpace(id), TcpTargetPrefix):
return TcpSubtype
}
return UnknownSubtype
}
+44 -38
View File
@@ -1,12 +1,14 @@
package target
import (
"context"
"fmt"
"github.com/hashicorp/boundary/internal/db/timestamp"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/hashicorp/boundary/internal/types/subtypes"
)
// Target is a commmon interface for all target subtypes
@@ -17,29 +19,25 @@ type Target interface {
GetName() string
GetDescription() string
GetVersion() uint32
GetType() string
GetType() subtypes.Subtype
GetCreateTime() *timestamp.Timestamp
GetUpdateTime() *timestamp.Timestamp
GetSessionMaxSeconds() uint32
GetSessionConnectionLimit() int32
GetWorkerFilter() string
oplog(op oplog.OpType) oplog.Metadata
}
// TargetType defines the possible types for targets.
type TargetType uint32
const (
UnknownTargetType TargetType = 0
TcpTargetType TargetType = 1
)
// String returns a string representation of the target type.
func (t TargetType) String() string {
return [...]string{
"unknown",
"tcp",
}[t]
Clone() Target
SetPublicId(context.Context, string) error
SetScopeId(string)
SetName(string)
SetDescription(string)
SetVersion(uint32)
SetDefaultPort(uint32)
SetCreateTime(*timestamp.Timestamp)
SetUpdateTime(*timestamp.Timestamp)
SetSessionMaxSeconds(uint32)
SetSessionConnectionLimit(int32)
SetWorkerFilter(string)
Oplog(op oplog.OpType) oplog.Metadata
}
const (
@@ -79,24 +77,32 @@ func (t *targetView) SetTableName(n string) {
}
}
// targetSubtype converts the target view to the concrete subtype
func (t *targetView) targetSubtype() (Target, error) {
const op = "target.targetView.targetSubtype"
switch t.Type {
case TcpTargetType.String():
tcpTarget := allocTcpTarget()
tcpTarget.PublicId = t.PublicId
tcpTarget.ScopeId = t.ScopeId
tcpTarget.Name = t.Name
tcpTarget.Description = t.Description
tcpTarget.DefaultPort = t.DefaultPort
tcpTarget.CreateTime = t.CreateTime
tcpTarget.UpdateTime = t.UpdateTime
tcpTarget.Version = t.Version
tcpTarget.SessionMaxSeconds = t.SessionMaxSeconds
tcpTarget.SessionConnectionLimit = t.SessionConnectionLimit
tcpTarget.WorkerFilter = t.WorkerFilter
return &tcpTarget, nil
}
return nil, errors.NewDeprecated(errors.InvalidParameter, op, fmt.Sprintf("%s is an unknown target subtype of %s", t.PublicId, t.Type))
func (t *targetView) Subtype() subtypes.Subtype {
return subtypes.Subtype(t.Type)
}
// targetSubtype converts the target view to the concrete subtype
func (t *targetView) targetSubtype(ctx context.Context) (Target, error) {
const op = "target.targetView.targetSubtype"
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
if !ok {
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unknown target subtype of %s", t.PublicId, t.Type))
}
tt := alloc()
if err := tt.SetPublicId(ctx, t.PublicId); err != nil {
return nil, err
}
tt.SetVersion(t.Version)
tt.SetScopeId(t.ScopeId)
tt.SetName(t.Name)
tt.SetDescription(t.Description)
tt.SetDefaultPort(t.DefaultPort)
tt.SetCreateTime(t.CreateTime)
tt.SetUpdateTime(t.UpdateTime)
tt.SetSessionMaxSeconds(t.SessionMaxSeconds)
tt.SetSessionConnectionLimit(t.SessionConnectionLimit)
tt.SetWorkerFilter(t.WorkerFilter)
return tt, nil
}
+5 -4
View File
@@ -1,15 +1,16 @@
package target
package target_test
import (
"testing"
"github.com/hashicorp/boundary/internal/target"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTarget_SetTableName(t *testing.T) {
t.Parallel()
defaultTableName := targetsViewDefaultTable
defaultTableName := target.TargetsViewDefaultTable
tests := []struct {
name string
setNameTo string
@@ -29,9 +30,9 @@ func TestTarget_SetTableName(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
def := allocTargetView()
def := target.AllocTargetView()
require.Equal(defaultTableName, def.TableName())
s := allocTargetView()
s := target.AllocTargetView()
s.SetTableName(tt.setNameTo)
assert.Equal(tt.want, s.TableName())
})
+19
View File
@@ -0,0 +1,19 @@
package tcp
import "github.com/hashicorp/boundary/internal/target"
// Expose functions and variables for tests.
var (
TestId = testId
TestTargetName = testTargetName
DefaultTableName = defaultTableName
)
// NewTestTarget is a test helper that bypasses the scopeId checks
// performed by NewTarget, allowing tests to create Targets with
// nil scopeIds for more robust testing.
func NewTestTarget(scopeId string, opt ...target.Option) *Target {
t, _ := New("testScope", opt...)
t.ScopeId = scopeId
return t
}
@@ -1,4 +1,4 @@
package target
package tcp_test
import (
"context"
@@ -9,6 +9,8 @@ import (
"github.com/hashicorp/boundary/internal/host/static"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
@@ -24,17 +26,17 @@ func TestTarget_ImmutableFields(t *testing.T) {
ts := timestamp.Timestamp{Timestamp: &timestamppb.Timestamp{Seconds: 0, Nanos: 0}}
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
new := TestTcpTarget(t, conn, proj.PublicId, testId(t))
new := tcp.TestTarget(t, conn, proj.PublicId, tcp.TestId(t))
tests := []struct {
name string
update *TcpTarget
update *tcp.Target
fieldMask []string
}{
{
name: "public_id",
update: func() *TcpTarget {
target := new.Clone().(*TcpTarget)
update: func() *tcp.Target {
target := new.Clone().(*tcp.Target)
target.PublicId = "p_thisIsNotAValidId"
return target
}(),
@@ -42,8 +44,8 @@ func TestTarget_ImmutableFields(t *testing.T) {
},
{
name: "create time",
update: func() *TcpTarget {
target := new.Clone().(*TcpTarget)
update: func() *tcp.Target {
target := new.Clone().(*tcp.Target)
target.CreateTime = &ts
return target
}(),
@@ -51,8 +53,8 @@ func TestTarget_ImmutableFields(t *testing.T) {
},
{
name: "scope_id",
update: func() *TcpTarget {
target := new.Clone().(*TcpTarget)
update: func() *tcp.Target {
target := new.Clone().(*tcp.Target)
target.ScopeId = "o_thisIsNotAValidId"
return target
}(),
@@ -65,7 +67,7 @@ func TestTarget_ImmutableFields(t *testing.T) {
assert, require := assert.New(t), require.New(t)
orig := new.Clone()
orig.(*TcpTarget).SetTableName("target")
orig.(*tcp.Target).SetTableName("target")
err := rw.LookupById(context.Background(), orig)
require.NoError(err)
@@ -75,11 +77,11 @@ func TestTarget_ImmutableFields(t *testing.T) {
assert.Equal(0, rowsUpdated)
after := new.Clone()
after.(*TcpTarget).SetTableName("target")
after.(*tcp.Target).SetTableName("target")
err = rw.LookupById(context.Background(), after)
require.NoError(err)
assert.True(proto.Equal(orig.(*TcpTarget), after.(*TcpTarget)))
assert.True(proto.Equal(orig.(*tcp.Target), after.(*tcp.Target)))
})
}
}
@@ -93,17 +95,17 @@ func TestTcpTarget_ImmutableFields(t *testing.T) {
ts := timestamp.Timestamp{Timestamp: &timestamppb.Timestamp{Seconds: 0, Nanos: 0}}
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
new := TestTcpTarget(t, conn, proj.PublicId, testId(t))
new := tcp.TestTarget(t, conn, proj.PublicId, tcp.TestId(t))
tests := []struct {
name string
update *TcpTarget
update *tcp.Target
fieldMask []string
}{
{
name: "public_id",
update: func() *TcpTarget {
target := new.Clone().(*TcpTarget)
update: func() *tcp.Target {
target := new.Clone().(*tcp.Target)
target.PublicId = "p_thisIsNotAValidId"
return target
}(),
@@ -111,8 +113,8 @@ func TestTcpTarget_ImmutableFields(t *testing.T) {
},
{
name: "create time",
update: func() *TcpTarget {
target := new.Clone().(*TcpTarget)
update: func() *tcp.Target {
target := new.Clone().(*tcp.Target)
target.CreateTime = &ts
return target
}(),
@@ -120,8 +122,8 @@ func TestTcpTarget_ImmutableFields(t *testing.T) {
},
{
name: "scope_id",
update: func() *TcpTarget {
target := new.Clone().(*TcpTarget)
update: func() *tcp.Target {
target := new.Clone().(*tcp.Target)
target.ScopeId = "o_thisIsNotAValidId"
return target
}(),
@@ -144,7 +146,7 @@ func TestTcpTarget_ImmutableFields(t *testing.T) {
err = rw.LookupById(context.Background(), after)
require.NoError(err)
assert.True(proto.Equal(orig.(*TcpTarget), after.(*TcpTarget)))
assert.True(proto.Equal(orig.(*tcp.Target), after.(*tcp.Target)))
})
}
}
@@ -155,35 +157,35 @@ func TestTargetHostSet_ImmutableFields(t *testing.T) {
wrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
repo, err := NewRepository(rw, rw, testKms)
repo, err := target.NewRepository(rw, rw, testKms)
require.NoError(t, err)
ts := timestamp.Timestamp{Timestamp: &timestamppb.Timestamp{Seconds: 0, Nanos: 0}}
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
projTarget := TestTcpTarget(t, conn, proj.PublicId, testId(t))
projTarget := tcp.TestTarget(t, conn, proj.PublicId, tcp.TestId(t))
testCats := static.TestCatalogs(t, conn, proj.PublicId, 1)
hsets := static.TestSets(t, conn, testCats[0].GetPublicId(), 2)
require.Equal(t, 2, len(hsets))
updateTarget := TestTcpTarget(t, conn, proj.PublicId, testId(t))
updateTarget := tcp.TestTarget(t, conn, proj.PublicId, tcp.TestId(t))
updateHset := hsets[1]
_, gotHostSources, _, err := repo.AddTargetHostSources(context.Background(), projTarget.PublicId, 1, []string{hsets[0].PublicId})
require.NoError(t, err)
require.Equal(t, 1, len(gotHostSources))
new, err := NewTargetHostSet(projTarget.PublicId, gotHostSources[0].Id())
new, err := target.NewTargetHostSet(projTarget.PublicId, gotHostSources[0].Id())
require.NoError(t, err)
tests := []struct {
name string
update *TargetHostSet
update *target.TargetHostSet
fieldMask []string
}{
{
name: "target_id",
update: func() *TargetHostSet {
target := new.Clone().(*TargetHostSet)
update: func() *target.TargetHostSet {
target := new.Clone().(*target.TargetHostSet)
target.TargetId = updateTarget.PublicId
return target
}(),
@@ -191,8 +193,8 @@ func TestTargetHostSet_ImmutableFields(t *testing.T) {
},
{
name: "create time",
update: func() *TargetHostSet {
target := new.Clone().(*TargetHostSet)
update: func() *target.TargetHostSet {
target := new.Clone().(*target.TargetHostSet)
target.CreateTime = &ts
return target
}(),
@@ -200,8 +202,8 @@ func TestTargetHostSet_ImmutableFields(t *testing.T) {
},
{
name: "host_set_id",
update: func() *TargetHostSet {
target := new.Clone().(*TargetHostSet)
update: func() *target.TargetHostSet {
target := new.Clone().(*target.TargetHostSet)
target.HostSetId = updateHset.PublicId
return target
}(),
@@ -223,7 +225,7 @@ func TestTargetHostSet_ImmutableFields(t *testing.T) {
after := new.Clone()
err = rw.LookupWhere(context.Background(), after, "target_id = ? and host_set_id = ?", new.TargetId, new.HostSetId)
require.NoError(err)
assert.True(proto.Equal(orig.(*TargetHostSet), after.(*TargetHostSet)))
assert.True(proto.Equal(orig.(*target.TargetHostSet), after.(*target.TargetHostSet)))
})
}
}
+37
View File
@@ -0,0 +1,37 @@
package tcp
import (
"context"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/target"
)
func init() {
target.Register(Subtype, allocTarget, vet, TargetPrefix)
}
const (
// TargetPrefix is the prefix for public ids of a tcp.Target.
TargetPrefix = "ttcp"
)
// vet validates that the given target.Target is a tcp.Target and that it
// has a Target store.
func vet(ctx context.Context, t target.Target) error {
const op = "tcp.vet"
tt, ok := t.(*Target)
if !ok {
return errors.New(ctx, errors.InvalidParameter, op, "target is not a tcp.Target")
}
if tt == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing target")
}
if tt.Target == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing target store")
}
return nil
}
@@ -1,4 +1,4 @@
package target
package tcp_test
import (
"context"
@@ -12,6 +12,8 @@ import (
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
@@ -25,7 +27,7 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
testKms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, staticProj := iam.TestScopes(t, iamRepo)
repo, err := NewRepository(rw, rw, testKms)
repo, err := target.NewRepository(rw, rw, testKms)
require.NoError(t, err)
cs := vault.TestCredentialStores(t, conn, wrapper, staticProj.GetPublicId(), 1)[0]
@@ -103,7 +105,7 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
projTarget := TestTcpTarget(t, conn, staticProj.PublicId, tt.name)
projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, tt.name)
gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, tt.args.credLibIds)
if tt.wantErr {
require.Error(err)
@@ -112,7 +114,7 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
}
require.NoError(err)
assert.Len(gotCredSources, len(tt.wantCredLibIds))
gotCredSourcesMap := map[string]CredentialSource{}
gotCredSourcesMap := map[string]target.CredentialSource{}
for _, s := range gotCredSources {
gotCredSourcesMap[s.Id()] = s
}
@@ -124,26 +126,22 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
err = db.TestVerifyOplog(t, rw, projTarget.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
assert.NoError(err)
foundCredSources, err := fetchCredentialSources(context.Background(), rw, projTarget.PublicId)
tar, _, lookupCredSources, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
require.NoError(err)
assert.Len(foundCredSources, len(gotCredSourcesMap))
for _, s := range foundCredSources {
assert.Equal(tt.args.targetVersion+1, tar.GetVersion())
assert.Equal(projTarget.GetVersion(), tar.GetVersion()-1)
assert.True(proto.Equal(gotTarget.(*tcp.Target), tar.(*tcp.Target)))
assert.Equal(gotCredSources, lookupCredSources)
for _, s := range lookupCredSources {
assert.NotEmpty(gotCredSourcesMap[s.Id()])
assert.Equal(projTarget.PublicId, s.TargetId())
}
target, _, lookupCredSources, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
require.NoError(err)
assert.Equal(tt.args.targetVersion+1, target.GetVersion())
assert.Equal(projTarget.GetVersion(), target.GetVersion()-1)
assert.True(proto.Equal(gotTarget.(*TcpTarget), target.(*TcpTarget)))
assert.Equal(gotCredSources, lookupCredSources)
})
}
t.Run("add-existing", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
projTarget := TestTcpTarget(t, conn, staticProj.PublicId, "add-existing")
projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, "add-existing")
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []string{lib1.PublicId})
require.NoError(err)
assert.Len(gotCredSources, 1)
@@ -160,10 +158,10 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
assert.True(errors.Match(errors.T(errors.NotUnique), err))
// Previous transactions should have been rolled back and only lib1 should be associated
gotCredSources, err = fetchCredentialSources(context.Background(), rw, projTarget.PublicId)
_, _, lookupCredSources, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
require.NoError(err)
assert.Len(gotCredSources, 1)
assert.Equal(lib1.PublicId, gotCredSources[0].Id())
assert.Len(lookupCredSources, 1)
assert.Equal(lib1.PublicId, lookupCredSources[0].Id())
})
t.Run("target-not-found", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
@@ -183,7 +181,7 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
testKms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, proj := iam.TestScopes(t, iamRepo)
repo, err := NewRepository(rw, rw, testKms)
repo, err := target.NewRepository(rw, rw, testKms)
require.NoError(t, err)
type args struct {
@@ -229,7 +227,7 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
{
name: "not-found",
args: args{
targetIdOverride: func() *string { id := testId(t); return &id }(),
targetIdOverride: func() *string { id := tcp.TestId(t); return &id }(),
createCnt: 5,
deleteCnt: 5,
},
@@ -277,7 +275,7 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
assert, require := assert.New(t), require.New(t)
cs := css[i]
target := TestTcpTarget(t, conn, proj.PublicId, tt.name)
target := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
clIds := make([]string, 0, tt.args.createCnt)
if tt.args.createCnt > 0 {
@@ -334,7 +332,7 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
lib2 := libs[1]
lib3 := libs[2]
projTarget := TestTcpTarget(t, conn, proj.PublicId, "add-existing")
projTarget := tcp.TestTarget(t, conn, proj.PublicId, "add-existing")
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []string{lib1.PublicId, lib2.PublicId})
require.NoError(err)
assert.Len(gotCredSources, 2)
@@ -352,9 +350,9 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
assert.Equal(0, delCount)
// Previous transactions should have been rolled back and only lib1 should be associated
gotCredSources, err = fetchCredentialSources(context.Background(), rw, projTarget.PublicId)
_, _, lookupCredSources, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
require.NoError(err)
assert.Len(gotCredSources, 2)
assert.Len(lookupCredSources, 2)
})
}
@@ -364,7 +362,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
rw := db.New(conn)
wrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, conn, wrapper)
repo, err := NewRepository(rw, rw, testKms)
repo, err := target.NewRepository(rw, rw, testKms)
require.NoError(t, err)
iamRepo := iam.TestRepo(t, conn, wrapper)
@@ -375,7 +373,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
lib1 := credLibs[0]
lib2 := credLibs[1]
setupFn := func(target Target) []CredentialSource {
setupFn := func(target target.Target) []target.CredentialSource {
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 10)
clIds := make([]string, 0, len(credLibs))
for _, cl := range credLibs {
@@ -394,7 +392,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
}
tests := []struct {
name string
setup func(Target) []CredentialSource
setup func(target.Target) []target.CredentialSource
args args
wantAffectedRows int
wantErr bool
@@ -470,11 +468,11 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
target := TestTcpTarget(t, conn, proj.PublicId, tt.name)
tar := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
var origCredSources []CredentialSource
var origCredSources []target.CredentialSource
if tt.setup != nil {
origCredSources = tt.setup(target)
origCredSources = tt.setup(tar)
}
if tt.args.addToOrigLibs {
origIds := make([]string, 0, len(origCredSources))
@@ -484,11 +482,11 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
tt.args.clIds = append(tt.args.clIds, origIds...)
}
origTarget, _, lookupCredSources, err := repo.LookupTarget(context.Background(), target.GetPublicId())
origTarget, _, lookupCredSources, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
require.NoError(err)
assert.Equal(origCredSources, lookupCredSources)
_, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), target.GetPublicId(), tt.args.targetVersion, tt.args.clIds)
_, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, tt.args.clIds)
if tt.wantErr {
require.Error(err)
assert.Equal(0, affectedRows)
@@ -514,7 +512,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
sort.Strings(gotIds)
assert.Equal(wantIds, gotIds)
foundTarget, _, _, err := repo.LookupTarget(context.Background(), target.GetPublicId())
foundTarget, _, _, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
require.NoError(err)
if tt.name != "no-change" {
assert.Equalf(tt.args.targetVersion+1, foundTarget.GetVersion(), "%s unexpected version: %d/%d", tt.name, tt.args.targetVersion+1, foundTarget.GetVersion())
@@ -1,4 +1,4 @@
package target
package tcp_test
import (
"context"
@@ -12,11 +12,20 @@ import (
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target"
targetstore "github.com/hashicorp/boundary/internal/target/store"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
func allocTargetHostSet() target.TargetHostSet {
return target.TargetHostSet{
TargetHostSet: &targetstore.TargetHostSet{},
}
}
func TestRepository_AddTargetHostSets(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
@@ -25,7 +34,7 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
testKms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
staticOrg, staticProj := iam.TestScopes(t, iamRepo)
repo, err := NewRepository(rw, rw, testKms)
repo, err := target.NewRepository(rw, rw, testKms)
require.NoError(t, err)
createHostSetsFn := func(orgs, projects []string) []string {
@@ -46,7 +55,7 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
type args struct {
targetVersion uint32
wantTargetIds bool
opt []Option
opt []target.Option
}
tests := []struct {
name string
@@ -90,9 +99,9 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
require.NoError(conn.Where("1=1").Delete(allocTargetHostSet()).Error)
require.NoError(conn.Where("1=1").Delete(allocTcpTarget()).Error)
require.NoError(conn.Where("1=1").Delete(tcp.NewTestTarget("")).Error)
projTarget := TestTcpTarget(t, conn, staticProj.PublicId, "static-proj")
projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, "static-proj")
var hostSourceIds []string
origTarget, origHostSet, _, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
@@ -124,7 +133,7 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
return
}
require.NoError(err)
gotHostSet := map[string]HostSource{}
gotHostSet := map[string]target.HostSource{}
for _, s := range gotHostSources {
gotHostSet[s.Id()] = s
}
@@ -141,18 +150,15 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
err = db.TestVerifyOplog(t, rw, projTarget.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
assert.NoError(err)
foundHostSources, err := fetchHostSources(context.Background(), rw, projTarget.PublicId)
tar, ths, _, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
require.NoError(err)
for _, s := range foundHostSources {
assert.Equal(tt.args.targetVersion+1, tar.GetVersion())
assert.Equal(origTarget.GetVersion(), tar.GetVersion()-1)
assert.Equal(gotHostSources, ths)
assert.True(proto.Equal(gotTarget.(*tcp.Target), tar.(*tcp.Target)))
for _, s := range ths {
assert.NotEmpty(gotHostSet[s.Id()])
}
target, ths, _, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
require.NoError(err)
assert.Equal(tt.args.targetVersion+1, target.GetVersion())
assert.Equal(origTarget.GetVersion(), target.GetVersion()-1)
assert.Equal(gotHostSources, ths)
assert.True(proto.Equal(gotTarget.(*TcpTarget), target.(*TcpTarget)))
})
}
t.Run("add-existing", func(t *testing.T) {
@@ -164,7 +170,7 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
hs2 := hsets[1]
hs3 := hsets[2]
projTarget := TestTcpTarget(t, conn, staticProj.PublicId, "add-existing")
projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, "add-existing")
_, gotHostSources, _, err := repo.AddTargetHostSources(context.Background(), projTarget.PublicId, 1, []string{hs1.PublicId})
require.NoError(err)
assert.Len(gotHostSources, 1)
@@ -181,7 +187,7 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
assert.True(errors.Match(errors.T(errors.NotUnique), err))
// Previous transactions should have been rolled back and only hs1 should be associated
gotHostSources, err = fetchHostSources(context.Background(), rw, projTarget.PublicId)
_, gotHostSources, _, err = repo.LookupTarget(context.Background(), projTarget.PublicId)
require.NoError(err)
assert.Len(gotHostSources, 1)
assert.Equal(hs1.PublicId, gotHostSources[0].Id())
@@ -196,16 +202,16 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
testKms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, proj := iam.TestScopes(t, iamRepo)
repo, err := NewRepository(rw, rw, testKms)
repo, err := target.NewRepository(rw, rw, testKms)
require.NoError(t, err)
type args struct {
target Target
target target.Target
targetIdOverride *string
targetVersionOverride *uint32
createCnt int
deleteCnt int
opt []Option
opt []target.Option
}
tests := []struct {
name string
@@ -217,7 +223,7 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
{
name: "valid",
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "valid"),
target: tcp.TestTarget(t, conn, proj.PublicId, "valid"),
createCnt: 5,
deleteCnt: 5,
},
@@ -227,7 +233,7 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
{
name: "valid-keeping-some",
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "valid-keeping-some"),
target: tcp.TestTarget(t, conn, proj.PublicId, "valid-keeping-some"),
createCnt: 5,
deleteCnt: 2,
},
@@ -237,7 +243,7 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
{
name: "no-deletes",
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "no-deletes"),
target: tcp.TestTarget(t, conn, proj.PublicId, "no-deletes"),
createCnt: 5,
},
wantRowsDeleted: 0,
@@ -247,8 +253,8 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
{
name: "not-found",
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "not-found"),
targetIdOverride: func() *string { id := testId(t); return &id }(),
target: tcp.TestTarget(t, conn, proj.PublicId, "not-found"),
targetIdOverride: func() *string { id := tcp.TestId(t); return &id }(),
createCnt: 5,
deleteCnt: 5,
},
@@ -258,7 +264,7 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
{
name: "missing-target-id",
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "missing-target-id"),
target: tcp.TestTarget(t, conn, proj.PublicId, "missing-target-id"),
targetIdOverride: func() *string { id := ""; return &id }(),
createCnt: 5,
deleteCnt: 5,
@@ -270,7 +276,7 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
{
name: "zero-version",
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "zero-version"),
target: tcp.TestTarget(t, conn, proj.PublicId, "zero-version"),
targetVersionOverride: func() *uint32 { v := uint32(0); return &v }(),
createCnt: 5,
deleteCnt: 5,
@@ -282,7 +288,7 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
{
name: "bad-version",
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "bad-version"),
target: tcp.TestTarget(t, conn, proj.PublicId, "bad-version"),
targetVersionOverride: func() *uint32 { v := uint32(1000); return &v }(),
createCnt: 5,
deleteCnt: 5,
@@ -367,7 +373,7 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
hs2 := hsets[1]
hs3 := hsets[2]
projTarget := TestTcpTarget(t, conn, proj.PublicId, "delete-unassociated")
projTarget := tcp.TestTarget(t, conn, proj.PublicId, "delete-unassociated")
_, gotHostSources, _, err := repo.AddTargetHostSources(context.Background(), projTarget.PublicId, 1, []string{hs1.PublicId, hs2.PublicId})
require.NoError(err)
assert.Len(gotHostSources, 2)
@@ -386,7 +392,7 @@ func TestRepository_DeleteTargetHosts(t *testing.T) {
assert.Equal(0, delCount)
// Previous transactions should have been rolled back
gotHostSources, err = fetchHostSources(context.Background(), rw, projTarget.PublicId)
_, gotHostSources, _, err = repo.LookupTarget(context.Background(), projTarget.PublicId)
require.NoError(err)
assert.Len(gotHostSources, 2)
})
@@ -398,7 +404,7 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
rw := db.New(conn)
wrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, conn, wrapper)
repo, err := NewRepository(rw, rw, testKms)
repo, err := target.NewRepository(rw, rw, testKms)
require.NoError(t, err)
iamRepo := iam.TestRepo(t, conn, wrapper)
@@ -421,7 +427,7 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
return results
}
setupFn := func(target Target) []HostSource {
setupFn := func(target target.Target) []target.HostSource {
hs := createHostSetsFn()
_, created, _, err := repo.AddTargetHostSources(context.Background(), target.GetPublicId(), 1, hs)
require.NoError(t, err)
@@ -429,15 +435,15 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
return created
}
type args struct {
target Target
target target.Target
targetVersion uint32
hostSourceIds []string
addToOrigHostSources bool
opt []Option
opt []target.Option
}
tests := []struct {
name string
setup func(Target) []HostSource
setup func(target.Target) []target.HostSource
args args
wantAffectedRows int
wantErr bool
@@ -446,7 +452,7 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
name: "clear",
setup: setupFn,
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "clear"),
target: tcp.TestTarget(t, conn, proj.PublicId, "clear"),
targetVersion: 2, // yep, since setupFn will increment it to 2
hostSourceIds: []string{},
},
@@ -457,7 +463,7 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
name: "no-change",
setup: setupFn,
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "no-change"),
target: tcp.TestTarget(t, conn, proj.PublicId, "no-change"),
targetVersion: 2, // yep, since setupFn will increment it to 2
hostSourceIds: []string{},
addToOrigHostSources: true,
@@ -469,7 +475,7 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
name: "add-sets",
setup: setupFn,
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "add-sets"),
target: tcp.TestTarget(t, conn, proj.PublicId, "add-sets"),
targetVersion: 2, // yep, since setupFn will increment it to 2
hostSourceIds: []string{testHostSetIds[0], testHostSetIds[1]},
addToOrigHostSources: true,
@@ -481,7 +487,7 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
name: "add host sets with zero version",
setup: setupFn,
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "add host sets with zero version"),
target: tcp.TestTarget(t, conn, proj.PublicId, "add host sets with zero version"),
targetVersion: 0,
hostSourceIds: []string{testHostSetIds[0], testHostSetIds[1]},
addToOrigHostSources: true,
@@ -492,7 +498,7 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
name: "remove existing and add users and grps",
setup: setupFn,
args: args{
target: TestTcpTarget(t, conn, proj.PublicId, "remove existing and add host sets"),
target: tcp.TestTarget(t, conn, proj.PublicId, "remove existing and add host sets"),
targetVersion: 2, // yep, since setupFn will increment it to 2
hostSourceIds: []string{testHostSetIds[0], testHostSetIds[1]},
addToOrigHostSources: false,
@@ -504,7 +510,7 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
var origHostSources []HostSource
var origHostSources []target.HostSource
if tt.setup != nil {
origHostSources = tt.setup(tt.args.target)
}
Loaded 100 of 146 files, more files were not shown because too many files have changed in this diff. Show more