Use authenticate and Auth Method repo functions (#242)
This commit is contained in:
1 parent
908a299ea3
commit
f84991c0f1
17 files changed
+324
-184
No files matched your search
+14
-12
@@ -367,19 +367,21 @@ func (v verifier) performAuthCheck() (aclResults *perms.ACLResults, userId strin
|
||||
userId = "u_anon"
|
||||
|
||||
// Validate the token and fetch the corresponding user ID
|
||||
tokenRepo, err := v.authTokenRepoFn()
|
||||
if err != nil {
|
||||
retErr = fmt.Errorf("perform auth check: failed to get authtoken repo: %w", err)
|
||||
return
|
||||
}
|
||||
if v.requestInfo.TokenFormat != AuthTokenTypeUnknown {
|
||||
tokenRepo, err := v.authTokenRepoFn()
|
||||
if err != nil {
|
||||
retErr = fmt.Errorf("perform auth check: failed to get authtoken repo: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
at, err := tokenRepo.ValidateToken(v.ctx, v.requestInfo.PublicId, v.requestInfo.Token)
|
||||
if err != nil {
|
||||
retErr = fmt.Errorf("perform auth check: failed to validate token: %w", err)
|
||||
return
|
||||
}
|
||||
if at != nil {
|
||||
userId = at.GetIamUserId()
|
||||
at, err := tokenRepo.ValidateToken(v.ctx, v.requestInfo.PublicId, v.requestInfo.Token)
|
||||
if err != nil {
|
||||
retErr = fmt.Errorf("perform auth check: failed to validate token: %w", err)
|
||||
return
|
||||
}
|
||||
if at != nil {
|
||||
userId = at.GetIamUserId()
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch and parse grants for this user ID (which may include grants for
|
||||
|
||||
@@ -18,6 +18,7 @@ type options struct {
|
||||
withDescription string
|
||||
withLimit int
|
||||
withConfig Configuration
|
||||
withPublicId string
|
||||
password string
|
||||
withPassword bool
|
||||
}
|
||||
@@ -28,6 +29,13 @@ func getDefaultOptions() options {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPublicId provides an optional public id
|
||||
func WithPublicId(id string) Option {
|
||||
return func(o *options) {
|
||||
o.withPublicId = id
|
||||
}
|
||||
}
|
||||
|
||||
// WithDescription provides an optional description.
|
||||
func WithDescription(desc string) Option {
|
||||
return func(o *options) {
|
||||
|
||||
@@ -9,6 +9,12 @@ import (
|
||||
|
||||
func Test_GetOpts(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("WithPublicId", func(t *testing.T) {
|
||||
opts := getOpts(WithPublicId("test id"))
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withPublicId = "test id"
|
||||
assert.Equal(t, opts, testOpts)
|
||||
})
|
||||
t.Run("WithName", func(t *testing.T) {
|
||||
opts := getOpts(WithName("test"))
|
||||
testOpts := getDefaultOptions()
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
// contain a valid ScopeId. m must not contain a PublicId. The PublicId is
|
||||
// generated and assigned by this method.
|
||||
//
|
||||
// WithConfiguration is the only valid option. All other options are
|
||||
// ignored.
|
||||
// WithConfiguration and WithPublicId are the only valid options. All other
|
||||
// options are ignored.
|
||||
//
|
||||
// Both m.Name and m.Description are optional. If m.Name is set, it must be
|
||||
// unique within m.ScopeId.
|
||||
@@ -36,13 +36,21 @@ func (r *Repository) CreateAuthMethod(ctx context.Context, m *AuthMethod, opt ..
|
||||
}
|
||||
m = m.clone()
|
||||
|
||||
id, err := newAuthMethodId()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create: password auth method: %w", err)
|
||||
}
|
||||
m.PublicId = id
|
||||
|
||||
opts := getOpts(opt...)
|
||||
|
||||
if opts.withPublicId != "" {
|
||||
if !strings.HasPrefix(opts.withPublicId, AuthMethodPrefix+"_") {
|
||||
return nil, fmt.Errorf("create: password auth method: passed-in public ID %q has wrong prefix, should be %q: %w", opts.withPublicId, AuthMethodPrefix, db.ErrInvalidPublicId)
|
||||
}
|
||||
m.PublicId = opts.withPublicId
|
||||
} else {
|
||||
id, err := newAuthMethodId()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create: password auth method: %w", err)
|
||||
}
|
||||
m.PublicId = id
|
||||
}
|
||||
|
||||
c, ok := opts.withConfig.(*Argon2Configuration)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("create: password auth method: unknown configuration: %w", ErrUnsupportedConfiguration)
|
||||
@@ -51,6 +59,7 @@ func (r *Repository) CreateAuthMethod(ctx context.Context, m *AuthMethod, opt ..
|
||||
return nil, fmt.Errorf("create: password auth method: %w", err)
|
||||
}
|
||||
|
||||
var err error
|
||||
c.PrivateId, err = newArgon2ConfigurationId()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create: password auth method: %w", err)
|
||||
|
||||
@@ -215,6 +215,42 @@ func TestRepository_CreateAuthMethod(t *testing.T) {
|
||||
assert.Equal(in2.Description, got2.Description)
|
||||
assert.Equal(got2.CreateTime, got2.UpdateTime)
|
||||
})
|
||||
|
||||
t.Run("valid-with-publicid", func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
repo, err := NewRepository(rw, rw, wrapper)
|
||||
require.NoError(err)
|
||||
require.NotNil(repo)
|
||||
|
||||
org1, _ := iam.TestScopes(t, conn)
|
||||
in := allocAuthMethod()
|
||||
|
||||
amId, err := newAuthMethodId()
|
||||
require.NoError(err)
|
||||
|
||||
in.ScopeId = org1.GetPublicId()
|
||||
got, err := repo.CreateAuthMethod(context.Background(), &in, WithPublicId(amId))
|
||||
require.NoError(err)
|
||||
require.NotNil(got)
|
||||
assert.Equal(amId, got.GetPublicId())
|
||||
assert.Equal(got.CreateTime, got.UpdateTime)
|
||||
})
|
||||
|
||||
t.Run("invalid-with-badpublicid", func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
repo, err := NewRepository(rw, rw, wrapper)
|
||||
require.NoError(err)
|
||||
require.NotNil(repo)
|
||||
|
||||
org1, _ := iam.TestScopes(t, conn)
|
||||
in := allocAuthMethod()
|
||||
|
||||
in.ScopeId = org1.GetPublicId()
|
||||
got, err := repo.CreateAuthMethod(context.Background(), &in, WithPublicId("invalid_idwithabadprefix"))
|
||||
assert.Error(err)
|
||||
assert.Nil(got)
|
||||
assert.True(errors.Is(err, db.ErrInvalidPublicId))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRepository_LookupAuthMethod(t *testing.T) {
|
||||
|
||||
@@ -21,13 +21,14 @@ import (
|
||||
"github.com/hashicorp/vault/internalshared/configutil"
|
||||
"github.com/hashicorp/vault/internalshared/gatedwriter"
|
||||
"github.com/hashicorp/vault/internalshared/reloadutil"
|
||||
"github.com/hashicorp/vault/sdk/helper/base62"
|
||||
"github.com/hashicorp/vault/sdk/helper/logging"
|
||||
"github.com/hashicorp/vault/sdk/helper/mlock"
|
||||
"github.com/hashicorp/vault/sdk/logical"
|
||||
"github.com/hashicorp/watchtower/globals"
|
||||
"github.com/hashicorp/watchtower/internal/auth/password"
|
||||
"github.com/hashicorp/watchtower/internal/db"
|
||||
"github.com/hashicorp/watchtower/internal/iam"
|
||||
"github.com/hashicorp/watchtower/internal/servers/controller/handlers/authenticate"
|
||||
"github.com/hashicorp/watchtower/version"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/mitchellh/cli"
|
||||
@@ -62,6 +63,8 @@ type Server struct {
|
||||
|
||||
DefaultOrgId string
|
||||
DevAuthMethodId string
|
||||
DevUsername string
|
||||
DevPassword string
|
||||
|
||||
DevDatabaseUrl string
|
||||
DevDatabaseCleanupFunc func() error
|
||||
@@ -381,8 +384,13 @@ func (b *Server) RunShutdownFuncs() error {
|
||||
|
||||
func (b *Server) CreateDevDatabase(dialect string) error {
|
||||
c, url, container, err := db.InitDbInDocker(dialect)
|
||||
if err != nil {
|
||||
// In case of an error, run the cleanup function. If we pass all errors, c should be set to a noop
|
||||
// function before returning from this method
|
||||
defer func() {
|
||||
c()
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to start dev database with dialect %s: %w", dialect, err)
|
||||
}
|
||||
|
||||
@@ -398,7 +406,6 @@ func (b *Server) CreateDevDatabase(dialect string) error {
|
||||
|
||||
dbase, err := gorm.Open(dialect, url)
|
||||
if err != nil {
|
||||
c()
|
||||
return fmt.Errorf("unable to create db object with dialect %s: %w", dialect, err)
|
||||
}
|
||||
b.Database = dbase
|
||||
@@ -410,7 +417,6 @@ func (b *Server) CreateDevDatabase(dialect string) error {
|
||||
rw := db.New(b.Database)
|
||||
repo, err := iam.NewRepository(rw, rw, b.ControllerKMS)
|
||||
if err != nil {
|
||||
c()
|
||||
return fmt.Errorf("unable to create repo for org id: %w", err)
|
||||
}
|
||||
|
||||
@@ -424,7 +430,6 @@ func (b *Server) CreateDevDatabase(dialect string) error {
|
||||
if b.DefaultOrgId != "" {
|
||||
orgScope, err = repo.LookupScope(ctx, b.DefaultOrgId)
|
||||
if err != nil {
|
||||
c()
|
||||
return fmt.Errorf("error looking up existing scope with org ID %q: %w", b.DefaultOrgId, err)
|
||||
}
|
||||
}
|
||||
@@ -432,17 +437,14 @@ func (b *Server) CreateDevDatabase(dialect string) error {
|
||||
if orgScope == nil {
|
||||
orgScope, err = iam.NewOrg()
|
||||
if err != nil {
|
||||
c()
|
||||
return fmt.Errorf("error creating new org scope: %w", err)
|
||||
}
|
||||
orgScope, err = repo.CreateScope(ctx, orgScope, iam.WithPublicId(b.DefaultOrgId))
|
||||
if err != nil {
|
||||
c()
|
||||
return fmt.Errorf("error persisting new org scope: %w", err)
|
||||
}
|
||||
if b.DefaultOrgId != "" {
|
||||
if orgScope.GetPublicId() != b.DefaultOrgId {
|
||||
c()
|
||||
return fmt.Errorf("expected org ID %q, got %q after persisting", b.DefaultOrgId, orgScope.GetPublicId())
|
||||
}
|
||||
} else {
|
||||
@@ -480,27 +482,59 @@ func (b *Server) CreateDevDatabase(dialect string) error {
|
||||
return fmt.Errorf("error adding principal to role for default dev grants: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Remove this when Auth Account repo is in place.
|
||||
authenticate.Scope = orgScope.GetPublicId()
|
||||
insert := `insert into auth_method
|
||||
(public_id, scope_id)
|
||||
values
|
||||
($1, $2);`
|
||||
pwRepo, err := password.NewRepository(rw, rw, b.ControllerKMS)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating password repo: %w", err)
|
||||
}
|
||||
authMethod, err := password.NewAuthMethod(orgScope.GetPublicId())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating new in memory auth method: %w", err)
|
||||
}
|
||||
|
||||
amId := b.DevAuthMethodId
|
||||
if amId == "" {
|
||||
amId = "am_1234567890"
|
||||
amId = "paum_1234567890"
|
||||
}
|
||||
authenticate.RWDb.Store(rw)
|
||||
_, err = b.Database.DB().Exec(insert, amId, orgScope.GetPublicId())
|
||||
authMethod, err = pwRepo.CreateAuthMethod(ctx, authMethod, password.WithPublicId(amId))
|
||||
if err != nil {
|
||||
c()
|
||||
return err
|
||||
return fmt.Errorf("error saving auth method to the db: %w", err)
|
||||
}
|
||||
|
||||
b.InfoKeys = append(b.InfoKeys, "dev org id", "dev auth method id")
|
||||
acctUserName := b.DevUsername
|
||||
if acctUserName == "" {
|
||||
acctUserName, err = base62.Random(10)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to generate dev username: %w", err)
|
||||
}
|
||||
acctUserName = strings.ToLower(acctUserName)
|
||||
}
|
||||
|
||||
pw := b.DevPassword
|
||||
if pw == "" {
|
||||
pw, err = base62.Random(20)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to generate dev password: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
acct, err := password.NewAccount(amId, acctUserName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating new in memory auth account: %w", err)
|
||||
}
|
||||
acct, err = pwRepo.CreateAccount(ctx, acct, password.WithPassword(pw))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error saving auth account to the db: %w", err)
|
||||
}
|
||||
|
||||
b.InfoKeys = append(b.InfoKeys, "dev org id", "dev auth method id", "dev username", "dev password")
|
||||
b.Info["dev org id"] = b.DefaultOrgId
|
||||
b.Info["dev auth method id"] = amId
|
||||
b.Info["dev username"] = acct.GetUserName()
|
||||
b.Info["dev password"] = pw
|
||||
|
||||
// now that we have passed all the error cases, reset c to be a noop so the
|
||||
// defer doesn't do anything.
|
||||
c = func() error { return nil }
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/hashicorp/vault/sdk/helper/mlock"
|
||||
"github.com/hashicorp/vault/sdk/helper/strutil"
|
||||
"github.com/hashicorp/watchtower/globals"
|
||||
"github.com/hashicorp/watchtower/internal/auth/password"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/base"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/config"
|
||||
"github.com/hashicorp/watchtower/internal/servers/controller"
|
||||
@@ -44,7 +45,8 @@ type Command struct {
|
||||
flagLogFormat string
|
||||
flagCombineLogs bool
|
||||
flagDev bool
|
||||
flagDevAdminPassword string
|
||||
flagDevUsername string
|
||||
flagDevPassword string
|
||||
flagDevControllerAPIListenAddr string
|
||||
flagDevControllerClusterListenAddr string
|
||||
flagDevOrgId string
|
||||
@@ -129,13 +131,21 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-admin-password",
|
||||
Target: &c.flagDevAdminPassword,
|
||||
EnvVar: "WATCHTWER_DEV_ADMIN_PASSWORD",
|
||||
Name: "dev-password",
|
||||
Target: &c.flagDevPassword,
|
||||
EnvVar: "WATCHTWER_DEV_PASSWORD",
|
||||
Usage: "Initial admin password. This only applies when running in \"dev\" " +
|
||||
"mode.",
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-username",
|
||||
Target: &c.flagDevUsername,
|
||||
EnvVar: "WATCHTWER_DEV_USERNAME",
|
||||
Usage: "Initial admin username. This only applies when running in \"dev\" " +
|
||||
"mode.",
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-api-listen-address",
|
||||
Target: &c.flagDevControllerAPIListenAddr,
|
||||
@@ -322,11 +332,16 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
|
||||
case len(c.flagConfig) == 0:
|
||||
c.UI.Error("Must specify a config file using -config")
|
||||
return 1
|
||||
case c.flagDevAdminPassword != "":
|
||||
case c.flagDevPassword != "":
|
||||
c.UI.Warn(base.WrapAtLength(
|
||||
"You cannot specify a custom admin password outside of \"dev\" mode. " +
|
||||
"Your request has been ignored."))
|
||||
c.flagDevAdminPassword = ""
|
||||
c.flagDevPassword = ""
|
||||
case c.flagDevUsername != "":
|
||||
c.UI.Warn(base.WrapAtLength(
|
||||
"You cannot specify a custom admin username outside of \"dev\" mode. " +
|
||||
"Your request has been ignored."))
|
||||
c.flagDevUsername = ""
|
||||
}
|
||||
|
||||
c.Config, err = config.LoadFile(c.flagConfig, c.configKMS)
|
||||
@@ -346,16 +361,23 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
|
||||
c.Config.DefaultOrgId = c.flagDevOrgId
|
||||
}
|
||||
if c.flagDevAuthMethodId != "" {
|
||||
if !strings.HasPrefix(c.flagDevAuthMethodId, "am_") {
|
||||
c.UI.Error(fmt.Sprintf("Invalid dev auth method ID, must start with %q", "am_"))
|
||||
prefix := password.AuthMethodPrefix + "_"
|
||||
if !strings.HasPrefix(c.flagDevAuthMethodId, prefix) {
|
||||
c.UI.Error(fmt.Sprintf("Invalid dev auth method ID, must start with %q", prefix))
|
||||
return 1
|
||||
}
|
||||
if len(c.flagDevAuthMethodId) != 13 {
|
||||
c.UI.Error(fmt.Sprintf("Invalid dev auth method ID, must be 10 base62 characters after %q", "am_"))
|
||||
c.UI.Error(fmt.Sprintf("Invalid dev auth method ID, must be 10 base62 characters after %q", prefix))
|
||||
return 1
|
||||
}
|
||||
c.DevAuthMethodId = c.flagDevAuthMethodId
|
||||
}
|
||||
if c.flagDevUsername != "" {
|
||||
c.DevUsername = c.flagDevUsername
|
||||
}
|
||||
if c.flagDevPassword != "" {
|
||||
c.DevPassword = c.flagDevPassword
|
||||
}
|
||||
|
||||
c.Config.PassthroughDirectory = c.flagDevPassthroughDirectory
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/watchtower/internal/auth/password"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/base"
|
||||
controllercmd "github.com/hashicorp/watchtower/internal/cmd/commands/controller"
|
||||
workercmd "github.com/hashicorp/watchtower/internal/cmd/commands/worker"
|
||||
@@ -34,7 +35,8 @@ type Command struct {
|
||||
flagLogFormat string
|
||||
flagCombineLogs bool
|
||||
flagDev bool
|
||||
flagDevAdminPassword string
|
||||
flagDevUsername string
|
||||
flagDevPassword string
|
||||
flagDevOrgId string
|
||||
flagDevAuthMethodId string
|
||||
flagDevControllerAPIListenAddr string
|
||||
@@ -102,13 +104,21 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-admin-password",
|
||||
Target: &c.flagDevAdminPassword,
|
||||
EnvVar: "WATCHTWER_DEV_ADMIN_PASSWORD",
|
||||
Name: "dev-password",
|
||||
Target: &c.flagDevPassword,
|
||||
EnvVar: "WATCHTWER_DEV_PASSWORD",
|
||||
Usage: "Initial admin password. This only applies when running in \"dev\" " +
|
||||
"mode.",
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-username",
|
||||
Target: &c.flagDevUsername,
|
||||
EnvVar: "WATCHTWER_DEV_USERNAME",
|
||||
Usage: "Initial admin username. This only applies when running in \"dev\" " +
|
||||
"mode.",
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-api-listen-address",
|
||||
Target: &c.flagDevControllerAPIListenAddr,
|
||||
@@ -165,16 +175,23 @@ func (c *Command) Run(args []string) int {
|
||||
devConfig.DefaultOrgId = c.flagDevOrgId
|
||||
}
|
||||
if c.flagDevAuthMethodId != "" {
|
||||
if !strings.HasPrefix(c.flagDevAuthMethodId, "am_") {
|
||||
c.UI.Error(fmt.Sprintf("Invalid dev auth method ID, must start with %q", "am_"))
|
||||
prefix := password.AuthMethodPrefix + "_"
|
||||
if !strings.HasPrefix(c.flagDevAuthMethodId, prefix) {
|
||||
c.UI.Error(fmt.Sprintf("Invalid dev auth method ID, must start with %q", prefix))
|
||||
return 1
|
||||
}
|
||||
if len(c.flagDevAuthMethodId) != 13 {
|
||||
c.UI.Error(fmt.Sprintf("Invalid dev auth method ID, must be 10 base62 characters after %q", "am_"))
|
||||
c.UI.Error(fmt.Sprintf("Invalid dev auth method ID, must be 10 base62 characters after %q", prefix))
|
||||
return 1
|
||||
}
|
||||
c.DevAuthMethodId = c.flagDevAuthMethodId
|
||||
}
|
||||
if c.flagDevUsername != "" {
|
||||
c.DevUsername = c.flagDevUsername
|
||||
}
|
||||
if c.flagDevPassword != "" {
|
||||
c.DevPassword = c.flagDevPassword
|
||||
}
|
||||
|
||||
devConfig.PassthroughDirectory = c.flagDevPassthroughDirectory
|
||||
|
||||
|
||||
@@ -1879,7 +1879,7 @@
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"title": "Optional user-set descripton for identification purposes"
|
||||
"title": "Optional user-set description for identification purposes"
|
||||
},
|
||||
"created_time": {
|
||||
"type": "string",
|
||||
|
||||
@@ -44,7 +44,7 @@ type AuthMethod struct {
|
||||
Scope *scopes.ScopeInfo `protobuf:"bytes,2,opt,name=scope,proto3" json:"scope,omitempty"`
|
||||
// Optional name for identification purposes
|
||||
Name *wrappers.StringValue `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
|
||||
// Optional user-set descripton for identification purposes
|
||||
// Optional user-set description for identification purposes
|
||||
Description *wrappers.StringValue `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"`
|
||||
// The time this resource was created
|
||||
// Output only.
|
||||
|
||||
@@ -23,7 +23,7 @@ message AuthMethod {
|
||||
// Optional name for identification purposes
|
||||
google.protobuf.StringValue name = 3 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"name" that: "name"}];
|
||||
|
||||
// Optional user-set descripton for identification purposes
|
||||
// Optional user-set description for identification purposes
|
||||
google.protobuf.StringValue description = 4 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"description" that: "description"}];
|
||||
|
||||
// The time this resource was created
|
||||
|
||||
@@ -89,7 +89,7 @@ func handleGrpcGateway(c *Controller) (http.Handler, error) {
|
||||
if err := services.RegisterAccountServiceHandlerServer(ctx, mux, accts); err != nil {
|
||||
return nil, fmt.Errorf("failed to register account service handler: %w", err)
|
||||
}
|
||||
auths, err := authenticate.NewService(c.IamRepoFn, c.AuthTokenRepoFn)
|
||||
auths, err := authenticate.NewService(c.PasswordAuthRepoFn, c.IamRepoFn, c.AuthTokenRepoFn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create authentication handler service: %w", err)
|
||||
}
|
||||
|
||||
@@ -13,11 +13,16 @@ import (
|
||||
)
|
||||
|
||||
func TestAuthenticationHandler(t *testing.T) {
|
||||
c := NewTestController(t, &TestControllerOpts{DefaultOrgId: "o_1234567890"})
|
||||
c := NewTestController(t, &TestControllerOpts{
|
||||
DefaultOrgId: "o_1234567890",
|
||||
DisableAuthorizationFailures: true,
|
||||
DefaultUsername: "admin",
|
||||
DefaultPassword: "password123",
|
||||
})
|
||||
defer c.Shutdown()
|
||||
|
||||
resp, err := http.Post(fmt.Sprintf("%s/v1/scopes/o_1234567890/auth-methods/am_1234567890:authenticate", c.ApiAddrs()[0]), "application/json",
|
||||
strings.NewReader(`{"token_type": null, "credentials": {"name":"test", "password": "test"}}`))
|
||||
resp, err := http.Post(fmt.Sprintf("%s/v1/scopes/o_1234567890/auth-methods/paum_1234567890:authenticate", c.ApiAddrs()[0]), "application/json",
|
||||
strings.NewReader(`{"token_type": null, "credentials": {"name":"admin", "password": "password123"}}`))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode, "Got response: %v", resp)
|
||||
|
||||
|
||||
@@ -2,66 +2,66 @@ package authenticate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hashicorp/watchtower/internal/auth"
|
||||
"github.com/hashicorp/watchtower/internal/authtoken"
|
||||
"github.com/hashicorp/watchtower/internal/db"
|
||||
pba "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/authtokens"
|
||||
"github.com/hashicorp/watchtower/internal/gen/controller/api/resources/scopes"
|
||||
pbs "github.com/hashicorp/watchtower/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/watchtower/internal/iam"
|
||||
iamStore "github.com/hashicorp/watchtower/internal/iam/store"
|
||||
"github.com/hashicorp/watchtower/internal/servers/controller/common"
|
||||
"github.com/hashicorp/watchtower/internal/servers/controller/handlers"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const scopeIdFieldName = "scope_id"
|
||||
const (
|
||||
nameKey = "name"
|
||||
pwKey = "password"
|
||||
)
|
||||
|
||||
var (
|
||||
reInvalidID = regexp.MustCompile("[^A-Za-z0-9]")
|
||||
|
||||
// TODO: Remove once auth methods are in
|
||||
Scope string
|
||||
RWDb = new(atomic.Value)
|
||||
)
|
||||
|
||||
func init() {
|
||||
RWDb.Store((*db.Db)(nil))
|
||||
}
|
||||
|
||||
// Service handles request as described by the pbs.OrgServiceServer interface.
|
||||
type Service struct {
|
||||
pwRepo common.PasswordAuthRepoFactory
|
||||
iamRepo common.IamRepoFactory
|
||||
authTokenRepo common.AuthTokenRepoFactory
|
||||
}
|
||||
|
||||
// NewService returns an org service which handles org related requests to watchtower.
|
||||
func NewService(iamRepo common.IamRepoFactory, atRepo common.AuthTokenRepoFactory) (Service, error) {
|
||||
func NewService(pwRepo common.PasswordAuthRepoFactory, iamRepo common.IamRepoFactory, atRepo common.AuthTokenRepoFactory) (Service, error) {
|
||||
if iamRepo == nil {
|
||||
return Service{}, fmt.Errorf("nil iam repository provided")
|
||||
}
|
||||
if atRepo == nil {
|
||||
return Service{}, fmt.Errorf("nil auth token repository provided")
|
||||
}
|
||||
if pwRepo == nil {
|
||||
return Service{}, fmt.Errorf("nil password repository provided")
|
||||
}
|
||||
|
||||
return Service{iamRepo: iamRepo, authTokenRepo: atRepo}, nil
|
||||
return Service{pwRepo: pwRepo, iamRepo: iamRepo, authTokenRepo: atRepo}, nil
|
||||
}
|
||||
|
||||
var _ pbs.AuthenticationServiceServer = Service{}
|
||||
|
||||
// Authenticate implements the interface pbs.AuthenticationServiceServer.
|
||||
func (s Service) Authenticate(ctx context.Context, req *pbs.AuthenticateRequest) (*pbs.AuthenticateResponse, error) {
|
||||
authResults := auth.Verify(ctx)
|
||||
if !authResults.Valid {
|
||||
return nil, handlers.ForbiddenError()
|
||||
}
|
||||
if err := validateAuthenticateRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tok, err := s.authenticateWithRepo(ctx, req)
|
||||
creds := req.GetCredentials().GetFields()
|
||||
tok, err := s.authenticateWithRepo(ctx, req.GetAuthMethodId(), creds[nameKey].GetStringValue(), creds[pwKey].GetStringValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func (s Service) Deauthenticate(ctx context.Context, req *pbs.DeauthenticateRequ
|
||||
return nil, status.Error(codes.Unimplemented, "Requested method is unimplemented.")
|
||||
}
|
||||
|
||||
func (s Service) authenticateWithRepo(ctx context.Context, req *pbs.AuthenticateRequest) (*pba.AuthToken, error) {
|
||||
func (s Service) authenticateWithRepo(ctx context.Context, authMethodId, name, pw string) (*pba.AuthToken, error) {
|
||||
iamRepo, err := s.iamRepo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -82,29 +82,24 @@ func (s Service) authenticateWithRepo(ctx context.Context, req *pbs.Authenticate
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Place holder for making a request to authenticate
|
||||
creds := req.GetCredentials().GetFields()
|
||||
pwName, password := creds["name"], creds["password"]
|
||||
if pwName.GetStringValue() == "wrong" && password.GetStringValue() == "wrong" {
|
||||
return nil, status.Error(codes.Unauthenticated, "Unable to authenticate.")
|
||||
}
|
||||
// Get back a password.Account with a CredentialId string and a public Id
|
||||
// Create a fake auth account ID for the moment
|
||||
acctIdBytes := sha256.Sum256([]byte(pwName.GetStringValue()))
|
||||
acctId := fmt.Sprintf("aa_%s", base32.StdEncoding.EncodeToString(acctIdBytes[:])[0:10])
|
||||
|
||||
aAcct := &iam.AuthAccount{AuthAccount: &iamStore.AuthAccount{
|
||||
PublicId: acctId,
|
||||
ScopeId: Scope,
|
||||
AuthMethodId: req.AuthMethodId,
|
||||
}}
|
||||
RWDb.Load().(*db.Db).Create(ctx, aAcct)
|
||||
|
||||
u, err := iamRepo.LookupUserWithLogin(ctx, acctId, iam.WithAutoVivify(true))
|
||||
pwRepo, err := s.pwRepo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tok, err := atRepo.CreateAuthToken(ctx, u.GetPublicId(), acctId)
|
||||
|
||||
acct, err := pwRepo.Authenticate(ctx, authMethodId, name, pw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if acct == nil {
|
||||
return nil, status.Error(codes.Unauthenticated, "Unable to authenticate.")
|
||||
}
|
||||
|
||||
u, err := iamRepo.LookupUserWithLogin(ctx, acct.GetPublicId(), iam.WithAutoVivify(true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tok, err := atRepo.CreateAuthToken(ctx, u.GetPublicId(), acct.GetPublicId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -156,6 +151,13 @@ func validateAuthenticateRequest(req *pbs.AuthenticateRequest) error {
|
||||
if req.GetCredentials() == nil {
|
||||
badFields["credentials"] = "This is a required field."
|
||||
}
|
||||
creds := req.GetCredentials().GetFields()
|
||||
if _, ok := creds[nameKey]; !ok {
|
||||
badFields["credentials.name"] = "This is a required field."
|
||||
}
|
||||
if _, ok := creds[pwKey]; !ok {
|
||||
badFields["credentials.password"] = "This is a required field."
|
||||
}
|
||||
// TODO: Update this when we enable split cookie token types.
|
||||
tType := strings.ToLower(strings.TrimSpace(req.GetTokenType()))
|
||||
if tType != "" && tType != "token" {
|
||||
|
||||
@@ -2,59 +2,46 @@ package authenticate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
structpb "github.com/golang/protobuf/ptypes/struct"
|
||||
"github.com/hashicorp/watchtower/internal/auth"
|
||||
"github.com/hashicorp/watchtower/internal/auth/password"
|
||||
"github.com/hashicorp/watchtower/internal/authtoken"
|
||||
"github.com/hashicorp/watchtower/internal/db"
|
||||
pba "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/authtokens"
|
||||
pbs "github.com/hashicorp/watchtower/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/watchtower/internal/iam"
|
||||
iamStore "github.com/hashicorp/watchtower/internal/iam/store"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func getAuthMethodAndAccountId(t *testing.T, org *iam.Scope, rw *db.Db) (string, string) {
|
||||
// TODO: Remove this when Auth Account repo is in place.
|
||||
insert := `insert into auth_method
|
||||
(public_id, scope_id)
|
||||
values
|
||||
($1, $2);`
|
||||
amId, err := db.NewPublicId("am")
|
||||
require.NoError(t, err)
|
||||
innerDb, err := rw.DB()
|
||||
require.NoError(t, err)
|
||||
_, err = innerDb.Exec(insert, amId, org.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
aAcctId, err := db.NewPublicId("aa")
|
||||
require.NoError(t, err)
|
||||
|
||||
aAcct := &iam.AuthAccount{AuthAccount: &iamStore.AuthAccount{
|
||||
PublicId: aAcctId,
|
||||
ScopeId: org.GetPublicId(),
|
||||
AuthMethodId: amId,
|
||||
}}
|
||||
require.NoError(t, rw.Create(context.Background(), aAcct))
|
||||
return aAcct.GetAuthMethodId(), aAcct.GetPublicId()
|
||||
}
|
||||
const (
|
||||
testPassword = "thetestpassword"
|
||||
testUsername = "default"
|
||||
)
|
||||
|
||||
func TestAuthenticate(t *testing.T) {
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
RWDb.Store(rw)
|
||||
wrapper := db.TestWrapper(t)
|
||||
o, _ := iam.TestScopes(t, conn)
|
||||
|
||||
authTokenRepoFn := func() (*authtoken.Repository, error) { return authtoken.NewRepository(rw, rw, wrapper) }
|
||||
iamRepoFn := func() (*iam.Repository, error) { return iam.NewRepository(rw, rw, wrapper) }
|
||||
amId, _ := getAuthMethodAndAccountId(t, o, rw)
|
||||
passwordRepoFn := func() (*password.Repository, error) { return password.NewRepository(rw, rw, wrapper) }
|
||||
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
|
||||
|
||||
acct, err := password.NewAccount(am.GetPublicId(), testUsername)
|
||||
require.NoError(t, err)
|
||||
|
||||
pwRepo, err := passwordRepoFn()
|
||||
require.NoError(t, err)
|
||||
acct, err = pwRepo.CreateAccount(context.Background(), acct, password.WithPassword(testPassword))
|
||||
require.NoError(t, err)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
@@ -65,45 +52,45 @@ func TestAuthenticate(t *testing.T) {
|
||||
{
|
||||
name: "basic",
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: amId,
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
TokenType: "token",
|
||||
Credentials: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: "admin"}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: "hunter2"}},
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: testUsername}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
},
|
||||
want: &pbs.AuthenticateResponse{Item: &pba.AuthToken{
|
||||
AuthMethodId: amId,
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "no-token-type",
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: amId,
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
Credentials: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: "admin"}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: "hunter2"}},
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: testUsername}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
},
|
||||
want: &pbs.AuthenticateResponse{Item: &pba.AuthToken{
|
||||
AuthMethodId: amId,
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "bad-token-type",
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: amId,
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
TokenType: "email",
|
||||
Credentials: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: "admin"}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: "hunter2"}},
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: testUsername}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
@@ -115,8 +102,8 @@ func TestAuthenticate(t *testing.T) {
|
||||
request: &pbs.AuthenticateRequest{
|
||||
Credentials: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: "admin"}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: "hunter2"}},
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: testUsername}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
@@ -124,14 +111,29 @@ func TestAuthenticate(t *testing.T) {
|
||||
wantErr: status.Error(codes.InvalidArgument, "invalid argument"),
|
||||
},
|
||||
{
|
||||
name: "wrong-username-password",
|
||||
name: "wrong-password",
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: amId,
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
TokenType: "token",
|
||||
Credentials: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: testUsername}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: "wrong"}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
},
|
||||
wantErr: status.Error(codes.Unauthenticated, "unauthenticated"),
|
||||
},
|
||||
{
|
||||
name: "wrong-username",
|
||||
request: &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
TokenType: "token",
|
||||
Credentials: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: "wrong"}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: "wrong"}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
@@ -143,22 +145,10 @@ func TestAuthenticate(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
s, err := NewService(iamRepoFn, authTokenRepoFn)
|
||||
s, err := NewService(passwordRepoFn, iamRepoFn, authTokenRepoFn)
|
||||
require.NoError(err)
|
||||
|
||||
// TODO: remove when we stop faking things
|
||||
name := tc.request.Credentials.Fields["name"].GetStringValue()
|
||||
acctIdBytes := sha256.Sum256([]byte(name))
|
||||
acctId := fmt.Sprintf("aa_%s", base32.StdEncoding.EncodeToString(acctIdBytes[:])[0:10])
|
||||
|
||||
aAcct := &iam.AuthAccount{AuthAccount: &iamStore.AuthAccount{
|
||||
PublicId: acctId,
|
||||
ScopeId: o.PublicId,
|
||||
AuthMethodId: amId,
|
||||
}}
|
||||
RWDb.Load().(*db.Db).Create(context.Background(), aAcct)
|
||||
|
||||
resp, err := s.Authenticate(context.Background(), tc.request)
|
||||
resp, err := s.Authenticate(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), tc.request)
|
||||
if tc.wantErr != nil {
|
||||
assert.Error(err)
|
||||
assert.Equal(status.Code(tc.wantErr), status.Code(err))
|
||||
@@ -169,7 +159,7 @@ func TestAuthenticate(t *testing.T) {
|
||||
assert.NotEmpty(aToken.GetId())
|
||||
assert.NotEmpty(aToken.GetToken())
|
||||
assert.True(strings.HasPrefix(aToken.GetToken(), aToken.GetId()))
|
||||
assert.Equal(amId, aToken.GetAuthMethodId())
|
||||
assert.Equal(am.GetPublicId(), aToken.GetAuthMethodId())
|
||||
assert.Equal(aToken.GetCreatedTime(), aToken.GetUpdatedTime())
|
||||
assert.Equal(aToken.GetCreatedTime(), aToken.GetApproximateLastUsedTime())
|
||||
})
|
||||
@@ -180,40 +170,36 @@ func TestAuthenticate_AuthAccountConnectedToIamUser(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
RWDb.Store(rw)
|
||||
wrapper := db.TestWrapper(t)
|
||||
o, _ := iam.TestScopes(t, conn)
|
||||
|
||||
passwordRepoFn := func() (*password.Repository, error) { return password.NewRepository(rw, rw, wrapper) }
|
||||
authTokenRepoFn := func() (*authtoken.Repository, error) { return authtoken.NewRepository(rw, rw, wrapper) }
|
||||
iamRepoFn := func() (*iam.Repository, error) { return iam.NewRepository(rw, rw, wrapper) }
|
||||
iamRepo, err := iamRepoFn()
|
||||
|
||||
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
|
||||
acct, err := password.NewAccount(am.GetPublicId(), testUsername)
|
||||
require.NoError(err)
|
||||
|
||||
pwRepo, err := passwordRepoFn()
|
||||
require.NoError(err)
|
||||
acct, err = pwRepo.CreateAccount(context.Background(), acct, password.WithPassword(testPassword))
|
||||
require.NoError(err)
|
||||
|
||||
// connected to an account.
|
||||
amId, _ := getAuthMethodAndAccountId(t, o, rw)
|
||||
|
||||
name := "admin"
|
||||
acctIdBytes := sha256.Sum256([]byte(name))
|
||||
acctId := fmt.Sprintf("aa_%s", base32.StdEncoding.EncodeToString(acctIdBytes[:])[0:10])
|
||||
|
||||
aAcct := &iam.AuthAccount{AuthAccount: &iamStore.AuthAccount{
|
||||
PublicId: acctId,
|
||||
ScopeId: o.PublicId,
|
||||
AuthMethodId: amId,
|
||||
}}
|
||||
RWDb.Load().(*db.Db).Create(context.Background(), aAcct)
|
||||
|
||||
iamUser, err := iamRepo.LookupUserWithLogin(context.Background(), acctId, iam.WithAutoVivify(true))
|
||||
iamRepo, err := iamRepoFn()
|
||||
require.NoError(err)
|
||||
iamUser, err := iamRepo.LookupUserWithLogin(context.Background(), acct.GetPublicId(), iam.WithAutoVivify(true))
|
||||
require.NoError(err)
|
||||
|
||||
s, err := NewService(iamRepoFn, authTokenRepoFn)
|
||||
s, err := NewService(passwordRepoFn, iamRepoFn, authTokenRepoFn)
|
||||
require.NoError(err)
|
||||
resp, err := s.Authenticate(context.Background(), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: amId,
|
||||
resp, err := s.Authenticate(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
Credentials: func() *structpb.Struct {
|
||||
creds := map[string]*structpb.Value{
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: name}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: "hunter2"}},
|
||||
"name": {Kind: &structpb.Value_StringValue{StringValue: testUsername}},
|
||||
"password": {Kind: &structpb.Value_StringValue{StringValue: testPassword}},
|
||||
}
|
||||
return &structpb.Struct{Fields: creds}
|
||||
}(),
|
||||
@@ -222,7 +208,7 @@ func TestAuthenticate_AuthAccountConnectedToIamUser(t *testing.T) {
|
||||
|
||||
aToken := resp.GetItem()
|
||||
assert.Equal(iamUser.GetPublicId(), aToken.GetUserId())
|
||||
assert.Equal(amId, aToken.GetAuthMethodId())
|
||||
assert.Equal(am.GetPublicId(), aToken.GetAuthMethodId())
|
||||
|
||||
assert.NotEmpty(aToken.GetId())
|
||||
assert.NotEmpty(aToken.GetToken())
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
structpb "github.com/golang/protobuf/ptypes/struct"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
authpb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/auth"
|
||||
authpb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/authmethods"
|
||||
hostpb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/hosts"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -114,6 +114,12 @@ type TestControllerOpts struct {
|
||||
// in the normal config.
|
||||
DefaultOrgId string
|
||||
|
||||
// DefaultUsername is the username used when creating the default account.
|
||||
DefaultUsername string
|
||||
|
||||
// DefaultPassword is the password used when creating the default account.
|
||||
DefaultPassword string
|
||||
|
||||
// DisableDatabaseCreation can be set true to disable creating a dev
|
||||
// database
|
||||
DisableDatabaseCreation bool
|
||||
@@ -163,6 +169,13 @@ func NewTestController(t *testing.T, opts *TestControllerOpts) *TestController {
|
||||
tc.b.DefaultOrgId = opts.DefaultOrgId
|
||||
}
|
||||
|
||||
if opts.DefaultUsername != "" {
|
||||
tc.b.DevUsername = opts.DefaultUsername
|
||||
}
|
||||
if opts.DefaultPassword != "" {
|
||||
tc.b.DevPassword = opts.DefaultPassword
|
||||
}
|
||||
|
||||
// Start a logger
|
||||
tc.b.Logger = hclog.New(&hclog.LoggerOptions{
|
||||
Level: hclog.Trace,
|
||||
|
||||
Reference in new issue
Block a user