You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/daemon/controller/handlers/authmethods/password_test.go

787 lines
25 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package authmethods_test
import (
"context"
"encoding/json"
"os"
"strings"
"sync"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/hashicorp/boundary/globals"
am "github.com/hashicorp/boundary/internal/auth"
"github.com/hashicorp/boundary/internal/auth/ldap"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/authmethods"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/event"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/types/scope"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authmethods"
scopepb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
"github.com/hashicorp/eventlogger/formatter_filters/cloudevents"
"github.com/hashicorp/go-hclog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/timestamppb"
"google.golang.org/protobuf/types/known/wrapperspb"
)
func TestUpdate_Password(t *testing.T) {
ctx := context.TODO()
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
iamRepoFn := func() (*iam.Repository, error) {
return iam.TestRepo(t, conn, wrapper), nil
}
oidcRepoFn := func() (*oidc.Repository, error) {
return oidc.NewRepository(ctx, rw, rw, kms)
}
ldapRepoFn := func() (*ldap.Repository, error) {
return ldap.NewRepository(ctx, rw, rw, kms)
}
pwRepoFn := func() (*password.Repository, error) {
return password.NewRepository(ctx, rw, rw, kms)
}
atRepoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(ctx, rw, rw, kms)
}
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
return am.NewAuthMethodRepository(ctx, rw, rw, kms)
}
iamRepo := iam.TestRepo(t, conn, wrapper)
o, _ := iam.TestScopes(t, iamRepo)
tested, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
require.NoError(t, err, "Error when getting new auth_method service.")
defaultScopeInfo := &scopepb.ScopeInfo{Id: o.GetPublicId(), Type: o.GetType(), ParentScopeId: scope.Global.String()}
freshAuthMethod := func() (*pb.AuthMethod, func()) {
am, err := tested.CreateAuthMethod(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId()),
&pbs.CreateAuthMethodRequest{Item: &pb.AuthMethod{
ScopeId: o.GetPublicId(),
Name: wrapperspb.String("default"),
Description: wrapperspb.String("default"),
Type: "password",
}})
require.NoError(t, err)
clean := func() {
_, err := tested.DeleteAuthMethod(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId()),
&pbs.DeleteAuthMethodRequest{Id: am.GetItem().GetId()})
require.NoError(t, err)
}
return am.GetItem(), clean
}
cases := []struct {
name string
req *pbs.UpdateAuthMethodRequest
res *pbs.UpdateAuthMethodResponse
err error
}{
{
name: "Update an Existing AuthMethod",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name", "description"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
Type: "password",
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
ScopeId: o.GetPublicId(),
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
Type: "password",
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
MinPasswordLength: 8,
MinLoginNameLength: 3,
},
},
Scope: defaultScopeInfo,
AuthorizedActions: pwAuthorizedActions,
AuthorizedCollectionActions: authorizedCollectionActions,
},
},
},
{
name: "Multiple Paths in single string",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name,description,type"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
Type: "password",
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
ScopeId: o.GetPublicId(),
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
Type: "password",
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
MinPasswordLength: 8,
MinLoginNameLength: 3,
},
},
Scope: defaultScopeInfo,
AuthorizedActions: pwAuthorizedActions,
AuthorizedCollectionActions: authorizedCollectionActions,
},
},
},
{
name: "No Update Mask",
req: &pbs.UpdateAuthMethodRequest{
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated name"},
Description: &wrapperspb.StringValue{Value: "updated desc"},
},
},
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "No Paths in Mask",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{Paths: []string{}},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated name"},
Description: &wrapperspb.StringValue{Value: "updated desc"},
},
},
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Only non-existent paths in Mask",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{Paths: []string{"nonexistent_field"}},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated name"},
Description: &wrapperspb.StringValue{Value: "updated desc"},
},
},
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Cant change type",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{Paths: []string{"name", "type"}},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated name"},
Type: "oidc",
},
},
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Cant change is primary",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{Paths: []string{"is_primary"}},
Item: &pb.AuthMethod{
IsPrimary: true,
},
},
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Unset Name",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name"},
},
Item: &pb.AuthMethod{
Description: &wrapperspb.StringValue{Value: "ignored"},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
ScopeId: o.GetPublicId(),
Description: &wrapperspb.StringValue{Value: "default"},
Type: "password",
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
MinPasswordLength: 8,
MinLoginNameLength: 3,
},
},
Scope: defaultScopeInfo,
AuthorizedActions: pwAuthorizedActions,
AuthorizedCollectionActions: authorizedCollectionActions,
},
},
},
{
name: "Update Only Name",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated"},
Description: &wrapperspb.StringValue{Value: "ignored"},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
ScopeId: o.GetPublicId(),
Name: &wrapperspb.StringValue{Value: "updated"},
Description: &wrapperspb.StringValue{Value: "default"},
Type: "password",
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
MinPasswordLength: 8,
MinLoginNameLength: 3,
},
},
Scope: defaultScopeInfo,
AuthorizedActions: pwAuthorizedActions,
AuthorizedCollectionActions: authorizedCollectionActions,
},
},
},
{
name: "Update Only Description",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"description"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "ignored"},
Description: &wrapperspb.StringValue{Value: "notignored"},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
ScopeId: o.GetPublicId(),
Name: &wrapperspb.StringValue{Value: "default"},
Description: &wrapperspb.StringValue{Value: "notignored"},
Type: "password",
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
MinPasswordLength: 8,
MinLoginNameLength: 3,
},
},
Scope: defaultScopeInfo,
AuthorizedActions: pwAuthorizedActions,
AuthorizedCollectionActions: authorizedCollectionActions,
},
},
},
{
name: "Update a Non Existing AuthMethod",
req: &pbs.UpdateAuthMethodRequest{
Id: globals.PasswordAuthMethodPrefix + "_DoesntExis",
UpdateMask: &field_mask.FieldMask{
Paths: []string{"description"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
},
},
err: handlers.ApiErrorWithCode(codes.NotFound),
},
{
name: "Cant change Id",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"id"},
},
Item: &pb.AuthMethod{
Id: globals.PasswordAuthMethodPrefix + "_somethinge",
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "new desc"},
},
},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Cant specify Created Time",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"created_time"},
},
Item: &pb.AuthMethod{
CreatedTime: timestamppb.Now(),
},
},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Cant specify Updated Time",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"updated_time"},
},
Item: &pb.AuthMethod{
UpdatedTime: timestamppb.Now(),
},
},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Cant specify Type",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"type"},
},
Item: &pb.AuthMethod{
Type: "oidc",
},
},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Update login name length",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"attributes.min_login_name_length"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "ignored"},
Description: &wrapperspb.StringValue{Value: "ignored"},
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
MinLoginNameLength: 42,
MinPasswordLength: 55555,
},
},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
ScopeId: o.GetPublicId(),
Name: &wrapperspb.StringValue{Value: "default"},
Description: &wrapperspb.StringValue{Value: "default"},
Type: "password",
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
MinPasswordLength: 8,
MinLoginNameLength: 42,
},
},
Scope: defaultScopeInfo,
AuthorizedActions: pwAuthorizedActions,
AuthorizedCollectionActions: authorizedCollectionActions,
},
},
},
{
name: "Update password length",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"attributes.min_password_length"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "ignored"},
Description: &wrapperspb.StringValue{Value: "ignored"},
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
MinLoginNameLength: 5555,
MinPasswordLength: 42,
},
},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
ScopeId: o.GetPublicId(),
Name: &wrapperspb.StringValue{Value: "default"},
Description: &wrapperspb.StringValue{Value: "default"},
Type: "password",
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
MinPasswordLength: 42,
MinLoginNameLength: 3,
},
},
Scope: defaultScopeInfo,
AuthorizedActions: pwAuthorizedActions,
AuthorizedCollectionActions: authorizedCollectionActions,
},
},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
am, cleanup := freshAuthMethod()
defer cleanup()
tc.req.Item.Version = 1
if tc.req.GetId() == "" {
tc.req.Id = am.GetId()
}
if tc.res != nil && tc.res.Item != nil {
tc.res.Item.Id = am.GetId()
tc.res.Item.CreatedTime = am.GetCreatedTime()
}
got, gErr := tested.UpdateAuthMethod(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId()), tc.req)
if tc.err != nil {
require.Error(gErr)
assert.True(errors.Is(gErr, tc.err), "UpdateAuthMethod(%+v) got error %v, wanted %v", tc.req, gErr, tc.err)
}
if tc.res == nil {
require.Nil(got)
}
cmpOptions := []cmp.Option{
protocmp.Transform(),
cmpopts.SortSlices(func(a, b string) bool {
return a < b
}),
cmpopts.SortSlices(func(a, b protocmp.Message) bool {
return a.String() < b.String()
}),
}
if got != nil {
assert.NotNilf(tc.res, "Expected UpdateAuthMethod response to be nil, but was %v", got)
created := am.GetCreatedTime().AsTime()
gotUpdateTime := got.GetItem().GetUpdatedTime().AsTime()
// Verify it is a auth_method updated after it was created
assert.True(gotUpdateTime.After(created), "Updated auth_method should have been updated after it's creation. Was updated %v, which is after %v", gotUpdateTime, created)
// Ignore all values which are hard to compare against.
cmpOptions = append(cmpOptions, protocmp.IgnoreFields(&pb.AuthMethod{}, "updated_time"))
assert.EqualValues(2, got.Item.Version)
tc.res.Item.Version = 2
}
assert.Empty(cmp.Diff(got, tc.res, cmpOptions...), "UpdateAuthMethod(%q) got response %q, wanted %q", tc.req, got, tc.res)
})
}
}
func TestAuthenticate_Password(t *testing.T) {
ctx := context.TODO()
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
o, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
iamRepoFn := func() (*iam.Repository, error) {
return iam.TestRepo(t, conn, wrapper), nil
}
oidcRepoFn := func() (*oidc.Repository, error) {
return oidc.NewRepository(ctx, rw, rw, kms)
}
ldapRepoFn := func() (*ldap.Repository, error) {
return ldap.NewRepository(ctx, rw, rw, kms)
}
pwRepoFn := func() (*password.Repository, error) {
return password.NewRepository(ctx, rw, rw, kms)
}
atRepoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(ctx, rw, rw, kms)
}
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
return am.NewAuthMethodRepository(ctx, rw, rw, kms)
}
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
iam.TestSetPrimaryAuthMethod(t, iam.TestRepo(t, conn, wrapper), o, am.PublicId)
acct, err := password.NewAccount(ctx, am.GetPublicId(), password.WithLoginName(testLoginName))
require.NoError(t, err)
pwRepo, err := pwRepoFn()
require.NoError(t, err)
acct, err = pwRepo.CreateAccount(context.Background(), o.GetPublicId(), acct, password.WithPassword(testPassword))
require.NoError(t, err)
require.NotNil(t, acct)
c := event.TestEventerConfig(t, "Test_StartAuth_to_Callback", event.TestWithObservationSink(t))
testLock := &sync.Mutex{}
testLogger := hclog.New(&hclog.LoggerOptions{
Mutex: testLock,
Name: "test",
})
c.EventerConfig.TelemetryEnabled = true
require.NoError(t, event.InitSysEventer(testLogger, testLock, "use-Test_Authenticate", event.WithEventerConfig(&c.EventerConfig)))
sinkFileName := c.ObservationEvents.Name()
t.Cleanup(func() {
require.NoError(t, os.Remove(sinkFileName))
})
cases := []struct {
name string
request *pbs.AuthenticateRequest
actions []string
wantType string
wantErr error
wantErrContains string
}{
{
name: "basic",
request: &pbs.AuthenticateRequest{
AuthMethodId: am.GetPublicId(),
TokenType: "token",
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
LoginName: testLoginName,
Password: testPassword,
},
},
},
wantType: "token",
},
{
name: "cookie-type",
request: &pbs.AuthenticateRequest{
AuthMethodId: am.GetPublicId(),
TokenType: "cookie",
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
LoginName: testLoginName,
Password: testPassword,
},
},
},
wantType: "cookie",
},
{
name: "no-token-type",
request: &pbs.AuthenticateRequest{
AuthMethodId: am.GetPublicId(),
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
LoginName: testLoginName,
Password: testPassword,
},
},
},
},
{
name: "bad-token-type",
request: &pbs.AuthenticateRequest{
AuthMethodId: am.GetPublicId(),
TokenType: "email",
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
LoginName: testLoginName,
Password: testPassword,
},
},
},
wantErr: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "no-authmethod",
request: &pbs.AuthenticateRequest{
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
LoginName: testLoginName,
Password: testPassword,
},
},
},
wantErr: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "wrong-password",
request: &pbs.AuthenticateRequest{
AuthMethodId: am.GetPublicId(),
TokenType: "token",
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
LoginName: testLoginName,
Password: "wrong",
},
},
},
wantErr: handlers.ApiErrorWithCode(codes.Unauthenticated),
},
{
name: "wrong-login-name",
request: &pbs.AuthenticateRequest{
AuthMethodId: am.GetPublicId(),
TokenType: "token",
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
LoginName: "wrong",
Password: testPassword,
},
},
},
wantErr: handlers.ApiErrorWithCode(codes.Unauthenticated),
},
{
name: "no-attributes",
request: &pbs.AuthenticateRequest{
AuthMethodId: am.GetPublicId(),
TokenType: "token",
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{},
},
wantErr: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: `Details: {{name: "attributes", desc: "This is a required field."}}`,
},
{
name: "with-callback-action",
actions: []string{"callback"},
request: &pbs.AuthenticateRequest{
AuthMethodId: am.GetPublicId(),
TokenType: "token",
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
LoginName: testLoginName,
Password: testPassword,
},
},
},
wantErr: handlers.ApiErrorWithCode(codes.InvalidArgument),
wantErrContains: `Details: {{name: "request_path", desc: "callback is not a valid action for this auth method."}}`,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
s, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
require.NoError(err)
resp, err := s.Authenticate(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId(), auth.WithActions(tc.actions)), tc.request)
if tc.wantErr != nil {
assert.Error(err)
assert.Truef(errors.Is(err, tc.wantErr), "Got %#v, wanted %#v", err, tc.wantErr)
if tc.wantErrContains != "" {
assert.Contains(err.Error(), tc.wantErrContains)
}
return
}
require.NoError(err)
aToken := resp.GetAuthTokenResponse()
assert.NotEmpty(aToken.GetId())
assert.NotEmpty(aToken.GetToken())
assert.True(strings.HasPrefix(aToken.GetToken(), aToken.GetId()))
assert.Equal(am.GetPublicId(), aToken.GetAuthMethodId())
assert.Equal(aToken.GetCreatedTime(), aToken.GetUpdatedTime())
assert.Equal(aToken.GetCreatedTime(), aToken.GetApproximateLastUsedTime())
assert.Equal(acct.GetPublicId(), aToken.GetAccountId())
assert.Equal(am.GetPublicId(), aToken.GetAuthMethodId())
assert.Equal(tc.wantType, resp.GetType())
defer func() { _ = os.WriteFile(sinkFileName, nil, 0o666) }()
b, err := os.ReadFile(sinkFileName)
require.NoError(err)
gotRes := &cloudevents.Event{}
err = json.Unmarshal(b, gotRes)
require.NoErrorf(err, "json: %s", string(b))
details, ok := gotRes.Data.(map[string]any)["details"]
require.True(ok)
for _, key := range details.([]any) {
assert.Contains(key.(map[string]any)["payload"], "user_id")
assert.Contains(key.(map[string]any)["payload"], "auth_token_start")
assert.Contains(key.(map[string]any)["payload"], "auth_token_end")
}
})
}
}
func TestAuthenticate_AuthAccountConnectedToIamUser_Password(t *testing.T) {
ctx := context.TODO()
assert, require := assert.New(t), require.New(t)
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
o, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
iamRepoFn := func() (*iam.Repository, error) {
return iam.TestRepo(t, conn, wrapper), nil
}
oidcRepoFn := func() (*oidc.Repository, error) {
return oidc.NewRepository(ctx, rw, rw, kms)
}
ldapRepoFn := func() (*ldap.Repository, error) {
return ldap.NewRepository(ctx, rw, rw, kms)
}
pwRepoFn := func() (*password.Repository, error) {
return password.NewRepository(ctx, rw, rw, kms)
}
atRepoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(ctx, rw, rw, kms)
}
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
return am.NewAuthMethodRepository(ctx, rw, rw, kms)
}
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
acct, err := password.NewAccount(ctx, am.GetPublicId(), password.WithLoginName(testLoginName))
require.NoError(err)
pwRepo, err := pwRepoFn()
require.NoError(err)
acct, err = pwRepo.CreateAccount(context.Background(), o.GetPublicId(), acct, password.WithPassword(testPassword))
require.NoError(err)
// connected to an account.
iamRepo, err := iamRepoFn()
require.NoError(err)
iam.TestUser(t, iamRepo, am.ScopeId, iam.WithAccountIds(acct.PublicId))
iamUser, err := iamRepo.LookupUserWithLogin(context.Background(), acct.GetPublicId())
require.NoError(err)
s, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
require.NoError(err)
resp, err := s.Authenticate(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId()), &pbs.AuthenticateRequest{
AuthMethodId: am.GetPublicId(),
Attrs: &pbs.AuthenticateRequest_PasswordLoginAttributes{
PasswordLoginAttributes: &pbs.PasswordLoginAttributes{
LoginName: testLoginName,
Password: testPassword,
},
},
})
require.NoError(err)
aToken := resp.GetAuthTokenResponse()
assert.Equal(iamUser.GetPublicId(), aToken.GetUserId())
assert.Equal(am.GetPublicId(), aToken.GetAuthMethodId())
assert.Equal(acct.GetPublicId(), aToken.GetAccountId())
assert.NotEmpty(aToken.GetId())
assert.NotEmpty(aToken.GetToken())
assert.True(strings.HasPrefix(aToken.GetToken(), aToken.GetId()))
}