From 70bddceda80b5c6f0dc429073991556426735a17 Mon Sep 17 00:00:00 2001 From: KevinRSI <74612067+KevinRSI@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:00:04 +0100 Subject: [PATCH] fix(user fields): missing creationDate in details (#9250) # Which Problems Are Solved The `creationDate` property on user search V2 endpoint was missing # How the Problems Are Solved Added property in v2 `object.proto` and in the function creating the details on each call # Additional Changes - none # Additional Context closes #8552 --------- Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> --- .../idp/v2/integration_test/query_test.go | 4 ++ internal/api/grpc/idp/v2/query.go | 1 + internal/api/grpc/object/v2/converter.go | 3 ++ internal/api/grpc/object/v2beta/converter.go | 3 ++ .../org/v2/integration_test/query_test.go | 41 +++++++++++-------- internal/api/grpc/org/v2/query.go | 1 + internal/api/grpc/settings/v2/settings.go | 7 ++++ internal/api/grpc/settings/v2beta/settings.go | 7 ++++ .../user/v2/integration_test/query_test.go | 6 +++ internal/api/grpc/user/v2/passkey_test.go | 16 ++++++++ internal/api/grpc/user/v2/query.go | 2 + internal/api/grpc/user/v2/u2f_test.go | 6 +++ internal/api/grpc/user/v2beta/passkey_test.go | 16 ++++++++ internal/api/grpc/user/v2beta/u2f_test.go | 6 +++ internal/integration/assert.go | 7 ++++ proto/zitadel/object/v2/object.proto | 2 + proto/zitadel/object/v2beta/object.proto | 2 + 17 files changed, 113 insertions(+), 17 deletions(-) diff --git a/internal/api/grpc/idp/v2/integration_test/query_test.go b/internal/api/grpc/idp/v2/integration_test/query_test.go index 7bfa286b5e..2c4be8a73b 100644 --- a/internal/api/grpc/idp/v2/integration_test/query_test.go +++ b/internal/api/grpc/idp/v2/integration_test/query_test.go @@ -76,6 +76,7 @@ func TestServer_GetIDPByID(t *testing.T) { name, &object.Details{ Sequence: resp.Details.Sequence, + CreationDate: resp.Details.CreationDate, ChangeDate: resp.Details.ChangeDate, ResourceOwner: resp.Details.ResourceOwner, }} @@ -124,6 +125,7 @@ func TestServer_GetIDPByID(t *testing.T) { name, &object.Details{ Sequence: resp.Details.Sequence, + CreationDate: resp.Details.CreationDate, ChangeDate: resp.Details.ChangeDate, ResourceOwner: resp.Details.ResourceOwner, }} @@ -145,6 +147,7 @@ func TestServer_GetIDPByID(t *testing.T) { name, &object.Details{ Sequence: resp.Details.Sequence, + CreationDate: resp.Details.CreationDate, ChangeDate: resp.Details.ChangeDate, ResourceOwner: resp.Details.ResourceOwner, }} @@ -193,6 +196,7 @@ func TestServer_GetIDPByID(t *testing.T) { name, &object.Details{ Sequence: resp.Details.Sequence, + CreationDate: resp.Details.CreationDate, ChangeDate: resp.Details.ChangeDate, ResourceOwner: resp.Details.ResourceOwner, }} diff --git a/internal/api/grpc/idp/v2/query.go b/internal/api/grpc/idp/v2/query.go index e53d54eee7..de78775804 100644 --- a/internal/api/grpc/idp/v2/query.go +++ b/internal/api/grpc/idp/v2/query.go @@ -31,6 +31,7 @@ func idpToPb(idp *query.IDPTemplate) *idp_pb.IDP { Sequence: idp.Sequence, EventDate: idp.ChangeDate, ResourceOwner: idp.ResourceOwner, + CreationDate: idp.CreationDate, }), State: idpStateToPb(idp.State), Name: idp.Name, diff --git a/internal/api/grpc/object/v2/converter.go b/internal/api/grpc/object/v2/converter.go index 8cf0d8b1fa..753b9db095 100644 --- a/internal/api/grpc/object/v2/converter.go +++ b/internal/api/grpc/object/v2/converter.go @@ -20,6 +20,9 @@ func DomainToDetailsPb(objectDetail *domain.ObjectDetails) *object.Details { if !objectDetail.EventDate.IsZero() { details.ChangeDate = timestamppb.New(objectDetail.EventDate) } + if !objectDetail.CreationDate.IsZero() { + details.CreationDate = timestamppb.New(objectDetail.CreationDate) + } return details } diff --git a/internal/api/grpc/object/v2beta/converter.go b/internal/api/grpc/object/v2beta/converter.go index cc7e02c7fe..9b14bb677a 100644 --- a/internal/api/grpc/object/v2beta/converter.go +++ b/internal/api/grpc/object/v2beta/converter.go @@ -19,6 +19,9 @@ func DomainToDetailsPb(objectDetail *domain.ObjectDetails) *object.Details { if !objectDetail.EventDate.IsZero() { details.ChangeDate = timestamppb.New(objectDetail.EventDate) } + if !objectDetail.CreationDate.IsZero() { + details.CreationDate = timestamppb.New(objectDetail.CreationDate) + } return details } diff --git a/internal/api/grpc/org/v2/integration_test/query_test.go b/internal/api/grpc/org/v2/integration_test/query_test.go index 188aeddf9f..86a2bd312b 100644 --- a/internal/api/grpc/org/v2/integration_test/query_test.go +++ b/internal/api/grpc/org/v2/integration_test/query_test.go @@ -26,6 +26,16 @@ type orgAttr struct { Details *object.Details } +func createOrganization(ctx context.Context, name string) orgAttr { + orgResp := Instance.CreateOrganization(ctx, name, gofakeit.Email()) + orgResp.Details.CreationDate = orgResp.Details.ChangeDate + return orgAttr{ + ID: orgResp.GetOrganizationId(), + Name: name, + Details: orgResp.GetDetails(), + } +} + func TestServer_ListOrganizations(t *testing.T) { type args struct { ctx context.Context @@ -63,6 +73,7 @@ func TestServer_ListOrganizations(t *testing.T) { State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE, Details: &object.Details{ Sequence: Instance.DefaultOrg.Details.Sequence, + CreationDate: Instance.DefaultOrg.Details.CreationDate, ChangeDate: Instance.DefaultOrg.Details.ChangeDate, ResourceOwner: Instance.DefaultOrg.Details.ResourceOwner, }, @@ -85,12 +96,7 @@ func TestServer_ListOrganizations(t *testing.T) { prefix := fmt.Sprintf("ListOrgs-%s", gofakeit.AppName()) for i := 0; i < count; i++ { name := prefix + strconv.Itoa(i) - orgResp := Instance.CreateOrganization(ctx, name, gofakeit.Email()) - orgs[i] = orgAttr{ - ID: orgResp.GetOrganizationId(), - Name: name, - Details: orgResp.GetDetails(), - } + orgs[i] = createOrganization(ctx, name) } request.Queries = []*org.SearchQuery{ OrganizationNamePrefixQuery(prefix), @@ -140,6 +146,7 @@ func TestServer_ListOrganizations(t *testing.T) { Name: Instance.DefaultOrg.Name, Details: &object.Details{ Sequence: Instance.DefaultOrg.Details.Sequence, + CreationDate: Instance.DefaultOrg.Details.CreationDate, ChangeDate: Instance.DefaultOrg.Details.ChangeDate, ResourceOwner: Instance.DefaultOrg.Details.ResourceOwner, }, @@ -172,6 +179,7 @@ func TestServer_ListOrganizations(t *testing.T) { Name: Instance.DefaultOrg.Name, Details: &object.Details{ Sequence: Instance.DefaultOrg.Details.Sequence, + CreationDate: Instance.DefaultOrg.Details.CreationDate, ChangeDate: Instance.DefaultOrg.Details.ChangeDate, ResourceOwner: Instance.DefaultOrg.Details.ResourceOwner, }, @@ -204,6 +212,7 @@ func TestServer_ListOrganizations(t *testing.T) { Name: Instance.DefaultOrg.Name, Details: &object.Details{ Sequence: Instance.DefaultOrg.Details.Sequence, + CreationDate: Instance.DefaultOrg.Details.CreationDate, ChangeDate: Instance.DefaultOrg.Details.ChangeDate, ResourceOwner: Instance.DefaultOrg.Details.ResourceOwner, }, @@ -221,14 +230,9 @@ func TestServer_ListOrganizations(t *testing.T) { func(ctx context.Context, request *org.ListOrganizationsRequest) ([]orgAttr, error) { orgs := make([]orgAttr, 1) name := fmt.Sprintf("ListOrgs-%s", gofakeit.AppName()) - orgResp := Instance.CreateOrganization(ctx, name, gofakeit.Email()) - orgs[0] = orgAttr{ - ID: orgResp.GetOrganizationId(), - Name: name, - Details: orgResp.GetDetails(), - } + orgs[0] = createOrganization(ctx, name) domain := gofakeit.DomainName() - _, err := Instance.Client.Mgmt.AddOrgDomain(integration.SetOrgID(ctx, orgResp.GetOrganizationId()), &management.AddOrgDomainRequest{ + _, err := Instance.Client.Mgmt.AddOrgDomain(integration.SetOrgID(ctx, orgs[0].ID), &management.AddOrgDomainRequest{ Domain: domain, }) if err != nil { @@ -262,18 +266,19 @@ func TestServer_ListOrganizations(t *testing.T) { }, func(ctx context.Context, request *org.ListOrganizationsRequest) ([]orgAttr, error) { name := gofakeit.Name() - orgResp := Instance.CreateOrganization(ctx, name, gofakeit.Email()) - deactivateOrgResp := Instance.DeactivateOrganization(ctx, orgResp.GetOrganizationId()) + orgResp := createOrganization(ctx, name) + deactivateOrgResp := Instance.DeactivateOrganization(ctx, orgResp.ID) request.Queries = []*org.SearchQuery{ - OrganizationIdQuery(orgResp.GetOrganizationId()), + OrganizationIdQuery(orgResp.ID), OrganizationStateQuery(org.OrganizationState_ORGANIZATION_STATE_INACTIVE), } return []orgAttr{{ - ID: orgResp.GetOrganizationId(), + ID: orgResp.ID, Name: name, Details: &object.Details{ ResourceOwner: deactivateOrgResp.GetDetails().GetResourceOwner(), Sequence: deactivateOrgResp.GetDetails().GetSequence(), + CreationDate: orgResp.Details.GetCreationDate(), ChangeDate: deactivateOrgResp.GetDetails().GetChangeDate(), }, }}, nil @@ -317,6 +322,7 @@ func TestServer_ListOrganizations(t *testing.T) { Name: Instance.DefaultOrg.Name, Details: &object.Details{ Sequence: Instance.DefaultOrg.Details.Sequence, + CreationDate: Instance.DefaultOrg.Details.ChangeDate, ChangeDate: Instance.DefaultOrg.Details.ChangeDate, ResourceOwner: Instance.DefaultOrg.Details.ResourceOwner, }, @@ -414,6 +420,7 @@ func TestServer_ListOrganizations(t *testing.T) { Name: Instance.DefaultOrg.Name, Details: &object.Details{ Sequence: Instance.DefaultOrg.Details.Sequence, + CreationDate: Instance.DefaultOrg.Details.ChangeDate, ChangeDate: Instance.DefaultOrg.Details.ChangeDate, ResourceOwner: Instance.DefaultOrg.Details.ResourceOwner, }, diff --git a/internal/api/grpc/org/v2/query.go b/internal/api/grpc/org/v2/query.go index f07fb71d20..27f279d40e 100644 --- a/internal/api/grpc/org/v2/query.go +++ b/internal/api/grpc/org/v2/query.go @@ -129,6 +129,7 @@ func organizationToPb(organization *query.Org) *org.Organization { Sequence: organization.Sequence, EventDate: organization.ChangeDate, ResourceOwner: organization.ResourceOwner, + CreationDate: organization.CreationDate, }), State: orgStateToPb(organization.State), } diff --git a/internal/api/grpc/settings/v2/settings.go b/internal/api/grpc/settings/v2/settings.go index 8b9ab9b845..77874bf970 100644 --- a/internal/api/grpc/settings/v2/settings.go +++ b/internal/api/grpc/settings/v2/settings.go @@ -23,6 +23,7 @@ func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSet Settings: loginSettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.OrgID, }, @@ -38,6 +39,7 @@ func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *setting Settings: passwordComplexitySettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -53,6 +55,7 @@ func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.Ge Settings: passwordExpirySettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -68,6 +71,7 @@ func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrand Settings: brandingSettingsToPb(current, s.assetsAPIDomain(ctx)), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -83,6 +87,7 @@ func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainS Settings: domainSettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -98,6 +103,7 @@ func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.G Settings: legalAndSupportSettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -113,6 +119,7 @@ func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockou Settings: lockoutSettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, diff --git a/internal/api/grpc/settings/v2beta/settings.go b/internal/api/grpc/settings/v2beta/settings.go index 677d8f1c15..6193f129ba 100644 --- a/internal/api/grpc/settings/v2beta/settings.go +++ b/internal/api/grpc/settings/v2beta/settings.go @@ -23,6 +23,7 @@ func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSet Settings: loginSettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.OrgID, }, @@ -38,6 +39,7 @@ func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *setting Settings: passwordComplexitySettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -53,6 +55,7 @@ func (s *Server) GetPasswordExpirySettings(ctx context.Context, req *settings.Ge Settings: passwordExpirySettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -68,6 +71,7 @@ func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrand Settings: brandingSettingsToPb(current, s.assetsAPIDomain(ctx)), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -83,6 +87,7 @@ func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainS Settings: domainSettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -98,6 +103,7 @@ func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.G Settings: legalAndSupportSettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, @@ -113,6 +119,7 @@ func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockou Settings: lockoutSettingsToPb(current), Details: &object_pb.Details{ Sequence: current.Sequence, + CreationDate: timestamppb.New(current.CreationDate), ChangeDate: timestamppb.New(current.ChangeDate), ResourceOwner: current.ResourceOwner, }, diff --git a/internal/api/grpc/user/v2/integration_test/query_test.go b/internal/api/grpc/user/v2/integration_test/query_test.go index bbf8c24865..554de2b69a 100644 --- a/internal/api/grpc/user/v2/integration_test/query_test.go +++ b/internal/api/grpc/user/v2/integration_test/query_test.go @@ -150,6 +150,7 @@ func TestServer_GetUserByID(t *testing.T) { }, Details: &object.Details{ ChangeDate: timestamppb.Now(), + CreationDate: timestamppb.Now(), ResourceOwner: orgResp.OrganizationId, }, }, @@ -195,6 +196,7 @@ func TestServer_GetUserByID(t *testing.T) { }, Details: &object.Details{ ChangeDate: timestamppb.Now(), + CreationDate: timestamppb.Now(), ResourceOwner: orgResp.OrganizationId, }, }, @@ -282,6 +284,7 @@ func TestServer_GetUserByID_Permission(t *testing.T) { }, Details: &object.Details{ ChangeDate: timestamppb.Now(), + CreationDate: timestamppb.Now(), ResourceOwner: newOrg.GetOrganizationId(), }, }, @@ -320,6 +323,7 @@ func TestServer_GetUserByID_Permission(t *testing.T) { }, Details: &object.Details{ ChangeDate: timestamppb.Now(), + CreationDate: timestamppb.Now(), ResourceOwner: newOrg.GetOrganizationId(), }, }, @@ -415,6 +419,8 @@ func createUser(ctx context.Context, orgID string, passwordChangeRequired bool) phone := "+41" + gofakeit.Phone() resp := Instance.CreateHumanUserVerified(ctx, orgID, username, phone) info := userAttr{resp.GetUserId(), username, phone, nil, resp.GetDetails()} + // as the change date of the creation is the creation date + resp.Details.CreationDate = resp.GetDetails().GetChangeDate() if passwordChangeRequired { details := Instance.SetUserPassword(ctx, resp.GetUserId(), integration.UserPassword, true) info.Changed = details.GetChangeDate() diff --git a/internal/api/grpc/user/v2/passkey_test.go b/internal/api/grpc/user/v2/passkey_test.go index 7facfc74e0..9263012b98 100644 --- a/internal/api/grpc/user/v2/passkey_test.go +++ b/internal/api/grpc/user/v2/passkey_test.go @@ -74,6 +74,7 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, ID: "123", @@ -90,6 +91,7 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, ID: "123", @@ -104,6 +106,10 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) { Seconds: 3000, Nanos: 22, }, + CreationDate: ×tamppb.Timestamp{ + Seconds: 3000, + Nanos: 22, + }, ResourceOwner: "me", }, PasskeyId: "123", @@ -150,6 +156,7 @@ func Test_passkeyDetailsToPb(t *testing.T) { details: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, err: nil, @@ -161,6 +168,10 @@ func Test_passkeyDetailsToPb(t *testing.T) { Seconds: 3000, Nanos: 22, }, + CreationDate: ×tamppb.Timestamp{ + Seconds: 3000, + Nanos: 22, + }, ResourceOwner: "me", }, }, @@ -199,6 +210,7 @@ func Test_passkeyCodeDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, CodeID: "123", @@ -213,6 +225,10 @@ func Test_passkeyCodeDetailsToPb(t *testing.T) { Seconds: 3000, Nanos: 22, }, + CreationDate: ×tamppb.Timestamp{ + Seconds: 3000, + Nanos: 22, + }, ResourceOwner: "me", }, Code: &user.PasskeyRegistrationCode{ diff --git a/internal/api/grpc/user/v2/query.go b/internal/api/grpc/user/v2/query.go index aec5367ded..23d4b4422c 100644 --- a/internal/api/grpc/user/v2/query.go +++ b/internal/api/grpc/user/v2/query.go @@ -21,6 +21,7 @@ func (s *Server) GetUserByID(ctx context.Context, req *user.GetUserByIDRequest) return &user.GetUserByIDResponse{ Details: object.DomainToDetailsPb(&domain.ObjectDetails{ Sequence: resp.Sequence, + CreationDate: resp.CreationDate, EventDate: resp.ChangeDate, ResourceOwner: resp.ResourceOwner, }), @@ -58,6 +59,7 @@ func userToPb(userQ *query.User, assetPrefix string) *user.User { Sequence: userQ.Sequence, EventDate: userQ.ChangeDate, ResourceOwner: userQ.ResourceOwner, + CreationDate: userQ.CreationDate, }), State: userStateToPb(userQ.State), Username: userQ.Username, diff --git a/internal/api/grpc/user/v2/u2f_test.go b/internal/api/grpc/user/v2/u2f_test.go index 73366ab29b..fae3ba1cdb 100644 --- a/internal/api/grpc/user/v2/u2f_test.go +++ b/internal/api/grpc/user/v2/u2f_test.go @@ -43,6 +43,7 @@ func Test_u2fRegistrationDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, ID: "123", @@ -59,6 +60,7 @@ func Test_u2fRegistrationDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, ID: "123", @@ -73,6 +75,10 @@ func Test_u2fRegistrationDetailsToPb(t *testing.T) { Seconds: 3000, Nanos: 22, }, + CreationDate: ×tamppb.Timestamp{ + Seconds: 3000, + Nanos: 22, + }, ResourceOwner: "me", }, U2FId: "123", diff --git a/internal/api/grpc/user/v2beta/passkey_test.go b/internal/api/grpc/user/v2beta/passkey_test.go index 7d45c41756..f4a48ed941 100644 --- a/internal/api/grpc/user/v2beta/passkey_test.go +++ b/internal/api/grpc/user/v2beta/passkey_test.go @@ -74,6 +74,7 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, ID: "123", @@ -90,6 +91,7 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, ID: "123", @@ -100,6 +102,10 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) { want: &user.RegisterPasskeyResponse{ Details: &object.Details{ Sequence: 22, + CreationDate: ×tamppb.Timestamp{ + Seconds: 3000, + Nanos: 22, + }, ChangeDate: ×tamppb.Timestamp{ Seconds: 3000, Nanos: 22, @@ -150,6 +156,7 @@ func Test_passkeyDetailsToPb(t *testing.T) { details: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, err: nil, @@ -157,6 +164,10 @@ func Test_passkeyDetailsToPb(t *testing.T) { want: &user.CreatePasskeyRegistrationLinkResponse{ Details: &object.Details{ Sequence: 22, + CreationDate: ×tamppb.Timestamp{ + Seconds: 3000, + Nanos: 22, + }, ChangeDate: ×tamppb.Timestamp{ Seconds: 3000, Nanos: 22, @@ -199,6 +210,7 @@ func Test_passkeyCodeDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, CodeID: "123", @@ -209,6 +221,10 @@ func Test_passkeyCodeDetailsToPb(t *testing.T) { want: &user.CreatePasskeyRegistrationLinkResponse{ Details: &object.Details{ Sequence: 22, + CreationDate: ×tamppb.Timestamp{ + Seconds: 3000, + Nanos: 22, + }, ChangeDate: ×tamppb.Timestamp{ Seconds: 3000, Nanos: 22, diff --git a/internal/api/grpc/user/v2beta/u2f_test.go b/internal/api/grpc/user/v2beta/u2f_test.go index 087837ce3c..53f2a0bb8c 100644 --- a/internal/api/grpc/user/v2beta/u2f_test.go +++ b/internal/api/grpc/user/v2beta/u2f_test.go @@ -43,6 +43,7 @@ func Test_u2fRegistrationDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, ID: "123", @@ -59,6 +60,7 @@ func Test_u2fRegistrationDetailsToPb(t *testing.T) { ObjectDetails: &domain.ObjectDetails{ Sequence: 22, EventDate: time.Unix(3000, 22), + CreationDate: time.Unix(3000, 22), ResourceOwner: "me", }, ID: "123", @@ -69,6 +71,10 @@ func Test_u2fRegistrationDetailsToPb(t *testing.T) { want: &user.RegisterU2FResponse{ Details: &object.Details{ Sequence: 22, + CreationDate: ×tamppb.Timestamp{ + Seconds: 3000, + Nanos: 22, + }, ChangeDate: ×tamppb.Timestamp{ Seconds: 3000, Nanos: 22, diff --git a/internal/integration/assert.go b/internal/integration/assert.go index 77d7558b55..22432a3a84 100644 --- a/internal/integration/assert.go +++ b/internal/integration/assert.go @@ -19,6 +19,7 @@ import ( type Details interface { comparable GetSequence() uint64 + GetCreationDate() *timestamppb.Timestamp GetChangeDate() *timestamppb.Timestamp GetResourceOwner() string } @@ -62,6 +63,12 @@ func AssertDetails[D Details, M DetailsMsg[D]](t assert.TestingT, expected, actu assert.NotZero(t, gotDetails.GetSequence()) + if wantDetails.GetCreationDate() != nil { + wantCreationDate := time.Now() + gotCreationDate := gotDetails.GetCreationDate().AsTime() + assert.WithinRange(t, gotCreationDate, wantCreationDate.Add(-time.Minute), wantCreationDate.Add(time.Minute)) + } + if wantDetails.GetChangeDate() != nil { wantChangeDate := time.Now() gotChangeDate := gotDetails.GetChangeDate().AsTime() diff --git a/proto/zitadel/object/v2/object.proto b/proto/zitadel/object/v2/object.proto index 5a63ece19b..339966d3b2 100644 --- a/proto/zitadel/object/v2/object.proto +++ b/proto/zitadel/object/v2/object.proto @@ -78,6 +78,8 @@ message Details { example: "\"69629023906488334\""; } ]; + //creation_date is the timestamp where the first operation on the object was made + google.protobuf.Timestamp creation_date = 4; } message ListDetails { diff --git a/proto/zitadel/object/v2beta/object.proto b/proto/zitadel/object/v2beta/object.proto index df8e77319a..fd3190ccd6 100644 --- a/proto/zitadel/object/v2beta/object.proto +++ b/proto/zitadel/object/v2beta/object.proto @@ -78,6 +78,8 @@ message Details { example: "\"69629023906488334\""; } ]; + //creation_date is the timestamp where the first operation on the object was made + google.protobuf.Timestamp creation_date = 4; } message ListDetails {