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"
2021-04-20 20:33:56 -04:00
"sort"
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"
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"
2022-05-09 12:45:10 -07:00
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
"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"
"github.com/hashicorp/boundary/internal/iam"
2021-04-14 11:34:17 -07:00
"github.com/hashicorp/boundary/internal/kms"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/types/scope"
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"
)
2021-04-23 09:13:37 -05:00
var testAuthorizedActions = [] string { "no-op" , "read" , "update" , "delete" , "add-accounts" , "set-accounts" , "remove-accounts" }
2021-04-20 20:33:56 -04:00
func createDefaultUserAndRepo ( t * testing . T , withAccts bool ) ( * iam . User , [] string , func () ( * iam . Repository , error )) {
2020-06-09 11:20:59 -07:00
t . Helper ()
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 )
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
}
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 :
return u , nil , repoFn
default :
require := require . New ( t )
ctx := context . Background ()
kmsCache := kms . TestKms ( t , conn , wrap )
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 )
return u , accts , repoFn
}
2020-06-09 11:20:59 -07:00
}
func TestGet ( t * testing . T ) {
2021-04-20 20:33:56 -04:00
u , uAccts , repoFn := createDefaultUserAndRepo ( t , true )
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
},
{
2020-09-23 08:10:27 -07:00
name : "Get a non existant 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 )
2023-06-06 17:09:08 -04:00
s , err := users . NewService ( context . Background (), repoFn )
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 ) {
2020-07-06 10:15:01 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
2020-07-02 08:17:52 -07:00
wrap := db . TestWrapper ( t )
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
}
repo , err := repoFn ()
2020-09-25 20:44:55 -07:00
require . NoError ( t , err )
2020-07-02 08:17:52 -07:00
2020-08-19 16:47:18 -04:00
oNoUsers , _ := iam . TestScopes ( t , repo )
oWithUsers , _ := iam . TestScopes ( t , repo )
2020-07-02 08:17:52 -07:00
2021-04-20 20:33:56 -04:00
kmsCache := kms . TestKms ( t , conn , wrap )
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 ),
)
iam . TestSetPrimaryAuthMethod ( t , repo , oWithUsers , primaryAm . PublicId )
secondaryAm := password . TestAuthMethods ( t , conn , oWithUsers . PublicId , 1 )
require . Len ( t , secondaryAm , 1 )
2023-06-06 17:09:08 -04:00
s , err := users . NewService ( context . Background (), repoFn )
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
2021-03-25 03:15:43 -04:00
ctx := auth . DisabledAuthTestContext ( repoFn , "global" )
2022-10-28 15:52:06 -04:00
anon , err := s . GetUser ( ctx , & pbs . GetUserRequest { Id : globals . AnonymousUserId })
2021-01-25 19:37:40 -05:00
require . NoError ( t , err )
totalUsers = append ( totalUsers , anon . GetItem ())
2022-10-28 15:52:06 -04:00
authUser , err := s . GetUser ( ctx , & pbs . GetUserRequest { Id : globals . AnyAuthenticatedUserId })
2021-01-25 19:37:40 -05:00
require . NoError ( t , err )
totalUsers = append ( totalUsers , authUser . GetItem ())
2022-10-28 15:52:06 -04:00
recovery , err := s . GetUser ( ctx , & pbs . GetUserRequest { Id : globals . RecoveryUserId })
2021-01-25 19:37:40 -05:00
require . NoError ( t , err )
totalUsers = append ( totalUsers , recovery . GetItem ())
// 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 )
2020-07-02 08:17:52 -07:00
u , err := repo . 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 ))
added , err := repo . AddUserAccounts ( ctx , u . PublicId , u . Version , [] string { oidcAcct . PublicId , pwAcct . PublicId })
require . NoError ( t , err )
require . Len ( t , added , 2 )
u , _ , err = repo . LookupUser ( ctx , u . PublicId )
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
2022-10-28 15:52:06 -04:00
ctx = auth . DisabledAuthTestContext ( repoFn , oWithUsers . GetPublicId (), auth . WithUserId ( globals . AnyAuthenticatedUserId ))
2021-01-25 19:37:40 -05:00
usersInOrg , err := s . ListUsers ( ctx , & pbs . ListUsersRequest { ScopeId : oWithUsers . GetPublicId ()})
require . NoError ( t , err )
totalUsers = append ( totalUsers , usersInOrg . GetItems () ... )
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 ()},
res : & pbs . ListUsersResponse { Items : wantUsers },
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 ()},
res : & pbs . ListUsersResponse {},
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 },
res : & pbs . ListUsersResponse { Items : wantUsers },
},
{
name : "List Recursively in Global" ,
req : & pbs . ListUsersRequest { ScopeId : "global" , Recursive : true },
res : & pbs . ListUsersResponse { Items : totalUsers },
},
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 ())},
res : & pbs . ListUsersResponse { Items : wantUsers },
},
{
name : "Filter To No Users" ,
req : & pbs . ListUsersRequest { ScopeId : oWithUsers . GetPublicId (), Filter : `"/item/id"=="doesntmatch"` },
res : & pbs . ListUsersResponse {},
},
{
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
}
2021-04-20 20:33:56 -04:00
gotUsers := sortableUsers {
users : got . GetItems (),
}
resUsers := sortableUsers {
users : tc . res . GetItems (),
}
if got != nil {
sort . Sort ( gotUsers )
got . Items = gotUsers . users
}
if tc . res != nil {
sort . Sort ( resUsers )
tc . res . Items = resUsers . users
}
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
}),
), "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
})
}
}
2021-04-20 20:33:56 -04:00
type sortableUsers struct {
users [] * pb . User
}
func ( s sortableUsers ) Len () int { return len ( s . users ) }
func ( s sortableUsers ) Less ( i , j int ) bool { return s . users [ i ]. GetId () < s . users [ j ]. GetId () }
func ( s sortableUsers ) Swap ( i , j int ) { s . users [ i ], s . users [ j ] = s . users [ j ], s . users [ i ] }
2020-06-09 11:20:59 -07:00
func TestDelete ( t * testing . T ) {
2021-04-20 20:33:56 -04:00
u , _ , repoFn := createDefaultUserAndRepo ( t , false )
2020-06-09 11:20:59 -07:00
2023-06-06 17:09:08 -04:00
s , err := users . NewService ( context . Background (), repoFn )
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 )
2021-04-20 20:33:56 -04:00
u , _ , repoFn := createDefaultUserAndRepo ( t , false )
2020-06-09 11:20:59 -07:00
2023-06-06 17:09:08 -04:00
s , err := users . NewService ( context . Background (), repoFn )
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 ) {
2021-04-20 20:33:56 -04:00
defaultUser , _ , repoFn := createDefaultUserAndRepo ( t , false )
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 )
2023-06-06 17:09:08 -04:00
s , err := users . NewService ( context . Background (), repoFn )
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 ) {
2021-04-20 20:33:56 -04:00
u , _ , repoFn := createDefaultUserAndRepo ( t , false )
2023-06-06 17:09:08 -04:00
tested , err := users . NewService ( context . Background (), repoFn )
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
},
{
name : "Only non-existant paths in Mask" ,
req : & pbs . UpdateUserRequest {
UpdateMask : & field_mask . FieldMask { Paths : [] string { "nonexistant_field" }},
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 ()
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
}
2023-06-06 17:09:08 -04:00
s , err := users . NewService ( ctx , repoFn )
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 ()
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
}
2023-06-06 17:09:08 -04:00
s , err := users . NewService ( ctx , repoFn )
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 ()
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
}
2023-06-06 17:09:08 -04:00
s , err := users . NewService ( ctx , repoFn )
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 )
}
})
}
}