diff --git a/CHANGELOG.md b/CHANGELOG.md index 36d17babd..b410c409c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,11 @@ Canonical reference for changes, improvements, and bugfixes for Boundary. output of the `Authenticate` function returns a map, from which a concrete type can be easily umarshaled (see the updated `authenticate password` command for an example). +* Anonymous scope/auth method listing: When listing auth methods and scopes + without authentication (that is, as the anonymous user `u_anon`), only + information necessary for navigation to an auth method and authenticating to + the auth method is now output. Granting `u_anon` list access to other resource + types will not currently filter any information out. ### New and Improved diff --git a/internal/servers/controller/handlers/authmethods/authmethod_service_test.go b/internal/servers/controller/handlers/authmethods/authmethod_service_test.go index 3259a2373..863d236e1 100644 --- a/internal/servers/controller/handlers/authmethods/authmethod_service_test.go +++ b/internal/servers/controller/handlers/authmethods/authmethod_service_test.go @@ -369,13 +369,8 @@ func TestList(t *testing.T) { // Now check with anonymous user got, gErr = s.ListAuthMethods(auth.DisabledAuthTestContext(iamRepoFn, tc.req.GetScopeId()), tc.req) - if tc.err != nil { - require.Error(gErr) - assert.True(errors.Is(gErr, tc.err), "ListAuthMethods() for scope %q got error %v, wanted %v", tc.req.GetScopeId(), gErr, tc.err) - return - } require.NoError(gErr) - for _, g := range got.Items { + for _, g := range got.GetItems() { assert.Nil(g.Attributes) assert.Nil(g.CreatedTime) assert.Nil(g.UpdatedTime) diff --git a/internal/servers/controller/handlers/scopes/scope_service.go b/internal/servers/controller/handlers/scopes/scope_service.go index 902a8b975..af5ef4cfb 100644 --- a/internal/servers/controller/handlers/scopes/scope_service.go +++ b/internal/servers/controller/handlers/scopes/scope_service.go @@ -155,7 +155,7 @@ func (s Service) ListScopes(ctx context.Context, req *pbs.ListScopesRequest) (*p return &pbs.ListScopesResponse{}, nil } - pl, err := s.listFromRepo(ctx, scopeIds) + pl, err := s.listFromRepo(ctx, scopeIds, authResults.UserId == auth.AnonymousUserId) if err != nil { return nil, err } @@ -402,7 +402,7 @@ func SortScopes(scps []*pb.Scope) { }) } -func (s Service) listFromRepo(ctx context.Context, scopeIds []string) ([]*pb.Scope, error) { +func (s Service) listFromRepo(ctx context.Context, scopeIds []string, anonUser bool) ([]*pb.Scope, error) { repo, err := s.repoFn() if err != nil { return nil, err @@ -414,7 +414,7 @@ func (s Service) listFromRepo(ctx context.Context, scopeIds []string) ([]*pb.Sco var outPl []*pb.Scope for _, scp := range scps { - outPl = append(outPl, ToProto(scp)) + outPl = append(outPl, ToProto(scp, handlers.WithAnonymousListing(anonUser))) } SortScopes(outPl) return outPl, nil @@ -459,14 +459,12 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth. return auth.Verify(ctx, opts...) } -func ToProto(in *iam.Scope) *pb.Scope { +func ToProto(in *iam.Scope, opt ...handlers.Option) *pb.Scope { + anonListing := handlers.GetOpts(opt...).WithAnonymousListing out := pb.Scope{ - Id: in.GetPublicId(), - ScopeId: in.GetParentId(), - CreatedTime: in.GetCreateTime().GetTimestamp(), - UpdatedTime: in.GetUpdateTime().GetTimestamp(), - Version: in.GetVersion(), - Type: in.GetType(), + Id: in.GetPublicId(), + ScopeId: in.GetParentId(), + Type: in.GetType(), } if in.GetDescription() != "" { out.Description = &wrapperspb.StringValue{Value: in.GetDescription()} @@ -477,6 +475,11 @@ func ToProto(in *iam.Scope) *pb.Scope { if in.GetPrimaryAuthMethodId() != "" { out.PrimaryAuthMethodId = &wrapperspb.StringValue{Value: in.GetPrimaryAuthMethodId()} } + if !anonListing { + out.CreatedTime = in.GetCreateTime().GetTimestamp() + out.UpdatedTime = in.GetUpdateTime().GetTimestamp() + out.Version = in.GetVersion() + } return &out } diff --git a/internal/servers/controller/handlers/scopes/scope_service_test.go b/internal/servers/controller/handlers/scopes/scope_service_test.go index ebc5db35c..3e78c86e3 100644 --- a/internal/servers/controller/handlers/scopes/scope_service_test.go +++ b/internal/servers/controller/handlers/scopes/scope_service_test.go @@ -7,7 +7,6 @@ import ( "strings" "testing" - "github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes/wrappers" "github.com/google/go-cmp/cmp" "github.com/hashicorp/boundary/internal/auth" @@ -23,6 +22,7 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/wrapperspb" "github.com/stretchr/testify/assert" @@ -339,12 +339,23 @@ func TestList(t *testing.T) { s, err := scopes.NewService(repoFn) require.NoError(err, "Couldn't create new role service.") - got, gErr := s.ListScopes(auth.DisabledAuthTestContext(repoFn, tc.scopeId), tc.req) + // Test with non-anonymous listing first + got, gErr := s.ListScopes(auth.DisabledAuthTestContext(repoFn, tc.scopeId, auth.WithUserId("u_auth")), tc.req) if tc.err != nil { require.Error(gErr) assert.True(errors.Is(gErr, tc.err), "ListScopes(%+v) got error\n%v, wanted\n%v", tc.req, gErr, tc.err) + return } assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "ListScopes(%q) got response\n%q\nwanted\n%q", tc.req, got, tc.res) + + // Now test with anonymous listing + got, gErr = s.ListScopes(auth.DisabledAuthTestContext(repoFn, tc.scopeId), tc.req) + require.NoError(gErr) + for _, item := range got.GetItems() { + assert.Nil(item.CreatedTime) + assert.Nil(item.UpdatedTime) + assert.Empty(item.Version) + } }) } @@ -441,12 +452,24 @@ func TestList(t *testing.T) { s, err := scopes.NewService(repoFn) require.NoError(err, "Couldn't create new role service.") - got, gErr := s.ListScopes(auth.DisabledAuthTestContext(repoFn, tc.scopeId), tc.req) + // Test with non-anonymous listing first + got, gErr := s.ListScopes(auth.DisabledAuthTestContext(repoFn, tc.scopeId, auth.WithUserId("u_auth")), tc.req) if tc.err != nil { require.Error(gErr) assert.True(errors.Is(gErr, tc.err), "ListScopes(%+v) got error\n%v, wanted\n%v", tc.req, gErr, tc.err) + return } + require.NoError(gErr) assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "ListScopes(%q) got response\n%q, wanted\n%q", tc.req, got, tc.res) + + // Now test with anonymous listing + got, gErr = s.ListScopes(auth.DisabledAuthTestContext(repoFn, tc.scopeId), tc.req) + require.NoError(gErr) + for _, item := range got.GetItems() { + assert.Nil(item.CreatedTime) + assert.Nil(item.UpdatedTime) + assert.Empty(item.Version) + } }) } } @@ -556,8 +579,7 @@ func TestDelete_twice(t *testing.T) { func TestCreate(t *testing.T) { ctx := context.Background() defaultOrg, defaultProj, repoFn := createDefaultScopesAndRepo(t) - defaultProjCreated, err := ptypes.Timestamp(defaultProj.GetCreateTime().GetTimestamp()) - require.NoError(t, err, "Error converting proto to timestamp.") + defaultProjCreated := defaultProj.GetCreateTime().GetTimestamp().AsTime() toMerge := &pbs.CreateScopeRequest{} repo, err := repoFn() @@ -709,7 +731,7 @@ func TestCreate(t *testing.T) { name: "Can't specify Created Time", scopeId: defaultOrg.GetPublicId(), req: &pbs.CreateScopeRequest{Item: &pb.Scope{ - CreatedTime: ptypes.TimestampNow(), + CreatedTime: timestamppb.Now(), }}, res: nil, err: handlers.ApiErrorWithCode(codes.InvalidArgument), @@ -718,7 +740,7 @@ func TestCreate(t *testing.T) { name: "Can't specify Update Time", scopeId: defaultOrg.GetPublicId(), req: &pbs.CreateScopeRequest{Item: &pb.Scope{ - UpdatedTime: ptypes.TimestampNow(), + UpdatedTime: timestamppb.Now(), }}, res: nil, err: handlers.ApiErrorWithCode(codes.InvalidArgument), @@ -768,10 +790,8 @@ func TestCreate(t *testing.T) { default: assert.True(strings.HasPrefix(got.GetItem().GetId(), "p_")) } - gotCreateTime, err := ptypes.Timestamp(got.GetItem().GetCreatedTime()) - require.NoError(err, "Error converting proto to timestamp.") - gotUpdateTime, err := ptypes.Timestamp(got.GetItem().GetUpdatedTime()) - require.NoError(err, "Error converting proto to timestamp.") + gotCreateTime := got.GetItem().GetCreatedTime().AsTime() + gotUpdateTime := got.GetItem().GetUpdatedTime().AsTime() // Verify it is a project created after the test setup's default project assert.True(gotCreateTime.After(defaultProjCreated), "New scope should have been created after default project. Was created %v, which is after %v", gotCreateTime, defaultProjCreated) assert.True(gotUpdateTime.After(defaultProjCreated), "New scope should have been updated after default project. Was updated %v, which is after %v", gotUpdateTime, defaultProjCreated) @@ -856,8 +876,7 @@ func TestUpdate(t *testing.T) { globalVersion = global.Version } - projCreated, err := ptypes.Timestamp(proj.GetCreateTime().GetTimestamp()) - require.NoError(t, err, "Error converting proto to timestamp") + projCreated := proj.GetCreateTime().GetTimestamp().AsTime() projToMerge := &pbs.UpdateScopeRequest{ Id: proj.GetPublicId(), } @@ -1173,7 +1192,7 @@ func TestUpdate(t *testing.T) { Paths: []string{"created_time"}, }, Item: &pb.Scope{ - CreatedTime: ptypes.TimestampNow(), + CreatedTime: timestamppb.Now(), }, }, res: nil, @@ -1187,7 +1206,7 @@ func TestUpdate(t *testing.T) { Paths: []string{"updated_time"}, }, Item: &pb.Scope{ - UpdatedTime: ptypes.TimestampNow(), + UpdatedTime: timestamppb.Now(), }, }, res: nil, @@ -1235,8 +1254,7 @@ func TestUpdate(t *testing.T) { if got != nil { assert.NotNilf(tc.res, "Expected UpdateScope response to be nil, but was %v", got) - gotUpdateTime, err := ptypes.Timestamp(got.GetItem().GetUpdatedTime()) - require.NoError(err, "Error converting proto to timestamp") + gotUpdateTime := got.GetItem().GetUpdatedTime().AsTime() // Verify it is a project updated after it was created assert.True(gotUpdateTime.After(projCreated), "Updated project should have been updated after it's creation. Was updated %v, which is after %v", gotUpdateTime, projCreated)