2021-04-20 20:33:56 -04:00
// Copyright (c) HashiCorp, Inc.
2021-02-22 10:09:25 -07:00
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2020-06-09 11:20:59 -07:00
package users_test
import (
"context"
2020-09-23 08:10:27 -07:00
"errors"
2020-06-09 11:20:59 -07:00
"fmt"
2023-12-20 16:51:57 -08:00
"slices"
2020-06-09 11:20:59 -07:00
"strings"
"testing"
2020-08-05 10:19:55 -07:00
"github.com/google/go-cmp/cmp"
2023-10-31 13:44:17 +00:00
"github.com/google/go-cmp/cmp/cmpopts"
2022-10-28 15:52:06 -04:00
"github.com/hashicorp/boundary/globals"
2024-04-17 08:26:46 -07:00
talias "github.com/hashicorp/boundary/internal/alias/target"
2023-05-03 09:45:29 -04:00
"github.com/hashicorp/boundary/internal/auth/ldap"
2021-04-14 11:34:17 -07:00
"github.com/hashicorp/boundary/internal/auth/oidc"
2020-09-25 20:44:55 -07:00
"github.com/hashicorp/boundary/internal/auth/password"
2023-12-20 16:51:57 -08:00
"github.com/hashicorp/boundary/internal/authtoken"
2022-05-09 12:45:10 -07:00
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
2024-04-17 08:26:46 -07:00
"github.com/hashicorp/boundary/internal/daemon/controller/common"
2022-05-09 12:45:10 -07:00
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/users"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/db"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
2023-12-20 16:51:57 -08:00
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/iam"
2021-04-14 11:34:17 -07:00
"github.com/hashicorp/boundary/internal/kms"
2023-12-20 16:51:57 -08:00
"github.com/hashicorp/boundary/internal/requests"
"github.com/hashicorp/boundary/internal/server"
2024-04-17 08:26:46 -07:00
"github.com/hashicorp/boundary/internal/target/tcp"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/types/scope"
2024-04-17 08:26:46 -07:00
pbalias "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/aliases"
2021-08-26 10:44:41 -04:00
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/users"
2020-06-09 11:20:59 -07:00
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/proto"
2020-08-05 10:19:55 -07:00
"google.golang.org/protobuf/testing/protocmp"
2021-04-20 20:33:56 -04:00
"google.golang.org/protobuf/types/known/timestamppb"
2020-06-09 11:20:59 -07:00
"google.golang.org/protobuf/types/known/wrapperspb"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
2024-04-17 08:26:46 -07:00
var testAuthorizedActions = [] string { "no-op" , "read" , "update" , "delete" , "add-accounts" , "set-accounts" , "remove-accounts" , "list-resolvable-aliases" }
2021-04-23 09:13:37 -05:00
2024-04-17 08:26:46 -07:00
func createDefaultUserAndRepos ( t * testing . T , withAccts bool ) ( * iam . User , [] string , common . IamRepoFactory , common . TargetAliasRepoFactory ) {
2020-06-09 11:20:59 -07:00
t . Helper ()
2024-04-17 08:26:46 -07:00
ctx := context . Background ()
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2020-06-09 11:20:59 -07:00
wrap := db . TestWrapper ( t )
2024-04-17 08:26:46 -07:00
kmsCache := kms . TestKms ( t , conn , wrap )
rw := db . New ( conn )
2020-08-19 16:47:18 -04:00
repo := iam . TestRepo ( t , conn , wrap )
2020-06-09 11:20:59 -07:00
repoFn := func () ( * iam . Repository , error ) {
2020-08-19 16:47:18 -04:00
return repo , nil
2020-06-09 11:20:59 -07:00
}
2024-04-17 08:26:46 -07:00
aliasRepoFn := func () ( * talias . Repository , error ) {
return talias . NewRepository ( context . Background (), rw , rw , kmsCache )
}
2020-08-19 16:47:18 -04:00
o , _ := iam . TestScopes ( t , repo )
u := iam . TestUser ( t , repo , o . GetPublicId (), iam . WithDescription ( "default" ), iam . WithName ( "default" ))
2021-04-20 20:33:56 -04:00
switch withAccts {
case false :
2024-04-17 08:26:46 -07:00
return u , nil , repoFn , aliasRepoFn
2021-04-20 20:33:56 -04:00
default :
require := require . New ( t )
databaseWrap , err := kmsCache . GetWrapper ( ctx , o . PublicId , kms . KeyPurposeDatabase )
require . NoError ( err )
primaryAm := oidc . TestAuthMethod ( t , conn , databaseWrap , o . PublicId , oidc . ActivePublicState , "alice-rp" , "fido" ,
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , "https://alice-eve-smith.com" )[ 0 ]),
oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "http://localhost:9200" )[ 0 ]),
oidc . WithSigningAlgs ( oidc . RS256 ),
)
iam . TestSetPrimaryAuthMethod ( t , repo , o , primaryAm . PublicId )
oidcAcct := oidc . TestAccount ( t , conn , primaryAm , "alice" , oidc . WithFullName ( "Alice Eve Smith" ), oidc . WithEmail ( "alice@smith.com" ))
secondaryAm := password . TestAuthMethods ( t , conn , o . PublicId , 1 )
require . Len ( secondaryAm , 1 )
pwAcct := password . TestAccount ( t , conn , secondaryAm [ 0 ]. PublicId , "alice" )
added , err := repo . AddUserAccounts ( ctx , u . PublicId , u . Version , [] string { oidcAcct . PublicId , pwAcct . PublicId })
require . NoError ( err )
require . Len ( added , 2 )
// reload the user with their accounts
u , accts , err := repo . LookupUser ( ctx , u . PublicId )
require . NoError ( err )
2024-04-17 08:26:46 -07:00
return u , accts , repoFn , aliasRepoFn
2021-04-20 20:33:56 -04:00
}
2020-06-09 11:20:59 -07:00
}
func TestGet ( t * testing . T ) {
2024-04-17 08:26:46 -07:00
u , uAccts , repoFn , aliasRepo := createDefaultUserAndRepos ( t , true )
2021-04-20 20:33:56 -04:00
2020-06-09 11:20:59 -07:00
toMerge := & pbs . GetUserRequest {
2020-07-22 00:14:28 -04:00
Id : u . GetPublicId (),
2020-06-09 11:20:59 -07:00
}
wantU := & pb . User {
2021-01-20 10:53:01 -05:00
Id : u . GetPublicId (),
ScopeId : u . GetScopeId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : u . ScopeId , Type : scope . Org . String (), ParentScopeId : scope . Global . String ()},
2021-01-20 10:53:01 -05:00
Name : & wrapperspb . StringValue { Value : u . GetName ()},
Description : & wrapperspb . StringValue { Value : u . GetDescription ()},
CreatedTime : u . CreateTime . GetTimestamp (),
UpdatedTime : u . UpdateTime . GetTimestamp (),
2021-04-20 20:33:56 -04:00
Version : u . Version ,
2021-04-23 09:13:37 -05:00
AuthorizedActions : testAuthorizedActions ,
2021-04-20 20:33:56 -04:00
LoginName : u . LoginName ,
FullName : u . GetFullName (),
Email : u . GetEmail (),
PrimaryAccountId : u . GetPrimaryAccountId (),
AccountIds : uAccts ,
Accounts : [] * pb . Account {{ Id : uAccts [ 0 ], ScopeId : u . ScopeId }, { Id : uAccts [ 1 ], ScopeId : u . ScopeId }},
2020-06-09 11:20:59 -07:00
}
cases := [] struct {
2020-09-23 08:10:27 -07:00
name string
req * pbs . GetUserRequest
res * pbs . GetUserResponse
err error
2020-06-09 11:20:59 -07:00
}{
{
2020-09-23 08:10:27 -07:00
name : "Get an Existing User" ,
req : & pbs . GetUserRequest { Id : u . GetPublicId ()},
res : & pbs . GetUserResponse { Item : wantU },
2020-06-09 11:20:59 -07:00
},
{
2024-02-16 08:30:16 -05:00
name : "Get a non existent User" ,
2023-03-10 15:06:39 -05:00
req : & pbs . GetUserRequest { Id : globals . UserPrefix + "_DoesntExis" },
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . NotFound ),
2020-06-09 11:20:59 -07:00
},
{
2020-09-23 08:10:27 -07:00
name : "Wrong id prefix" ,
req : & pbs . GetUserRequest { Id : "j_1234567890" },
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
{
2020-09-23 08:10:27 -07:00
name : "space in id" ,
2023-03-10 15:06:39 -05:00
req : & pbs . GetUserRequest { Id : globals . UserPrefix + "_1 23456789" },
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
2020-09-25 20:44:55 -07:00
assert , require := assert . New ( t ), require . New ( t )
2020-06-09 11:20:59 -07:00
req := proto . Clone ( toMerge ).( * pbs . GetUserRequest )
proto . Merge ( req , tc . req )
2024-04-17 08:26:46 -07:00
s , err := users . NewService ( context . Background (), repoFn , aliasRepo , 1000 )
2020-06-09 11:20:59 -07:00
require . NoError ( err , "Couldn't create new user service." )
2021-03-25 03:15:43 -04:00
got , gErr := s . GetUser ( auth . DisabledAuthTestContext ( repoFn , u . GetScopeId ()), req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "GetUser(%+v) got error %v, wanted %v" , req , gErr , tc . err )
}
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
got ,
tc . res ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
), "GetUser(%q) got response %q, wanted %q" , req , got , tc . res )
2020-06-09 11:20:59 -07:00
})
}
}
2020-07-02 08:17:52 -07:00
func TestList ( t * testing . T ) {
2023-12-20 16:51:57 -08:00
ctx := context . Background ()
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2024-04-17 08:26:46 -07:00
rw := db . New ( conn )
2020-07-02 08:17:52 -07:00
wrap := db . TestWrapper ( t )
2024-04-17 08:26:46 -07:00
kmsCache := kms . TestKms ( t , conn , wrap )
2020-08-19 16:47:18 -04:00
iamRepo := iam . TestRepo ( t , conn , wrap )
2020-07-02 08:17:52 -07:00
repoFn := func () ( * iam . Repository , error ) {
2020-08-19 16:47:18 -04:00
return iamRepo , nil
2020-07-02 08:17:52 -07:00
}
2024-04-17 08:26:46 -07:00
aliasRepoFn := func () ( * talias . Repository , error ) {
return talias . NewRepository ( context . Background (), rw , rw , kmsCache )
}
2020-07-02 08:17:52 -07:00
2024-04-17 08:26:46 -07:00
oNoUsers , _ := iam . TestScopes ( t , iamRepo )
oWithUsers , _ := iam . TestScopes ( t , iamRepo )
2020-07-02 08:17:52 -07:00
2021-04-20 20:33:56 -04:00
databaseWrap , err := kmsCache . GetWrapper ( context . Background (), oWithUsers . PublicId , kms . KeyPurposeDatabase )
require . NoError ( t , err )
primaryAm := oidc . TestAuthMethod ( t , conn , databaseWrap , oWithUsers . PublicId , oidc . ActivePublicState , "alice-rp" , "fido" ,
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , "https://alice-eve-smith.com" )[ 0 ]),
oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "http://localhost:9200" )[ 0 ]),
oidc . WithSigningAlgs ( oidc . RS256 ),
)
2024-04-17 08:26:46 -07:00
iam . TestSetPrimaryAuthMethod ( t , iamRepo , oWithUsers , primaryAm . PublicId )
2021-04-20 20:33:56 -04:00
secondaryAm := password . TestAuthMethods ( t , conn , oWithUsers . PublicId , 1 )
require . Len ( t , secondaryAm , 1 )
2024-04-17 08:26:46 -07:00
s , err := users . NewService ( context . Background (), repoFn , aliasRepoFn , 1000 )
2021-04-20 20:33:56 -04:00
require . NoError ( t , err )
2021-01-25 19:37:40 -05:00
2020-07-02 08:17:52 -07:00
var wantUsers [] * pb . User
2021-01-25 19:37:40 -05:00
// Populate expected values for recursive test
var totalUsers [] * pb . User
2023-12-20 16:51:57 -08:00
{
disabledAuthCtx := auth . DisabledAuthTestContext ( repoFn , "global" )
anon , err := s . GetUser ( disabledAuthCtx , & pbs . GetUserRequest { Id : globals . AnonymousUserId })
require . NoError ( t , err )
totalUsers = append ( totalUsers , anon . GetItem ())
authUser , err := s . GetUser ( disabledAuthCtx , & pbs . GetUserRequest { Id : globals . AnyAuthenticatedUserId })
require . NoError ( t , err )
totalUsers = append ( totalUsers , authUser . GetItem ())
recovery , err := s . GetUser ( disabledAuthCtx , & pbs . GetUserRequest { Id : globals . RecoveryUserId })
require . NoError ( t , err )
totalUsers = append ( totalUsers , recovery . GetItem ())
}
2021-01-25 19:37:40 -05:00
// Add new users
2020-07-02 08:17:52 -07:00
for i := 0 ; i < 10 ; i ++ {
2023-06-06 17:09:08 -04:00
newU , err := iam . NewUser ( ctx , oWithUsers . GetPublicId ())
2020-09-25 20:44:55 -07:00
require . NoError ( t , err )
2024-04-17 08:26:46 -07:00
u , err := iamRepo . CreateUser ( context . Background (), newU )
2020-09-25 20:44:55 -07:00
require . NoError ( t , err )
2021-04-20 20:33:56 -04:00
oidcAcct := oidc . TestAccount ( t , conn , primaryAm , fmt . Sprintf ( "alice+%d" , i ), oidc . WithFullName ( "Alice Eve Smith" ), oidc . WithEmail ( "alice@smith.com" ))
pwAcct := password . TestAccount ( t , conn , secondaryAm [ 0 ]. PublicId , fmt . Sprintf ( "alice+%d" , i ))
2024-04-17 08:26:46 -07:00
added , err := iamRepo . AddUserAccounts ( ctx , u . PublicId , u . Version , [] string { oidcAcct . PublicId , pwAcct . PublicId })
2021-04-20 20:33:56 -04:00
require . NoError ( t , err )
require . Len ( t , added , 2 )
2024-04-17 08:26:46 -07:00
u , _ , err = iamRepo . LookupUser ( ctx , u . PublicId )
2021-04-20 20:33:56 -04:00
require . NoError ( t , err )
2020-07-02 08:17:52 -07:00
wantUsers = append ( wantUsers , & pb . User {
2021-01-20 10:53:01 -05:00
Id : u . GetPublicId (),
ScopeId : u . GetScopeId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : u . GetScopeId (), Type : scope . Org . String (), ParentScopeId : scope . Global . String ()},
2021-01-20 10:53:01 -05:00
CreatedTime : u . GetCreateTime (). GetTimestamp (),
UpdatedTime : u . GetUpdateTime (). GetTimestamp (),
2021-04-20 20:33:56 -04:00
Version : 2 ,
2021-04-23 09:13:37 -05:00
AuthorizedActions : testAuthorizedActions ,
2021-04-20 20:33:56 -04:00
LoginName : oidcAcct . GetSubject (),
FullName : oidcAcct . GetFullName (),
Email : oidcAcct . GetEmail (),
PrimaryAccountId : oidcAcct . GetPublicId (),
2020-07-02 08:17:52 -07:00
})
}
2021-01-25 19:37:40 -05:00
// Populate these users into the total
2023-12-20 16:51:57 -08:00
totalUsers = append ( totalUsers , wantUsers ... )
slices . Reverse ( totalUsers )
slices . Reverse ( wantUsers )
// Run analyze to update postgres estimates
sqlDb , err := conn . SqlDB ( ctx )
require . NoError ( t , err )
_ , err = sqlDb . ExecContext ( ctx , "analyze" )
2021-01-25 19:37:40 -05:00
require . NoError ( t , err )
2023-12-20 16:51:57 -08:00
2020-07-02 08:17:52 -07:00
cases := [] struct {
2020-09-23 08:10:27 -07:00
name string
req * pbs . ListUsersRequest
res * pbs . ListUsersResponse
err error
2020-07-02 08:17:52 -07:00
}{
{
2020-09-23 08:10:27 -07:00
name : "List Many Users" ,
req : & pbs . ListUsersRequest { ScopeId : oWithUsers . GetPublicId ()},
2023-12-20 16:51:57 -08:00
res : & pbs . ListUsersResponse {
Items : wantUsers ,
EstItemCount : uint32 ( len ( wantUsers )),
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2020-07-02 08:17:52 -07:00
},
{
2020-09-23 08:10:27 -07:00
name : "List No Users" ,
req : & pbs . ListUsersRequest { ScopeId : oNoUsers . GetPublicId ()},
2023-12-20 16:51:57 -08:00
res : & pbs . ListUsersResponse {
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2020-07-02 08:17:52 -07:00
},
2021-01-25 19:37:40 -05:00
{
name : "List Recursively in Org" ,
req : & pbs . ListUsersRequest { ScopeId : oWithUsers . GetPublicId (), Recursive : true },
2023-12-20 16:51:57 -08:00
res : & pbs . ListUsersResponse {
Items : wantUsers ,
EstItemCount : uint32 ( len ( wantUsers )),
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2021-01-25 19:37:40 -05:00
},
{
name : "List Recursively in Global" ,
req : & pbs . ListUsersRequest { ScopeId : "global" , Recursive : true },
2023-12-20 16:51:57 -08:00
res : & pbs . ListUsersResponse {
Items : totalUsers ,
EstItemCount : uint32 ( len ( totalUsers )),
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2021-01-25 19:37:40 -05:00
},
2021-02-22 10:09:25 -07:00
{
name : "Filter Many Users" ,
req : & pbs . ListUsersRequest { ScopeId : "global" , Recursive : true , Filter : fmt . Sprintf ( `"/item/scope/id"==%q` , oWithUsers . GetPublicId ())},
2023-12-20 16:51:57 -08:00
res : & pbs . ListUsersResponse {
Items : wantUsers ,
EstItemCount : uint32 ( len ( wantUsers )),
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2021-02-22 10:09:25 -07:00
},
{
name : "Filter To No Users" ,
req : & pbs . ListUsersRequest { ScopeId : oWithUsers . GetPublicId (), Filter : `"/item/id"=="doesntmatch"` },
2023-12-20 16:51:57 -08:00
res : & pbs . ListUsersResponse {
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2021-02-22 10:09:25 -07:00
},
{
name : "Filter Bad Format" ,
req : & pbs . ListUsersRequest { ScopeId : oWithUsers . GetPublicId (), Filter : `"//id/"=="bad"` },
err : handlers . InvalidArgumentErrorf ( "bad format" , nil ),
},
2020-07-02 08:17:52 -07:00
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
2020-09-25 20:44:55 -07:00
assert , require := assert . New ( t ), require . New ( t )
2020-07-02 08:17:52 -07:00
require . NoError ( err , "Couldn't create new user service." )
2021-05-04 19:57:35 -05:00
// Test with non-anon user
2021-03-25 03:15:43 -04:00
got , gErr := s . ListUsers ( auth . DisabledAuthTestContext ( repoFn , tc . req . GetScopeId ()), tc . req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "ListUsers(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
2021-05-04 19:57:35 -05:00
return
2020-09-23 08:10:27 -07:00
}
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
got ,
tc . res ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
2023-12-20 16:51:57 -08:00
protocmp . IgnoreFields ( & pbs . ListUsersResponse {}, "list_token" ),
2023-10-31 13:44:17 +00:00
), "ListUsers(%q) got response %q, wanted %q" , tc . req , got , tc . res )
2021-05-04 19:57:35 -05:00
// Test with anon user
2022-10-28 15:52:06 -04:00
got , gErr = s . ListUsers ( auth . DisabledAuthTestContext ( repoFn , tc . req . GetScopeId (), auth . WithUserId ( globals . AnonymousUserId )), tc . req )
2021-05-04 19:57:35 -05:00
require . NoError ( gErr )
assert . Len ( got . Items , len ( tc . res . Items ))
for _ , item := range got . GetItems () {
require . Empty ( item . Version )
require . Nil ( item . CreatedTime )
require . Nil ( item . UpdatedTime )
require . Nil ( item . Accounts )
require . Nil ( item . AccountIds )
}
2020-07-02 08:17:52 -07:00
})
}
}
2023-12-20 16:51:57 -08:00
func userToProto ( u * iam . User , si * scopes . ScopeInfo , authorizedActions [] string ) * pb . User {
pu := & pb . User {
Id : u . GetPublicId (),
ScopeId : u . GetScopeId (),
Scope : si ,
CreatedTime : u . GetCreateTime (). GetTimestamp (),
UpdatedTime : u . GetUpdateTime (). GetTimestamp (),
Version : u . GetVersion (),
2024-04-17 08:26:46 -07:00
AuthorizedActions : authorizedActions ,
2023-12-20 16:51:57 -08:00
}
if u . GetName () != "" {
pu . Name = wrapperspb . String ( u . GetName ())
}
if u . GetDescription () != "" {
pu . Description = wrapperspb . String ( u . GetDescription ())
}
return pu
2021-04-20 20:33:56 -04:00
}
2023-12-20 16:51:57 -08:00
func TestListPagination ( t * testing . T ) {
// Set database read timeout to avoid duplicates in response
oldReadTimeout := globals . RefreshReadLookbackDuration
globals . RefreshReadLookbackDuration = 0
t . Cleanup ( func () {
globals . RefreshReadLookbackDuration = oldReadTimeout
})
ctx := context . Background ()
conn , _ := db . TestSetup ( t , "postgres" )
sqlDB , err := conn . SqlDB ( ctx )
require . NoError ( t , err )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
rw := db . New ( conn )
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
2024-04-17 08:26:46 -07:00
aliasRepoFn := func () ( * talias . Repository , error ) {
return talias . NewRepository ( ctx , rw , rw , kms )
}
2023-12-20 16:51:57 -08:00
tokenRepoFn := func () ( * authtoken . Repository , error ) {
return authtoken . NewRepository ( ctx , rw , rw , kms )
}
serversRepoFn := func () ( * server . Repository , error ) {
return server . NewRepository ( ctx , rw , rw , kms )
}
tokenRepo , err := tokenRepoFn ()
require . NoError ( t , err )
// Run analyze to update postgres meta tables
_ , err = sqlDB . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
oNoUsers , _ := iam . TestScopes ( t , iamRepo )
2024-02-15 09:26:29 -08:00
oWithUsers , p := iam . TestScopes ( t , iamRepo )
2023-12-20 16:51:57 -08:00
var allUsers [] * pb . User
// Get the 3 system users (u_recovery, u_anon, u_auth)
us , _ , err := iamRepo . ListUsers ( ctx , [] string { "global" })
require . NoError ( t , err )
require . Len ( t , us , 3 )
// They (should) be returned in reverse order by create time, so we reverse
slices . Reverse ( us )
for _ , u := range us {
allUsers = append ( allUsers , userToProto ( u , & scopes . ScopeInfo {
Id : u . ScopeId ,
Name : scope . Global . String (),
Description : "Global Scope" ,
Type : scope . Global . String (),
}, testAuthorizedActions ))
}
authMethod := password . TestAuthMethods ( t , conn , "global" , 1 )[ 0 ]
acct := password . TestAccount ( t , conn , authMethod . GetPublicId (), "test_user" )
u := iam . TestUser ( t , iamRepo , "global" , iam . WithAccountIds ( acct . PublicId ))
allUsers = append ( allUsers , userToProto ( u , & scopes . ScopeInfo {
Id : u . ScopeId ,
Name : scope . Global . String (),
Description : "Global Scope" ,
Type : scope . Global . String (),
}, testAuthorizedActions ))
// add roles to be able to see all users
allowedRole := iam . TestRole ( t , conn , "global" )
2024-01-17 23:54:49 -08:00
iam . TestRoleGrant ( t , conn , allowedRole . GetPublicId (), "ids=*;type=*;actions=*" )
2023-12-20 16:51:57 -08:00
iam . TestUserRole ( t , conn , allowedRole . GetPublicId (), u . GetPublicId ())
for _ , scope := range [] * iam . Scope { oWithUsers , oNoUsers } {
allowedRole := iam . TestRole ( t , conn , scope . GetPublicId ())
2024-01-17 23:54:49 -08:00
iam . TestRoleGrant ( t , conn , allowedRole . GetPublicId (), "ids=*;type=*;actions=*" )
2023-12-20 16:51:57 -08:00
iam . TestUserRole ( t , conn , allowedRole . GetPublicId (), u . GetPublicId ())
}
at , err := tokenRepo . CreateAuthToken ( ctx , u , acct . GetPublicId ())
require . NoError ( t , err )
// Test without anon user
requestInfo := authpb . RequestInfo {
TokenFormat : uint32 ( auth . AuthTokenTypeBearer ),
PublicId : at . GetPublicId (),
Token : at . GetToken (),
}
requestContext := context . WithValue ( context . Background (), requests . ContextRequestInformationKey , & requests . RequestContext {})
ctx = auth . NewVerifierContext ( requestContext , iamRepoFn , tokenRepoFn , serversRepoFn , kms , & requestInfo )
var safeToDeleteUser string
orgScopeInfo := & scopes . ScopeInfo { Id : oWithUsers . GetPublicId (), Type : scope . Org . String (), ParentScopeId : scope . Global . String ()}
for i := 0 ; i < 10 ; i ++ {
ou := iam . TestUser ( t , iamRepo , oWithUsers . GetPublicId ())
allUsers = append ( allUsers , userToProto ( ou , orgScopeInfo , testAuthorizedActions ))
safeToDeleteUser = ou . GetPublicId ()
}
slices . Reverse ( allUsers )
2024-04-17 08:26:46 -07:00
a , err := users . NewService ( ctx , iamRepoFn , aliasRepoFn , 1000 )
2023-12-20 16:51:57 -08:00
require . NoError ( t , err , "Couldn't create new user service." )
// Run analyze to update postgres estimates
_ , err = sqlDB . ExecContext ( context . Background (), "analyze" )
require . NoError ( t , err )
itemCount := uint32 ( len ( allUsers ))
testPageSize := int (( itemCount - 2 ) / 2 )
// Start paginating, recursively
req := & pbs . ListUsersRequest {
ScopeId : "global" ,
Recursive : true ,
Filter : "" ,
ListToken : "" ,
PageSize : uint32 ( testPageSize ),
}
got , err := a . ListUsers ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), testPageSize )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListUsersResponse {
Items : allUsers [ 0 : testPageSize ],
ResponseType : "delta" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
// In addition to the added users, there are the users added
// by the test setup when specifying the permissions of the
// requester
EstItemCount : itemCount ,
},
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListUsersResponse {}, "list_token" ),
),
)
// Request second page
req . ListToken = got . ListToken
got , err = a . ListUsers ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), testPageSize )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListUsersResponse {
Items : allUsers [ testPageSize : testPageSize * 2 ],
ResponseType : "delta" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListUsersResponse {}, "list_token" ),
),
)
// Request rest of results
req . ListToken = got . ListToken
req . PageSize = 10
got , err = a . ListUsers ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 2 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListUsersResponse {
Items : allUsers [ testPageSize * 2 :],
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListUsersResponse {}, "list_token" ),
),
)
// Update 2 users and see them in the refresh
r1 := allUsers [ len ( allUsers ) - 1 ]
r1 . Description = wrapperspb . String ( "updated1" )
resp1 , err := a . UpdateUser ( ctx , & pbs . UpdateUserRequest {
Id : r1 . GetId (),
Item : & pb . User { Description : r1 . GetDescription (), Version : r1 . GetVersion ()},
UpdateMask : & field_mask . FieldMask { Paths : [] string { "description" }},
})
require . NoError ( t , err )
r1 . UpdatedTime = resp1 . GetItem (). GetUpdatedTime ()
r1 . Version = resp1 . GetItem (). GetVersion ()
allUsers = append ([] * pb . User { r1 }, allUsers [: len ( allUsers ) - 1 ] ... )
r2 := allUsers [ len ( allUsers ) - 1 ]
r2 . Description = wrapperspb . String ( "updated2" )
resp2 , err := a . UpdateUser ( ctx , & pbs . UpdateUserRequest {
Id : r2 . GetId (),
Item : & pb . User { Description : r2 . GetDescription (), Version : r2 . GetVersion ()},
UpdateMask : & field_mask . FieldMask { Paths : [] string { "description" }},
})
require . NoError ( t , err )
r2 . UpdatedTime = resp2 . GetItem (). GetUpdatedTime ()
r2 . Version = resp2 . GetItem (). GetVersion ()
allUsers = append ([] * pb . User { r2 }, allUsers [: len ( allUsers ) - 1 ] ... )
// Run analyze to update postgres estimates
_ , err = sqlDB . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
// Request updated results
req . ListToken = got . ListToken
req . PageSize = 1
got , err = a . ListUsers ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListUsersResponse {
Items : [] * pb . User { allUsers [ 0 ]},
ResponseType : "delta" ,
SortBy : "updated_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListUsersResponse {}, "list_token" ),
),
)
// Get next page
req . ListToken = got . ListToken
got , err = a . ListUsers ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListUsersResponse {
Items : [] * pb . User { allUsers [ 1 ]},
ResponseType : "complete" ,
SortBy : "updated_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListUsersResponse {}, "list_token" ),
),
)
// Request new page with filter requiring looping
// to fill the page.
req . ListToken = ""
req . PageSize = 1
req . Filter = fmt . Sprintf ( `"/item/id"==%q or "/item/id"==%q` , allUsers [ len ( allUsers ) - 2 ]. Id , allUsers [ len ( allUsers ) - 1 ]. Id )
got , err = a . ListUsers ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListUsersResponse {
Items : [] * pb . User { allUsers [ len ( allUsers ) - 2 ]},
ResponseType : "delta" ,
SortBy : "created_time" ,
SortDir : "desc" ,
// Should be empty again
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListUsersResponse {}, "list_token" ),
),
)
req . ListToken = got . ListToken
// Get the second page
got , err = a . ListUsers ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListUsersResponse {
Items : [] * pb . User { allUsers [ len ( allUsers ) - 1 ]},
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListUsersResponse {}, "list_token" ),
),
)
_ , err = iamRepo . DeleteUser ( ctx , safeToDeleteUser )
require . NoError ( t , err )
req . ListToken = got . ListToken
got , err = a . ListUsers ( ctx , req )
require . NoError ( t , err )
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListUsersResponse {
Items : nil ,
ResponseType : "complete" ,
SortBy : "updated_time" ,
SortDir : "desc" ,
RemovedIds : [] string { safeToDeleteUser },
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListUsersResponse {}, "list_token" ),
),
)
2024-02-15 09:26:29 -08:00
// Create unauthenticated user
unauthAt := authtoken . TestAuthToken ( t , conn , kms , oWithUsers . GetPublicId ())
unauthR := iam . TestRole ( t , conn , p . GetPublicId ())
_ = iam . TestUserRole ( t , conn , unauthR . GetPublicId (), unauthAt . GetIamUserId ())
// Make a request with the unauthenticated user,
// ensure the response contains the pagination parameters.
requestInfo = authpb . RequestInfo {
TokenFormat : uint32 ( auth . AuthTokenTypeBearer ),
PublicId : unauthAt . GetPublicId (),
Token : unauthAt . GetToken (),
}
requestContext = context . WithValue ( context . Background (), requests . ContextRequestInformationKey , & requests . RequestContext {})
ctx = auth . NewVerifierContext ( requestContext , iamRepoFn , tokenRepoFn , serversRepoFn , kms , & requestInfo )
_ , err = a . ListUsers ( ctx , & pbs . ListUsersRequest {
ScopeId : "global" ,
Recursive : true ,
})
require . Error ( t , err )
assert . ErrorIs ( t , handlers . ForbiddenError (), err )
2023-12-20 16:51:57 -08:00
}
2021-04-20 20:33:56 -04:00
2024-04-17 08:26:46 -07:00
func TestListResolvableAliasesPagination ( t * testing . T ) {
// Set database read timeout to avoid duplicates in response
oldReadTimeout := globals . RefreshReadLookbackDuration
globals . RefreshReadLookbackDuration = 0
t . Cleanup ( func () {
globals . RefreshReadLookbackDuration = oldReadTimeout
})
ctx := context . Background ()
conn , _ := db . TestSetup ( t , "postgres" )
sqlDB , err := conn . SqlDB ( ctx )
require . NoError ( t , err )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
rw := db . New ( conn )
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
aliasRepoFn := func () ( * talias . Repository , error ) {
return talias . NewRepository ( ctx , rw , rw , kms )
}
tokenRepoFn := func () ( * authtoken . Repository , error ) {
return authtoken . NewRepository ( ctx , rw , rw , kms )
}
serversRepoFn := func () ( * server . Repository , error ) {
return server . NewRepository ( ctx , rw , rw , kms )
}
tokenRepo , err := tokenRepoFn ()
require . NoError ( t , err )
// Run analyze to update postgres meta tables
_ , err = sqlDB . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
_ , p := iam . TestScopes ( t , iamRepo )
tar := tcp . TestTarget ( ctx , t , conn , p . GetPublicId (), "resolvable" )
_ , unresolvableP := iam . TestScopes ( t , iamRepo )
unresolvedTar := tcp . TestTarget ( ctx , t , conn , unresolvableP . GetPublicId (), "unresolvable" )
// Create an alias that shouldn't be included in the paginated list results.
talias . TestAlias ( t , rw , "unresolved.alias" , talias . WithDestinationId ( unresolvedTar . GetPublicId ()))
authMethod := password . TestAuthMethods ( t , conn , "global" , 1 )[ 0 ]
acct := password . TestAccount ( t , conn , authMethod . GetPublicId (), "test_user" )
u := iam . TestUser ( t , iamRepo , "global" , iam . WithAccountIds ( acct . PublicId ))
// add roles for requester to be able to perform all actions on everyone
allowedRole := iam . TestRole ( t , conn , "global" , iam . WithGrantScopeIds ([] string { globals . GrantScopeThis , globals . GrantScopeDescendants }))
iam . TestRoleGrant ( t , conn , allowedRole . GetPublicId (), "ids=*;type=*;actions=*" )
iam . TestUserRole ( t , conn , allowedRole . GetPublicId (), u . GetPublicId ())
at , err := tokenRepo . CreateAuthToken ( ctx , u , acct . GetPublicId ())
require . NoError ( t , err )
// add roles for user whose resolvable aliases are being listed they can
// only see the aliases which resolve to targets in project p.
resolvingUsersAt := authtoken . TestAuthToken ( t , conn , kms , scope . Global . String ())
roleForResolving := iam . TestRole ( t , conn , "global" , iam . WithGrantScopeIds ([] string { p . GetPublicId (), globals . GrantScopeThis }))
iam . TestRoleGrant ( t , conn , roleForResolving . GetPublicId (), "ids=*;type=target;actions=authorize-session" )
iam . TestRoleGrant ( t , conn , roleForResolving . GetPublicId (), "ids={{.User.Id}};type=user;actions=list-resolvable-aliases" )
iam . TestUserRole ( t , conn , roleForResolving . GetPublicId (), resolvingUsersAt . GetIamUserId ())
var allAliases [] * talias . Alias
var allAliasPbs [] * pbalias . Alias
var safeToRemoveAlias * talias . Alias
for i := 0 ; i < 10 ; i ++ {
na := talias . TestAlias ( t , rw , fmt . Sprintf ( "aliase%d.test" , i ), talias . WithDestinationId ( tar . GetPublicId ()))
allAliases = append ( allAliases , na )
allAliasPbs = append ( allAliasPbs , & pbalias . Alias {
Id : na . GetPublicId (),
Value : na . GetValue (),
DestinationId : wrapperspb . String ( na . GetDestinationId ()),
CreatedTime : na . GetCreateTime (). GetTimestamp (),
UpdatedTime : na . GetUpdateTime (). GetTimestamp (),
Type : "target" ,
})
safeToRemoveAlias = na
}
slices . Reverse ( allAliases )
slices . Reverse ( allAliasPbs )
a , err := users . NewService ( ctx , iamRepoFn , aliasRepoFn , 1000 )
require . NoError ( t , err , "Couldn't create new user service." )
// Run analyze to update postgres estimates
_ , err = sqlDB . ExecContext ( context . Background (), "analyze" )
require . NoError ( t , err )
// +1 because we have one alias that points to an unresolvable target
itemCount := uint32 ( len ( allAliasPbs )) + 1
testPageSize := int (( itemCount - 2 ) / 2 )
// See that the resolvingUser can query themselves
requestInfo := authpb . RequestInfo {
TokenFormat : uint32 ( auth . AuthTokenTypeBearer ),
PublicId : resolvingUsersAt . GetPublicId (),
Token : resolvingUsersAt . GetToken (),
}
requestContext := context . WithValue ( context . Background (), requests . ContextRequestInformationKey , & requests . RequestContext {})
ctx = auth . NewVerifierContext ( requestContext , iamRepoFn , tokenRepoFn , serversRepoFn , kms , & requestInfo )
got , err := a . ListResolvableAliases ( ctx , & pbs . ListResolvableAliasesRequest {
Id : resolvingUsersAt . GetIamUserId (),
})
require . NoError ( t , err )
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListResolvableAliasesResponse {
Items : allAliasPbs ,
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 10 ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListResolvableAliasesResponse {}, "list_token" ),
),
)
// This user cannot list resolvable for other aliases
_ , err = a . ListResolvableAliases ( ctx , & pbs . ListResolvableAliasesRequest {
Id : at . GetIamUserId (),
})
require . Error ( t , err )
assert . ErrorIs ( t , handlers . ForbiddenError (), err )
// Now let the admin user list resolvable aliases
requestInfo = authpb . RequestInfo {
TokenFormat : uint32 ( auth . AuthTokenTypeBearer ),
PublicId : at . GetPublicId (),
Token : at . GetToken (),
}
requestContext = context . WithValue ( context . Background (), requests . ContextRequestInformationKey , & requests . RequestContext {})
ctx = auth . NewVerifierContext ( requestContext , iamRepoFn , tokenRepoFn , serversRepoFn , kms , & requestInfo )
req := & pbs . ListResolvableAliasesRequest {
Id : resolvingUsersAt . GetIamUserId (),
ListToken : "" ,
PageSize : uint32 ( testPageSize ),
}
got , err = a . ListResolvableAliases ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), testPageSize )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListResolvableAliasesResponse {
Items : allAliasPbs [ 0 : testPageSize ],
ResponseType : "delta" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
// In addition to the added users, there are the users added
// by the test setup when specifying the permissions of the
// requester
EstItemCount : itemCount ,
},
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListResolvableAliasesResponse {}, "list_token" ),
),
)
// Request second page
req . ListToken = got . ListToken
got , err = a . ListResolvableAliases ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), testPageSize )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListResolvableAliasesResponse {
Items : allAliasPbs [ testPageSize : testPageSize * 2 ],
ResponseType : "delta" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListResolvableAliasesResponse {}, "list_token" ),
),
)
// Request rest of results
req . ListToken = got . ListToken
req . PageSize = 10
got , err = a . ListResolvableAliases ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 2 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListResolvableAliasesResponse {
Items : allAliasPbs [ testPageSize * 2 :],
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListResolvableAliasesResponse {}, "list_token" ),
),
)
// Update 2 aliases and see them in the refresh
aliasRepo , err := aliasRepoFn ()
require . NoError ( t , err )
for i := 0 ; i < 2 ; i ++ {
r := allAliases [ len ( allAliasPbs ) - 1 ]
rPb := allAliasPbs [ len ( allAliasPbs ) - 1 ]
r . Description = fmt . Sprintf ( "updated%d" , i )
updated , _ , err := aliasRepo . UpdateAlias ( ctx , r , r . GetVersion (), [] string { "description" })
require . NoError ( t , err )
r . Version = updated . GetVersion ()
r . UpdateTime = updated . GetUpdateTime ()
rPb . UpdatedTime = updated . GetUpdateTime (). GetTimestamp ()
// ListResolvableAliases does not return the description, or the version
// so we do not update those values here in the protobuf aliases
allAliases = append ([] * talias . Alias { r }, allAliases [: len ( allAliases ) - 1 ] ... )
allAliasPbs = append ([] * pbalias . Alias { rPb }, allAliasPbs [: len ( allAliasPbs ) - 1 ] ... )
}
// Run analyze to update postgres estimates
_ , err = sqlDB . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
// Request updated results
req . ListToken = got . ListToken
req . PageSize = 1
got , err = a . ListResolvableAliases ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListResolvableAliasesResponse {
Items : [] * pbalias . Alias { allAliasPbs [ 0 ]},
ResponseType : "delta" ,
SortBy : "updated_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListResolvableAliasesResponse {}, "list_token" ),
),
)
// Get next page
req . ListToken = got . ListToken
got , err = a . ListResolvableAliases ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListResolvableAliasesResponse {
Items : [] * pbalias . Alias { allAliasPbs [ 1 ]},
ResponseType : "complete" ,
SortBy : "updated_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListResolvableAliasesResponse {}, "list_token" ),
),
)
_ , err = aliasRepo . DeleteAlias ( ctx , safeToRemoveAlias . GetPublicId ())
require . NoError ( t , err )
req . ListToken = got . ListToken
got , err = a . ListResolvableAliases ( ctx , req )
require . NoError ( t , err )
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListResolvableAliasesResponse {
Items : nil ,
ResponseType : "complete" ,
SortBy : "updated_time" ,
SortDir : "desc" ,
RemovedIds : [] string { safeToRemoveAlias . GetPublicId ()},
EstItemCount : itemCount ,
},
protocmp . Transform (),
protocmp . SortRepeated ( func ( a , b string ) bool {
return strings . Compare ( a , b ) < 0
}),
protocmp . IgnoreFields ( & pbs . ListResolvableAliasesResponse {}, "list_token" ),
),
)
// Create unauthenticated user
unauthAt := authtoken . TestAuthToken ( t , conn , kms , scope . Global . String ())
unauthR := iam . TestRole ( t , conn , p . GetPublicId ())
_ = iam . TestUserRole ( t , conn , unauthR . GetPublicId (), unauthAt . GetIamUserId ())
// Make a request with the unauthenticated user,
// ensure the response contains the pagination parameters.
requestInfo = authpb . RequestInfo {
TokenFormat : uint32 ( auth . AuthTokenTypeBearer ),
PublicId : unauthAt . GetPublicId (),
Token : unauthAt . GetToken (),
}
requestContext = context . WithValue ( context . Background (), requests . ContextRequestInformationKey , & requests . RequestContext {})
ctx = auth . NewVerifierContext ( requestContext , iamRepoFn , tokenRepoFn , serversRepoFn , kms , & requestInfo )
_ , err = a . ListResolvableAliases ( ctx , & pbs . ListResolvableAliasesRequest {
Id : resolvingUsersAt . GetIamUserId (),
})
require . Error ( t , err )
assert . ErrorIs ( t , handlers . ForbiddenError (), err )
}
2020-06-09 11:20:59 -07:00
func TestDelete ( t * testing . T ) {
2024-04-17 08:26:46 -07:00
u , _ , repoFn , aliasRepoFn := createDefaultUserAndRepos ( t , false )
2020-06-09 11:20:59 -07:00
2024-04-17 08:26:46 -07:00
s , err := users . NewService ( context . Background (), repoFn , aliasRepoFn , 1000 )
2020-09-23 08:10:27 -07:00
require . NoError ( t , err , "Error when getting new user service." )
2020-06-09 11:20:59 -07:00
cases := [] struct {
2020-09-23 08:10:27 -07:00
name string
req * pbs . DeleteUserRequest
res * pbs . DeleteUserResponse
err error
2020-06-09 11:20:59 -07:00
}{
{
name : "Delete an Existing User" ,
req : & pbs . DeleteUserRequest {
2020-07-22 00:14:28 -04:00
Id : u . GetPublicId (),
2020-06-09 11:20:59 -07:00
},
},
{
name : "Delete bad user id" ,
req : & pbs . DeleteUserRequest {
2023-03-10 15:06:39 -05:00
Id : globals . UserPrefix + "_doesntexis" ,
2020-06-09 11:20:59 -07:00
},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . NotFound ),
2020-06-09 11:20:59 -07:00
},
{
name : "Bad User Id formatting" ,
req : & pbs . DeleteUserRequest {
2020-07-22 00:14:28 -04:00
Id : "bad_format" ,
2020-06-09 11:20:59 -07:00
},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
2020-09-23 08:10:27 -07:00
assert , require := assert . New ( t ), require . New ( t )
2021-03-25 03:15:43 -04:00
got , gErr := s . DeleteUser ( auth . DisabledAuthTestContext ( repoFn , u . GetScopeId ()), tc . req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "DeleteUser(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
}
2020-06-09 11:20:59 -07:00
assert . EqualValuesf ( tc . res , got , "DeleteUser(%q) got response %q, wanted %q" , tc . req , got , tc . res )
})
}
}
func TestDelete_twice ( t * testing . T ) {
2020-09-23 08:10:27 -07:00
assert , require := assert . New ( t ), require . New ( t )
2024-04-17 08:26:46 -07:00
u , _ , repoFn , aliasRepoFn := createDefaultUserAndRepos ( t , false )
2020-06-09 11:20:59 -07:00
2024-04-17 08:26:46 -07:00
s , err := users . NewService ( context . Background (), repoFn , aliasRepoFn , 1000 )
2020-06-09 11:20:59 -07:00
require . NoError ( err , "Error when getting new user service" )
req := & pbs . DeleteUserRequest {
2020-07-22 00:14:28 -04:00
Id : u . GetPublicId (),
2020-06-09 11:20:59 -07:00
}
2021-03-25 03:15:43 -04:00
ctx := auth . DisabledAuthTestContext ( repoFn , u . GetScopeId ())
2020-09-08 23:57:26 -04:00
_ , gErr := s . DeleteUser ( ctx , req )
2020-06-09 11:20:59 -07:00
assert . NoError ( gErr , "First attempt" )
2020-09-08 23:57:26 -04:00
_ , gErr = s . DeleteUser ( ctx , req )
2020-09-04 14:48:11 -07:00
assert . Error ( gErr , "Second attempt" )
2020-09-23 08:10:27 -07:00
assert . True ( errors . Is ( gErr , handlers . ApiErrorWithCode ( codes . NotFound )), "Expected permission denied for the second delete." )
2020-06-09 11:20:59 -07:00
}
func TestCreate ( t * testing . T ) {
2024-04-17 08:26:46 -07:00
defaultUser , _ , repoFn , aliasRepoFn := createDefaultUserAndRepos ( t , false )
2021-04-20 20:33:56 -04:00
defaultCreated := defaultUser . GetCreateTime (). GetTimestamp (). AsTime ()
2020-06-09 11:20:59 -07:00
cases := [] struct {
2020-09-23 08:10:27 -07:00
name string
req * pbs . CreateUserRequest
res * pbs . CreateUserResponse
err error
2020-06-09 11:20:59 -07:00
}{
{
name : "Create a valid User" ,
req : & pbs . CreateUserRequest { Item : & pb . User {
2020-09-02 19:43:41 -07:00
ScopeId : defaultUser . GetScopeId (),
2020-06-09 11:20:59 -07:00
Name : & wrapperspb . StringValue { Value : "name" },
Description : & wrapperspb . StringValue { Value : "desc" },
}},
res : & pbs . CreateUserResponse {
2023-03-10 15:06:39 -05:00
Uri : fmt . Sprintf ( "users/%s_" , globals . UserPrefix ),
2020-06-09 11:20:59 -07:00
Item : & pb . User {
2021-01-20 10:53:01 -05:00
ScopeId : defaultUser . GetScopeId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : defaultUser . GetScopeId (), Type : scope . Org . String (), ParentScopeId : scope . Global . String ()},
2021-01-20 10:53:01 -05:00
Name : & wrapperspb . StringValue { Value : "name" },
Description : & wrapperspb . StringValue { Value : "desc" },
Version : 1 ,
2021-04-23 09:13:37 -05:00
AuthorizedActions : testAuthorizedActions ,
2020-06-09 11:20:59 -07:00
},
},
},
2020-09-03 08:02:30 -07:00
{
name : "Create a valid Global User" ,
req : & pbs . CreateUserRequest { Item : & pb . User {
ScopeId : scope . Global . String (),
Name : & wrapperspb . StringValue { Value : "name" },
Description : & wrapperspb . StringValue { Value : "desc" },
}},
res : & pbs . CreateUserResponse {
2023-03-10 15:06:39 -05:00
Uri : fmt . Sprintf ( "users/%s_" , globals . UserPrefix ),
2020-09-03 08:02:30 -07:00
Item : & pb . User {
2021-01-20 10:53:01 -05:00
ScopeId : scope . Global . String (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : scope . Global . String (), Type : scope . Global . String (), Name : scope . Global . String (), Description : "Global Scope" },
2021-01-20 10:53:01 -05:00
Name : & wrapperspb . StringValue { Value : "name" },
Description : & wrapperspb . StringValue { Value : "desc" },
Version : 1 ,
2021-04-23 09:13:37 -05:00
AuthorizedActions : testAuthorizedActions ,
2020-09-03 08:02:30 -07:00
},
},
},
2020-06-09 11:20:59 -07:00
{
name : "Can't specify Id" ,
req : & pbs . CreateUserRequest { Item : & pb . User {
2020-09-02 19:43:41 -07:00
ScopeId : defaultUser . GetScopeId (),
2023-03-10 15:06:39 -05:00
Id : globals . UserPrefix + "_notallowed" ,
2020-06-09 11:20:59 -07:00
}},
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
{
name : "Can't specify Created Time" ,
req : & pbs . CreateUserRequest { Item : & pb . User {
2020-09-02 19:43:41 -07:00
ScopeId : defaultUser . GetScopeId (),
2021-04-20 20:33:56 -04:00
CreatedTime : timestamppb . Now (),
2020-06-09 11:20:59 -07:00
}},
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
{
name : "Can't specify Update Time" ,
req : & pbs . CreateUserRequest { Item : & pb . User {
2020-09-02 19:43:41 -07:00
ScopeId : defaultUser . GetScopeId (),
2021-04-20 20:33:56 -04:00
UpdatedTime : timestamppb . Now (),
2020-06-09 11:20:59 -07:00
}},
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
2020-09-23 08:10:27 -07:00
assert , require := assert . New ( t ), require . New ( t )
2024-04-17 08:26:46 -07:00
s , err := users . NewService ( context . Background (), repoFn , aliasRepoFn , 1000 )
2020-06-09 11:20:59 -07:00
require . NoError ( err , "Error when getting new user service." )
2021-03-25 03:15:43 -04:00
got , gErr := s . CreateUser ( auth . DisabledAuthTestContext ( repoFn , tc . req . GetItem (). GetScopeId ()), tc . req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "CreateUser(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
}
2020-06-09 11:20:59 -07:00
if got != nil {
2020-08-05 10:19:55 -07:00
assert . Contains ( got . GetUri (), tc . res . Uri )
2023-03-10 15:06:39 -05:00
assert . True ( strings . HasPrefix ( got . GetItem (). GetId (), globals . UserPrefix + "_" ))
2021-04-20 20:33:56 -04:00
gotCreateTime := got . GetItem (). GetCreatedTime (). AsTime ()
gotUpdateTime := got . GetItem (). GetUpdatedTime (). AsTime ()
2020-06-09 11:20:59 -07:00
// Verify it is a user created after the test setup's default user
assert . True ( gotCreateTime . After ( defaultCreated ), "New user should have been created after default user. Was created %v, which is after %v" , gotCreateTime , defaultCreated )
assert . True ( gotUpdateTime . After ( defaultCreated ), "New user should have been updated after default user. Was updated %v, which is after %v" , gotUpdateTime , defaultCreated )
// Clear all values which are hard to compare against.
got . Uri , tc . res . Uri = "" , ""
got . Item . Id , tc . res . Item . Id = "" , ""
got . Item . CreatedTime , got . Item . UpdatedTime , tc . res . Item . CreatedTime , tc . res . Item . UpdatedTime = nil , nil , nil , nil
}
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
got ,
tc . res ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
), "CreateUser(%q) got response %q, wanted %q" , tc . req , got , tc . res )
2020-06-09 11:20:59 -07:00
})
}
}
func TestUpdate ( t * testing . T ) {
2024-04-17 08:26:46 -07:00
u , _ , repoFn , aliasRepoFn := createDefaultUserAndRepos ( t , false )
tested , err := users . NewService ( context . Background (), repoFn , aliasRepoFn , 1000 )
2020-08-07 12:55:02 -04:00
require . NoError ( t , err , "Error when getting new user service." )
2020-06-09 11:20:59 -07:00
2021-04-20 20:33:56 -04:00
created := u . GetCreateTime (). GetTimestamp (). AsTime ()
2020-06-09 11:20:59 -07:00
toMerge := & pbs . UpdateUserRequest {
2020-07-22 00:14:28 -04:00
Id : u . GetPublicId (),
2020-06-09 11:20:59 -07:00
}
2020-08-07 12:55:02 -04:00
var version uint32 = 1
resetUser := func () {
repo , err := repoFn ()
require . NoError ( t , err , "Couldn't get a new repo" )
version ++ // From the test case that resulted in calling this
2020-09-25 13:35:32 -04:00
u , _ , _ , err = repo . UpdateUser ( context . Background (), u , version , [] string { "Name" , "Description" })
2020-08-07 12:55:02 -04:00
require . NoError ( t , err , "Failed to reset the user" )
version ++
}
2020-06-09 11:20:59 -07:00
cases := [] struct {
2020-09-23 08:10:27 -07:00
name string
req * pbs . UpdateUserRequest
res * pbs . UpdateUserResponse
err error
2020-06-09 11:20:59 -07:00
}{
{
name : "Update an Existing User" ,
req : & pbs . UpdateUserRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name" , "description" },
},
Item : & pb . User {
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
},
},
res : & pbs . UpdateUserResponse {
Item : & pb . User {
2021-01-20 10:53:01 -05:00
Id : u . GetPublicId (),
ScopeId : u . GetScopeId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : u . GetScopeId (), Type : scope . Org . String (), ParentScopeId : scope . Global . String ()},
2021-01-20 10:53:01 -05:00
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
CreatedTime : u . GetCreateTime (). GetTimestamp (),
2021-04-23 09:13:37 -05:00
AuthorizedActions : testAuthorizedActions ,
2020-06-09 11:20:59 -07:00
},
},
},
{
name : "Multiple Paths in single string" ,
req : & pbs . UpdateUserRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name,description" },
},
Item : & pb . User {
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
},
},
res : & pbs . UpdateUserResponse {
Item : & pb . User {
2021-01-20 10:53:01 -05:00
Id : u . GetPublicId (),
ScopeId : u . GetScopeId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : u . GetScopeId (), Type : scope . Org . String (), ParentScopeId : scope . Global . String ()},
2021-01-20 10:53:01 -05:00
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
CreatedTime : u . GetCreateTime (). GetTimestamp (),
2021-04-23 09:13:37 -05:00
AuthorizedActions : testAuthorizedActions ,
2020-06-09 11:20:59 -07:00
},
},
},
{
name : "No Update Mask" ,
req : & pbs . UpdateUserRequest {
Item : & pb . User {
Name : & wrapperspb . StringValue { Value : "updated name" },
Description : & wrapperspb . StringValue { Value : "updated desc" },
},
},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
{
name : "No Paths in Mask" ,
req : & pbs . UpdateUserRequest {
UpdateMask : & field_mask . FieldMask { Paths : [] string {}},
Item : & pb . User {
Name : & wrapperspb . StringValue { Value : "updated name" },
Description : & wrapperspb . StringValue { Value : "updated desc" },
},
},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
{
2024-02-16 08:30:16 -05:00
name : "Only non-existent paths in Mask" ,
2020-06-09 11:20:59 -07:00
req : & pbs . UpdateUserRequest {
2024-02-16 08:30:16 -05:00
UpdateMask : & field_mask . FieldMask { Paths : [] string { "nonexistent_field" }},
2020-06-09 11:20:59 -07:00
Item : & pb . User {
Name : & wrapperspb . StringValue { Value : "updated name" },
Description : & wrapperspb . StringValue { Value : "updated desc" },
},
},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
{
name : "Unset Name" ,
req : & pbs . UpdateUserRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name" },
},
Item : & pb . User {
Description : & wrapperspb . StringValue { Value : "ignored" },
},
},
res : & pbs . UpdateUserResponse {
Item : & pb . User {
2021-01-20 10:53:01 -05:00
Id : u . GetPublicId (),
ScopeId : u . GetScopeId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : u . GetScopeId (), Type : scope . Org . String (), ParentScopeId : scope . Global . String ()},
2021-01-20 10:53:01 -05:00
Description : & wrapperspb . StringValue { Value : "default" },
CreatedTime : u . GetCreateTime (). GetTimestamp (),
2021-04-23 09:13:37 -05:00
AuthorizedActions : testAuthorizedActions ,
2020-06-09 11:20:59 -07:00
},
},
},
{
name : "Update Only Name" ,
req : & pbs . UpdateUserRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name" },
},
Item : & pb . User {
Name : & wrapperspb . StringValue { Value : "updated" },
Description : & wrapperspb . StringValue { Value : "ignored" },
},
},
res : & pbs . UpdateUserResponse {
Item : & pb . User {
2021-01-20 10:53:01 -05:00
Id : u . GetPublicId (),
ScopeId : u . GetScopeId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : u . GetScopeId (), Type : scope . Org . String (), ParentScopeId : scope . Global . String ()},
2021-01-20 10:53:01 -05:00
Name : & wrapperspb . StringValue { Value : "updated" },
Description : & wrapperspb . StringValue { Value : "default" },
CreatedTime : u . GetCreateTime (). GetTimestamp (),
2021-04-23 09:13:37 -05:00
AuthorizedActions : testAuthorizedActions ,
2020-06-09 11:20:59 -07:00
},
},
},
{
name : "Update Only Description" ,
req : & pbs . UpdateUserRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "description" },
},
Item : & pb . User {
Name : & wrapperspb . StringValue { Value : "ignored" },
Description : & wrapperspb . StringValue { Value : "notignored" },
},
},
res : & pbs . UpdateUserResponse {
Item : & pb . User {
2021-01-20 10:53:01 -05:00
Id : u . GetPublicId (),
ScopeId : u . GetScopeId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : u . GetScopeId (), Type : scope . Org . String (), ParentScopeId : scope . Global . String ()},
2021-01-20 10:53:01 -05:00
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "notignored" },
CreatedTime : u . GetCreateTime (). GetTimestamp (),
2021-04-23 09:13:37 -05:00
AuthorizedActions : testAuthorizedActions ,
2020-06-09 11:20:59 -07:00
},
},
},
{
name : "Update a Non Existing User" ,
req : & pbs . UpdateUserRequest {
2023-03-10 15:06:39 -05:00
Id : globals . UserPrefix + "_DoesntExis" ,
2020-06-09 11:20:59 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "description" },
},
Item : & pb . User {
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
},
},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . NotFound ),
2020-06-09 11:20:59 -07:00
},
{
name : "Cant change Id" ,
req : & pbs . UpdateUserRequest {
Id : u . GetPublicId (),
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "id" },
},
Item : & pb . User {
2023-03-10 15:06:39 -05:00
Id : globals . UserPrefix + "_somethinge" ,
2020-06-09 11:20:59 -07:00
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "new desc" },
2021-01-07 10:02:32 -05:00
},
},
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
{
name : "Cant specify Created Time" ,
req : & pbs . UpdateUserRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "created_time" },
},
Item : & pb . User {
2021-04-20 20:33:56 -04:00
CreatedTime : timestamppb . Now (),
2020-06-09 11:20:59 -07:00
},
},
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
{
name : "Cant specify Updated Time" ,
req : & pbs . UpdateUserRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "updated_time" },
},
Item : & pb . User {
2021-04-20 20:33:56 -04:00
UpdatedTime : timestamppb . Now (),
2020-06-09 11:20:59 -07:00
},
},
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-06-09 11:20:59 -07:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
2020-08-18 17:38:38 -07:00
tc . req . Item . Version = version
2020-08-07 12:55:02 -04:00
assert , require := assert . New ( t ), require . New ( t )
2020-06-09 11:20:59 -07:00
req := proto . Clone ( toMerge ).( * pbs . UpdateUserRequest )
proto . Merge ( req , tc . req )
2020-08-07 12:55:02 -04:00
// Test with bad version (too high, too low)
2020-08-18 17:38:38 -07:00
req . Item . Version = version + 2
2021-03-25 03:15:43 -04:00
_ , gErr := tested . UpdateUser ( auth . DisabledAuthTestContext ( repoFn , u . GetScopeId ()), req )
2020-08-07 12:55:02 -04:00
require . Error ( gErr )
2020-08-18 17:38:38 -07:00
req . Item . Version = version - 1
2021-03-25 03:15:43 -04:00
_ , gErr = tested . UpdateUser ( auth . DisabledAuthTestContext ( repoFn , u . GetScopeId ()), req )
2020-08-07 12:55:02 -04:00
require . Error ( gErr )
2020-08-18 17:38:38 -07:00
req . Item . Version = version
2020-08-07 12:55:02 -04:00
2021-03-25 03:15:43 -04:00
got , gErr := tested . UpdateUser ( auth . DisabledAuthTestContext ( repoFn , u . GetScopeId ()), req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
require . True ( errors . Is ( gErr , tc . err ), "UpdateUser(%+v) got error %v, wanted %v" , req , gErr , tc . err )
} else {
2020-08-07 12:55:02 -04:00
defer resetUser ()
}
2020-06-09 11:20:59 -07:00
if got != nil {
assert . NotNilf ( tc . res , "Expected UpdateUser response to be nil, but was %v" , got )
2021-04-20 20:33:56 -04:00
gotUpdateTime := got . GetItem (). GetUpdatedTime (). AsTime ()
2020-06-09 11:20:59 -07:00
// Verify it is a user updated after it was created
assert . True ( gotUpdateTime . After ( created ), "Updated user should have been updated after it's creation. Was updated %v, which is after %v" , gotUpdateTime , created )
// Clear all values which are hard to compare against.
got . Item . UpdatedTime , tc . res . Item . UpdatedTime = nil , nil
2020-08-07 12:55:02 -04:00
assert . Equal ( version + 1 , got . GetItem (). GetVersion ())
tc . res . Item . Version = version + 1
2020-06-09 11:20:59 -07:00
}
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
tc . res ,
got ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
), "UpdateUser(%q) got response %q, wanted %q" , req , got , tc . res )
2020-06-09 11:20:59 -07:00
})
}
}
2020-09-25 20:44:55 -07:00
func TestAddAccount ( t * testing . T ) {
conn , _ := db . TestSetup ( t , "postgres" )
wrap := db . TestWrapper ( t )
2023-05-03 09:45:29 -04:00
ctx := context . Background ()
2024-04-17 08:26:46 -07:00
rw := db . New ( conn )
2021-04-14 11:34:17 -07:00
kmsCache := kms . TestKms ( t , conn , wrap )
2020-09-25 20:44:55 -07:00
iamRepo := iam . TestRepo ( t , conn , wrap )
repoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
2024-04-17 08:26:46 -07:00
aliasRepoFn := func () ( * talias . Repository , error ) {
return talias . NewRepository ( ctx , rw , rw , kmsCache )
}
s , err := users . NewService ( ctx , repoFn , aliasRepoFn , 1000 )
2020-09-25 20:44:55 -07:00
require . NoError ( t , err , "Error when getting new user service." )
o , _ := iam . TestScopes ( t , iamRepo )
2021-04-20 20:33:56 -04:00
acctCnt := 3
accts := make ([] * password . Account , 0 , acctCnt )
for i := 0 ; i < acctCnt ; i ++ {
amId := password . TestAuthMethods ( t , conn , o . GetPublicId (), 1 )[ 0 ]. GetPublicId ()
newAcct := password . TestAccount ( t , conn , amId , "name1" )
accts = append ( accts , newAcct )
}
2020-09-25 20:44:55 -07:00
2021-04-14 11:34:17 -07:00
databaseWrapper , err := kmsCache . GetWrapper ( context . Background (), o . PublicId , kms . KeyPurposeDatabase )
2021-04-20 20:33:56 -04:00
require . NoError ( t , err )
2021-04-14 11:34:17 -07:00
oidcAm := oidc . TestAuthMethod (
t , conn , databaseWrapper , o . PublicId , oidc . ActivePrivateState ,
"alice-rp" , "fido" ,
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , "https://www.alice.com" )[ 0 ]),
oidc . WithSigningAlgs ( oidc . RS256 ),
oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://www.alice.com/callback" )[ 0 ]),
)
oidcAcct := oidc . TestAccount ( t , conn , oidcAm , "test-subject" )
2023-05-03 09:45:29 -04:00
ldapAm := ldap . TestAuthMethod ( t , conn , databaseWrapper , o . PublicId , [] string { "ldaps://ldap1" })
ldapAcct := ldap . TestAccount ( t , conn , ldapAm , "test-acct" ,
ldap . WithMemberOfGroups ( ctx , "admin" ),
ldap . WithFullName ( ctx , "test-name" ),
ldap . WithEmail ( ctx , "test-email" ),
ldap . WithDn ( ctx , "test-dn" ),
)
2020-09-25 20:44:55 -07:00
addCases := [] struct {
2020-09-28 15:39:10 -04:00
name string
setup func ( * iam . User )
addAccounts [] string
resultAccounts [] string
wantErr bool
2020-09-25 20:44:55 -07:00
}{
{
2020-09-28 15:39:10 -04:00
name : "Add account on empty user" ,
setup : func ( u * iam . User ) {},
addAccounts : [] string { accts [ 1 ]. GetPublicId ()},
2020-09-25 20:44:55 -07:00
resultAccounts : [] string { accts [ 1 ]. GetPublicId ()},
},
2021-04-14 11:34:17 -07:00
{
name : "Add oidc account on empty user" ,
setup : func ( u * iam . User ) {},
addAccounts : [] string { oidcAcct . GetPublicId ()},
resultAccounts : [] string { oidcAcct . GetPublicId ()},
},
2023-05-03 09:45:29 -04:00
{
name : "Add ldap account on empty user" ,
setup : func ( u * iam . User ) {},
addAccounts : [] string { ldapAcct . GetPublicId ()},
resultAccounts : [] string { ldapAcct . GetPublicId ()},
},
2020-09-25 20:44:55 -07:00
{
name : "Add account on populated user" ,
setup : func ( u * iam . User ) {
2020-09-28 15:39:10 -04:00
_ , err := iamRepo . SetUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
2020-09-25 20:44:55 -07:00
[] string { accts [ 0 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
2020-09-28 15:39:10 -04:00
addAccounts : [] string { accts [ 1 ]. GetPublicId ()},
2020-09-25 20:44:55 -07:00
resultAccounts : [] string { accts [ 0 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()},
},
2020-10-02 16:45:32 -07:00
{
name : "Add duplicate account on populated user" ,
setup : func ( u * iam . User ) {
_ , err := iamRepo . SetUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
[] string { accts [ 0 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
addAccounts : [] string { accts [ 1 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()},
resultAccounts : [] string { accts [ 0 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()},
},
2020-09-25 20:44:55 -07:00
{
name : "Add empty on populated user" ,
setup : func ( u * iam . User ) {
2021-04-20 20:33:56 -04:00
_ , err := iamRepo . SetUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
2020-09-25 20:44:55 -07:00
[] string { accts [ 0 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
wantErr : true ,
},
}
for _ , tc := range addCases {
t . Run ( tc . name , func ( t * testing . T ) {
usr := iam . TestUser ( t , iamRepo , o . GetPublicId ())
defer func () {
_ , err := iamRepo . DeleteUser ( context . Background (), usr . GetPublicId ())
require . NoError ( t , err )
}()
tc . setup ( usr )
req := & pbs . AddUserAccountsRequest {
Id : usr . GetPublicId (),
Version : usr . GetVersion (),
AccountIds : tc . addAccounts ,
}
2021-03-25 03:15:43 -04:00
got , err := s . AddUserAccounts ( auth . DisabledAuthTestContext ( repoFn , o . GetPublicId ()), req )
2020-09-25 20:44:55 -07:00
if tc . wantErr {
assert . Error ( t , err )
return
}
require . NoError ( t , err , "Got error: %v" , err )
assert . ElementsMatch ( t , got . GetItem (). GetAccountIds (), tc . resultAccounts )
})
}
usr := iam . TestUser ( t , iamRepo , o . GetPublicId ())
failCases := [] struct {
name string
req * pbs . AddUserAccountsRequest
err error
}{
{
name : "Bad user Id" ,
req : & pbs . AddUserAccountsRequest {
Id : "bad id" ,
Version : usr . GetVersion (),
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2020-10-02 16:45:32 -07:00
{
name : "Bad account Id" ,
req : & pbs . AddUserAccountsRequest {
2020-10-06 13:17:28 -04:00
Id : usr . GetPublicId (),
Version : usr . GetVersion (),
2020-10-02 16:45:32 -07:00
AccountIds : [] string { "invalid" },
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2020-09-25 20:44:55 -07:00
}
for _ , tc := range failCases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
2021-03-25 03:15:43 -04:00
_ , gErr := s . AddUserAccounts ( auth . DisabledAuthTestContext ( repoFn , usr . GetScopeId ()), tc . req )
2020-09-25 20:44:55 -07:00
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "AddUserAccounts(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
}
})
}
}
func TestSetAccount ( t * testing . T ) {
conn , _ := db . TestSetup ( t , "postgres" )
wrap := db . TestWrapper ( t )
2023-05-03 09:45:29 -04:00
ctx := context . Background ()
2024-04-17 08:26:46 -07:00
rw := db . New ( conn )
2021-04-14 11:34:17 -07:00
kmsCache := kms . TestKms ( t , conn , wrap )
2020-09-25 20:44:55 -07:00
iamRepo := iam . TestRepo ( t , conn , wrap )
repoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
2024-04-17 08:26:46 -07:00
aliasRepoFn := func () ( * talias . Repository , error ) {
return talias . NewRepository ( ctx , rw , rw , kmsCache )
}
s , err := users . NewService ( ctx , repoFn , aliasRepoFn , 1000 )
2020-09-25 20:44:55 -07:00
require . NoError ( t , err , "Error when getting new user service." )
o , _ := iam . TestScopes ( t , iamRepo )
2021-04-20 20:33:56 -04:00
acctCnt := 3
accts := make ([] * password . Account , 0 , acctCnt )
for i := 0 ; i < acctCnt ; i ++ {
amId := password . TestAuthMethods ( t , conn , o . GetPublicId (), 1 )[ 0 ]. GetPublicId ()
newAcct := password . TestAccount ( t , conn , amId , "name1" )
accts = append ( accts , newAcct )
}
2020-09-25 20:44:55 -07:00
2021-04-14 11:34:17 -07:00
databaseWrapper , err := kmsCache . GetWrapper ( context . Background (), o . PublicId , kms . KeyPurposeDatabase )
2021-04-20 20:33:56 -04:00
require . NoError ( t , err )
2021-04-14 11:34:17 -07:00
oidcAm := oidc . TestAuthMethod (
t , conn , databaseWrapper , o . PublicId , oidc . ActivePrivateState ,
"alice-rp" , "fido" ,
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , "https://www.alice.com" )[ 0 ]),
oidc . WithSigningAlgs ( oidc . RS256 ),
oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://www.alice.com/callback" )[ 0 ]),
)
oidcAcct := oidc . TestAccount ( t , conn , oidcAm , "test-subject" )
2023-05-03 09:45:29 -04:00
ldapAm := ldap . TestAuthMethod ( t , conn , databaseWrapper , o . PublicId , [] string { "ldaps://ldap1" })
ldapAcct := ldap . TestAccount ( t , conn , ldapAm , "test-acct" ,
ldap . WithMemberOfGroups ( ctx , "admin" ),
ldap . WithFullName ( ctx , "test-name" ),
ldap . WithEmail ( ctx , "test-email" ),
ldap . WithDn ( ctx , "test-dn" ),
)
2020-09-25 20:44:55 -07:00
setCases := [] struct {
2020-09-28 15:39:10 -04:00
name string
setup func ( * iam . User )
setAccounts [] string
2020-09-25 20:44:55 -07:00
resultAccounts [] string
2020-09-28 15:39:10 -04:00
wantErr bool
2020-09-25 20:44:55 -07:00
}{
{
2020-09-28 15:39:10 -04:00
name : "Set account on empty user" ,
setup : func ( u * iam . User ) {},
2020-09-25 20:44:55 -07:00
setAccounts : [] string { accts [ 1 ]. GetPublicId ()},
resultAccounts : [] string { accts [ 1 ]. GetPublicId ()},
},
2021-04-14 11:34:17 -07:00
{
name : "Set oidc account on empty user" ,
setup : func ( u * iam . User ) {},
setAccounts : [] string { oidcAcct . GetPublicId ()},
resultAccounts : [] string { oidcAcct . GetPublicId ()},
},
2023-05-03 09:45:29 -04:00
{
name : "Set ldap account on empty user" ,
setup : func ( u * iam . User ) {},
setAccounts : [] string { ldapAcct . GetPublicId ()},
resultAccounts : [] string { ldapAcct . GetPublicId ()},
},
2020-09-25 20:44:55 -07:00
{
name : "Set account on populated user" ,
setup : func ( u * iam . User ) {
2021-04-20 20:33:56 -04:00
_ , err := iamRepo . AddUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
2020-09-25 20:44:55 -07:00
[] string { accts [ 0 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
setAccounts : [] string { accts [ 1 ]. GetPublicId ()},
resultAccounts : [] string { accts [ 1 ]. GetPublicId ()},
},
2020-10-02 16:45:32 -07:00
{
name : "Set duplicate account on populated user" ,
setup : func ( u * iam . User ) {
2021-04-20 20:33:56 -04:00
_ , err := iamRepo . AddUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
2020-10-02 16:45:32 -07:00
[] string { accts [ 0 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
setAccounts : [] string { accts [ 1 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()},
resultAccounts : [] string { accts [ 1 ]. GetPublicId ()},
},
2020-09-25 20:44:55 -07:00
{
name : "Set empty on populated user" ,
setup : func ( u * iam . User ) {
2021-04-20 20:33:56 -04:00
_ , err := iamRepo . AddUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
2020-09-25 20:44:55 -07:00
[] string { accts [ 0 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
setAccounts : [] string {},
resultAccounts : nil ,
},
}
for _ , tc := range setCases {
2020-09-28 15:39:10 -04:00
t . Run ( tc . name , func ( t * testing . T ) {
usr := iam . TestUser ( t , iamRepo , o . GetPublicId ())
defer func () {
2021-04-23 09:13:37 -05:00
_ , err := iamRepo . DeleteUser ( context . Background (), usr . GetPublicId ())
require . NoError ( t , err )
2020-09-28 15:39:10 -04:00
}()
tc . setup ( usr )
req := & pbs . SetUserAccountsRequest {
Id : usr . GetPublicId (),
Version : usr . GetVersion (),
AccountIds : tc . setAccounts ,
}
2021-03-25 03:15:43 -04:00
got , err := s . SetUserAccounts ( auth . DisabledAuthTestContext ( repoFn , o . GetPublicId ()), req )
2020-09-28 15:39:10 -04:00
if tc . wantErr {
assert . Error ( t , err )
return
}
require . NoError ( t , err , "Got error: %v" , err )
assert . ElementsMatch ( t , got . GetItem (). GetAccountIds (), tc . resultAccounts )
})
2020-09-25 20:44:55 -07:00
}
usr := iam . TestUser ( t , iamRepo , o . GetPublicId ())
failCases := [] struct {
name string
req * pbs . SetUserAccountsRequest
err error
}{
{
name : "Bad User Id" ,
req : & pbs . SetUserAccountsRequest {
Id : "bad id" ,
Version : usr . GetVersion (),
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2020-10-02 16:45:32 -07:00
{
name : "Bad account Id" ,
req : & pbs . SetUserAccountsRequest {
2020-10-06 13:17:28 -04:00
Id : usr . GetPublicId (),
Version : usr . GetVersion (),
2020-10-02 16:45:32 -07:00
AccountIds : [] string { "invalid" },
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2020-09-25 20:44:55 -07:00
}
for _ , tc := range failCases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
2021-03-25 03:15:43 -04:00
_ , gErr := s . SetUserAccounts ( auth . DisabledAuthTestContext ( repoFn , usr . GetScopeId ()), tc . req )
2020-09-25 20:44:55 -07:00
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "SetUserAccounts(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
}
})
}
}
func TestRemoveAccount ( t * testing . T ) {
conn , _ := db . TestSetup ( t , "postgres" )
wrap := db . TestWrapper ( t )
2023-05-03 09:45:29 -04:00
ctx := context . Background ()
2024-04-17 08:26:46 -07:00
rw := db . New ( conn )
2021-04-14 11:34:17 -07:00
kmsCache := kms . TestKms ( t , conn , wrap )
2020-09-25 20:44:55 -07:00
iamRepo := iam . TestRepo ( t , conn , wrap )
repoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
2024-04-17 08:26:46 -07:00
aliasRepoFn := func () ( * talias . Repository , error ) {
return talias . NewRepository ( ctx , rw , rw , kmsCache )
}
s , err := users . NewService ( ctx , repoFn , aliasRepoFn , 1000 )
2020-09-25 20:44:55 -07:00
require . NoError ( t , err , "Error when getting new user service." )
o , _ := iam . TestScopes ( t , iamRepo )
2021-04-20 20:33:56 -04:00
acctCnt := 3
accts := make ([] * password . Account , 0 , acctCnt )
for i := 0 ; i < acctCnt ; i ++ {
amId := password . TestAuthMethods ( t , conn , o . GetPublicId (), 1 )[ 0 ]. GetPublicId ()
newAcct := password . TestAccount ( t , conn , amId , "name1" )
accts = append ( accts , newAcct )
}
2020-09-25 20:44:55 -07:00
2021-04-14 11:34:17 -07:00
databaseWrapper , err := kmsCache . GetWrapper ( context . Background (), o . PublicId , kms . KeyPurposeDatabase )
2021-04-19 13:06:17 -07:00
require . NoError ( t , err )
2021-04-14 11:34:17 -07:00
oidcAm := oidc . TestAuthMethod (
t , conn , databaseWrapper , o . PublicId , oidc . ActivePrivateState ,
"alice-rp" , "fido" ,
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , "https://www.alice.com" )[ 0 ]),
oidc . WithSigningAlgs ( oidc . RS256 ),
oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://www.alice.com/callback" )[ 0 ]),
)
oidcAcct := oidc . TestAccount ( t , conn , oidcAm , "test-subject" )
2023-05-03 09:45:29 -04:00
ldapAm := ldap . TestAuthMethod ( t , conn , databaseWrapper , o . PublicId , [] string { "ldaps://ldap1" })
ldapAcct := ldap . TestAccount ( t , conn , ldapAm , "test-acct" ,
ldap . WithMemberOfGroups ( ctx , "admin" ),
ldap . WithFullName ( ctx , "test-name" ),
ldap . WithEmail ( ctx , "test-email" ),
ldap . WithDn ( ctx , "test-dn" ),
)
2020-09-25 20:44:55 -07:00
addCases := [] struct {
2020-09-28 15:39:10 -04:00
name string
setup func ( * iam . User )
2020-09-25 20:44:55 -07:00
removeAccounts [] string
resultAccounts [] string
2020-09-28 15:39:10 -04:00
wantErr bool
2020-09-25 20:44:55 -07:00
}{
{
2020-09-28 15:39:10 -04:00
name : "Remove account on empty user" ,
setup : func ( * iam . User ) {},
2020-09-25 20:44:55 -07:00
removeAccounts : [] string { accts [ 1 ]. GetPublicId ()},
2020-09-28 15:39:10 -04:00
wantErr : true ,
2020-09-25 20:44:55 -07:00
},
{
name : "Remove 1 of 2 accounts from user" ,
setup : func ( u * iam . User ) {
2020-09-28 15:39:10 -04:00
_ , err := iamRepo . SetUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
2020-09-25 20:44:55 -07:00
[] string { accts [ 0 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
removeAccounts : [] string { accts [ 1 ]. GetPublicId ()},
resultAccounts : [] string { accts [ 0 ]. GetPublicId ()},
},
2021-04-14 11:34:17 -07:00
{
name : "Remove 1 oidc account of 2 accounts from user" ,
setup : func ( u * iam . User ) {
_ , err := iamRepo . SetUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
[] string { accts [ 0 ]. GetPublicId (), oidcAcct . GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
removeAccounts : [] string { oidcAcct . GetPublicId ()},
resultAccounts : [] string { accts [ 0 ]. GetPublicId ()},
},
2020-10-02 16:45:32 -07:00
{
name : "Remove 1 duplicate accounts of 2 accounts from user" ,
setup : func ( u * iam . User ) {
_ , err := iamRepo . SetUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
[] string { accts [ 0 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
removeAccounts : [] string { accts [ 1 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()},
resultAccounts : [] string { accts [ 0 ]. GetPublicId ()},
},
2023-05-03 09:45:29 -04:00
{
name : "Remove 1 ldap account of 3 accounts from user" ,
setup : func ( u * iam . User ) {
_ , err := iamRepo . SetUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
[] string { accts [ 0 ]. GetPublicId (), oidcAcct . GetPublicId (), ldapAcct . GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
removeAccounts : [] string { ldapAcct . GetPublicId ()},
resultAccounts : [] string { accts [ 0 ]. GetPublicId (), oidcAcct . GetPublicId ()},
},
2020-09-25 20:44:55 -07:00
{
name : "Remove all accounts from user" ,
setup : func ( u * iam . User ) {
2020-09-28 15:39:10 -04:00
_ , err := iamRepo . SetUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
2020-09-25 20:44:55 -07:00
[] string { accts [ 0 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
removeAccounts : [] string { accts [ 0 ]. GetPublicId (), accts [ 1 ]. GetPublicId ()},
resultAccounts : [] string {},
},
{
name : "Remove empty on populated user" ,
setup : func ( u * iam . User ) {
2020-09-28 15:39:10 -04:00
_ , err := iamRepo . SetUserAccounts ( context . Background (), u . GetPublicId (), u . GetVersion (),
2020-09-25 20:44:55 -07:00
[] string { accts [ 0 ]. GetPublicId ()})
require . NoError ( t , err )
u . Version = u . Version + 1
},
wantErr : true ,
},
}
for _ , tc := range addCases {
2020-09-28 15:39:10 -04:00
t . Run ( tc . name , func ( t * testing . T ) {
usr := iam . TestUser ( t , iamRepo , o . GetPublicId ())
defer func () {
2021-04-23 09:13:37 -05:00
_ , err := iamRepo . DeleteUser ( context . Background (), usr . GetPublicId ())
require . NoError ( t , err )
2020-09-28 15:39:10 -04:00
}()
tc . setup ( usr )
req := & pbs . RemoveUserAccountsRequest {
Id : usr . GetPublicId (),
Version : usr . GetVersion (),
AccountIds : tc . removeAccounts ,
}
2021-03-25 03:15:43 -04:00
got , err := s . RemoveUserAccounts ( auth . DisabledAuthTestContext ( repoFn , o . GetPublicId ()), req )
2020-09-28 15:39:10 -04:00
if tc . wantErr {
assert . Error ( t , err )
return
}
require . NoError ( t , err , "Got error: %v" , err )
assert . ElementsMatch ( t , got . GetItem (). GetAccountIds (), tc . resultAccounts )
})
2020-09-25 20:44:55 -07:00
}
usr := iam . TestUser ( t , iamRepo , o . GetPublicId ())
failCases := [] struct {
name string
2020-10-02 16:45:32 -07:00
req * pbs . RemoveUserAccountsRequest
2020-09-25 20:44:55 -07:00
err error
}{
{
name : "Bad User Id" ,
2020-10-02 16:45:32 -07:00
req : & pbs . RemoveUserAccountsRequest {
2020-09-25 20:44:55 -07:00
Id : "bad id" ,
Version : usr . GetVersion (),
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2020-10-02 16:45:32 -07:00
{
name : "Bad account Id" ,
req : & pbs . RemoveUserAccountsRequest {
2020-10-06 13:17:28 -04:00
Id : usr . GetPublicId (),
Version : usr . GetVersion (),
2020-10-02 16:45:32 -07:00
AccountIds : [] string { "invalid" },
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2020-09-25 20:44:55 -07:00
}
for _ , tc := range failCases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
2021-03-25 03:15:43 -04:00
_ , gErr := s . RemoveUserAccounts ( auth . DisabledAuthTestContext ( repoFn , usr . GetScopeId ()), tc . req )
2020-09-25 20:44:55 -07:00
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "AddUserAccounts(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
}
})
}
}