package auth_test import ( "context" "strings" "testing" "github.com/hashicorp/boundary/internal/auth" "github.com/hashicorp/boundary/internal/authtoken" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/servers" "github.com/hashicorp/boundary/internal/servers/controller" "github.com/hashicorp/boundary/internal/types/action" "github.com/hashicorp/boundary/internal/types/resource" "github.com/stretchr/testify/require" ) func TestAdditionalVerification(t *testing.T) { tc := controller.NewTestController(t, nil) defer tc.Shutdown() conn := tc.DbConn() client := tc.Client() token := tc.Token() client.SetToken(token.Token) org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId), iam.WithSkipRoleCreation(true)) iamRepoFn := func() (*iam.Repository, error) { return tc.IamRepo(), nil } serversRepoFn := func() (*servers.Repository, error) { return tc.ServersRepo(), nil } authTokenRepoFn := func() (*authtoken.Repository, error) { return tc.AuthTokenRepo(), nil } orgRole := iam.TestRole(t, conn, org.GetPublicId()) iam.TestUserRole(t, conn, orgRole.PublicId, token.UserId) iam.TestRoleGrant(t, conn, orgRole.PublicId, "id=ampw_1234567890;actions=read,list") orgRoleInProj := iam.TestRole(t, conn, org.GetPublicId(), iam.WithGrantScopeId(proj.GetPublicId())) iam.TestUserRole(t, conn, orgRoleInProj.PublicId, token.UserId) iam.TestRoleGrant(t, conn, orgRoleInProj.PublicId, "id=hcst_1234567890;type=host-set;actions=create,update") projRole := iam.TestRole(t, conn, proj.GetPublicId()) iam.TestUserRole(t, conn, projRole.PublicId, token.UserId) iam.TestRoleGrant(t, conn, projRole.PublicId, "id=ttcp_1234567890;actions=authorize") type additionalCase struct { name string opts []auth.Option allowed bool } cases := []struct { name string initialOpts []auth.Option additionalCases []additionalCase }{ { name: "base", initialOpts: []auth.Option{ auth.WithId("hsst_1234567890"), auth.WithAction(action.Create), auth.WithScopeId(proj.PublicId), auth.WithType(resource.HostSet), auth.WithPin("hcst_1234567890"), }, additionalCases: []additionalCase{ { name: "same as base", opts: []auth.Option{ auth.WithId("hsst_1234567890"), auth.WithAction(action.Create), auth.WithScopeId(proj.PublicId), auth.WithType(resource.HostSet), auth.WithPin("hcst_1234567890"), }, allowed: true, }, { name: "no pin off from base", opts: []auth.Option{ auth.WithId("hsst_1234567890"), auth.WithAction(action.Create), auth.WithScopeId(proj.PublicId), auth.WithType(resource.HostSet), }, }, { name: "good target", opts: []auth.Option{ auth.WithId("ttcp_1234567890"), auth.WithAction(action.Authorize), auth.WithScopeId(proj.PublicId), auth.WithType(resource.Target), }, allowed: true, }, { name: "cross scope", opts: []auth.Option{ auth.WithId("ampw_1234567890"), auth.WithAction(action.List), auth.WithScopeId(org.PublicId), auth.WithType(resource.AuthMethod), }, allowed: true, }, { name: "cross scope, bad action", opts: []auth.Option{ auth.WithId("ampw_1234567890"), auth.WithAction(action.Update), auth.WithScopeId(org.PublicId), auth.WithType(resource.AuthMethod), }, }, }, }, } for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { req := require.New(t) ctx := auth.NewVerifierContext( context.Background(), tc.Logger(), iamRepoFn, authTokenRepoFn, serversRepoFn, tc.Kms(), auth.RequestInfo{ PublicId: token.Id, EncryptedToken: strings.Split(token.Token, "_")[2], TokenFormat: auth.AuthTokenTypeBearer, }) res := auth.Verify(ctx, tt.initialOpts...) req.NoError(res.Error) for _, c := range tt.additionalCases { t.Run(c.name, func(t *testing.T) { req = require.New(t) res = res.AdditionalVerification(ctx, c.opts...) if c.allowed { req.NoError(res.Error) } else { req.Error(res.Error) } }) } }) } }