From 393343e55743fe109284288e090b5034e4277716 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Fri, 19 Dec 2025 17:38:44 +0100 Subject: [PATCH] Fix lastSession always return an error Signed-off-by: Bryan Frimin --- pkg/coredata/session.go | 8 +-- pkg/iam/session_service.go | 8 --- pkg/server/api/connect/v1/graphql_handler.go | 4 ++ pkg/server/api/connect/v1/schema.graphql | 1 + pkg/server/api/connect/v1/schema/schema.go | 62 ++++++++++++++++++-- pkg/server/api/connect/v1/types/session.go | 13 ++-- pkg/server/api/connect/v1/types/types.go | 13 ++-- pkg/server/api/connect/v1/v1_resolver.go | 5 ++ 8 files changed, 84 insertions(+), 30 deletions(-) diff --git a/pkg/coredata/session.go b/pkg/coredata/session.go index c08420b2e..f50f7d7c8 100644 --- a/pkg/coredata/session.go +++ b/pkg/coredata/session.go @@ -348,15 +348,15 @@ WHERE rows, err := conn.Query(ctx, q, args) if err != nil { - if err == pgx.ErrNoRows { - return ErrResourceNotFound - } - return fmt.Errorf("cannot query session: %w", err) } session, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Session]) if err != nil { + if err == pgx.ErrNoRows { + return ErrResourceNotFound + } + return fmt.Errorf("cannot collect session: %w", err) } diff --git a/pkg/iam/session_service.go b/pkg/iam/session_service.go index f73abdff1..391d57597 100644 --- a/pkg/iam/session_service.go +++ b/pkg/iam/session_service.go @@ -304,14 +304,6 @@ func (s SessionService) GetActiveSessionForMembership(ctx context.Context, rootS return fmt.Errorf("cannot load child session: %w", err) } - if childSession.ExpireReason != nil { - return NewSessionExpiredError(childSession.ID) - } - - if time.Now().After(childSession.ExpiredAt) { - return NewSessionExpiredError(childSession.ID) - } - return nil }, ) diff --git a/pkg/server/api/connect/v1/graphql_handler.go b/pkg/server/api/connect/v1/graphql_handler.go index f584f8304..f414af89c 100644 --- a/pkg/server/api/connect/v1/graphql_handler.go +++ b/pkg/server/api/connect/v1/graphql_handler.go @@ -81,6 +81,10 @@ func IsViewerDirective(ctx context.Context, obj any, next graphql.Resolver) (any if identity.ID != node.IdentityID { return nil, ErrForbidden } + case *types.Session: + if identity.ID != node.IdentityID { + return nil, ErrForbidden + } default: } diff --git a/pkg/server/api/connect/v1/schema.graphql b/pkg/server/api/connect/v1/schema.graphql index eec602f52..5e862da4e 100644 --- a/pkg/server/api/connect/v1/schema.graphql +++ b/pkg/server/api/connect/v1/schema.graphql @@ -268,6 +268,7 @@ type Invitation implements Node { type Session implements Node { id: ID! + identityId: ID! ipAddress: String! userAgent: String! updatedAt: Datetime! diff --git a/pkg/server/api/connect/v1/schema/schema.go b/pkg/server/api/connect/v1/schema/schema.go index 7a29e577a..5a23e0550 100644 --- a/pkg/server/api/connect/v1/schema/schema.go +++ b/pkg/server/api/connect/v1/schema/schema.go @@ -387,12 +387,13 @@ type ComplexityRoot struct { } Session struct { - CreatedAt func(childComplexity int) int - ExpiresAt func(childComplexity int) int - ID func(childComplexity int) int - IPAddress func(childComplexity int) int - UpdatedAt func(childComplexity int) int - UserAgent func(childComplexity int) int + CreatedAt func(childComplexity int) int + ExpiresAt func(childComplexity int) int + ID func(childComplexity int) int + IPAddress func(childComplexity int) int + IdentityID func(childComplexity int) int + UpdatedAt func(childComplexity int) int + UserAgent func(childComplexity int) int } SessionConnection struct { @@ -1880,6 +1881,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.Session.IPAddress(childComplexity), true + case "Session.identityId": + if e.complexity.Session.IdentityID == nil { + break + } + + return e.complexity.Session.IdentityID(childComplexity), true case "Session.updatedAt": if e.complexity.Session.UpdatedAt == nil { break @@ -2427,6 +2434,7 @@ type Invitation implements Node { type Session implements Node { id: ID! + identityId: ID! ipAddress: String! userAgent: String! updatedAt: Datetime! @@ -6266,6 +6274,8 @@ func (ec *executionContext) fieldContext_Membership_lastSession(_ context.Contex switch field.Name { case "id": return ec.fieldContext_Session_id(ctx, field) + case "identityId": + return ec.fieldContext_Session_identityId(ctx, field) case "ipAddress": return ec.fieldContext_Session_ipAddress(ctx, field) case "userAgent": @@ -8476,6 +8486,8 @@ func (ec *executionContext) fieldContext_OrganizationSessionCreated_session(_ co switch field.Name { case "id": return ec.fieldContext_Session_id(ctx, field) + case "identityId": + return ec.fieldContext_Session_identityId(ctx, field) case "ipAddress": return ec.fieldContext_Session_ipAddress(ctx, field) case "userAgent": @@ -10842,6 +10854,35 @@ func (ec *executionContext) fieldContext_Session_id(_ context.Context, field gra return fc, nil } +func (ec *executionContext) _Session_identityId(ctx context.Context, field graphql.CollectedField, obj *types.Session) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + ec.fieldContext_Session_identityId, + func(ctx context.Context) (any, error) { + return obj.IdentityID, nil + }, + nil, + ec.marshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID, + true, + true, + ) +} + +func (ec *executionContext) fieldContext_Session_identityId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Session", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Session_ipAddress(ctx context.Context, field graphql.CollectedField, obj *types.Session) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -11116,6 +11157,8 @@ func (ec *executionContext) fieldContext_SessionEdge_node(_ context.Context, fie switch field.Name { case "id": return ec.fieldContext_Session_id(ctx, field) + case "identityId": + return ec.fieldContext_Session_identityId(ctx, field) case "ipAddress": return ec.fieldContext_Session_ipAddress(ctx, field) case "userAgent": @@ -11355,6 +11398,8 @@ func (ec *executionContext) fieldContext_SignInPayload_session(_ context.Context switch field.Name { case "id": return ec.fieldContext_Session_id(ctx, field) + case "identityId": + return ec.fieldContext_Session_identityId(ctx, field) case "ipAddress": return ec.fieldContext_Session_ipAddress(ctx, field) case "userAgent": @@ -17539,6 +17584,11 @@ func (ec *executionContext) _Session(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { out.Invalids++ } + case "identityId": + out.Values[i] = ec._Session_identityId(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "ipAddress": out.Values[i] = ec._Session_ipAddress(ctx, field, obj) if out.Values[i] == graphql.Null { diff --git a/pkg/server/api/connect/v1/types/session.go b/pkg/server/api/connect/v1/types/session.go index 2db9b899f..fd90f2aa2 100644 --- a/pkg/server/api/connect/v1/types/session.go +++ b/pkg/server/api/connect/v1/types/session.go @@ -61,11 +61,12 @@ func NewSessionEdge(session *coredata.Session, orderField coredata.SessionOrderF func NewSession(session *coredata.Session) *Session { return &Session{ - ID: session.ID, - IPAddress: session.IPAddress.String(), - UserAgent: session.UserAgent, - UpdatedAt: session.UpdatedAt, - CreatedAt: session.CreatedAt, - ExpiresAt: session.ExpiredAt, + ID: session.ID, + IPAddress: session.IPAddress.String(), + IdentityID: session.UserID, + UserAgent: session.UserAgent, + UpdatedAt: session.UpdatedAt, + CreatedAt: session.CreatedAt, + ExpiresAt: session.ExpiredAt, } } diff --git a/pkg/server/api/connect/v1/types/types.go b/pkg/server/api/connect/v1/types/types.go index b31721ce3..98929c4ec 100644 --- a/pkg/server/api/connect/v1/types/types.go +++ b/pkg/server/api/connect/v1/types/types.go @@ -432,12 +432,13 @@ type SSOAvailability struct { } type Session struct { - ID gid.GID `json:"id"` - IPAddress string `json:"ipAddress"` - UserAgent string `json:"userAgent"` - UpdatedAt time.Time `json:"updatedAt"` - CreatedAt time.Time `json:"createdAt"` - ExpiresAt time.Time `json:"expiresAt"` + ID gid.GID `json:"id"` + IdentityID gid.GID `json:"identityId"` + IPAddress string `json:"ipAddress"` + UserAgent string `json:"userAgent"` + UpdatedAt time.Time `json:"updatedAt"` + CreatedAt time.Time `json:"createdAt"` + ExpiresAt time.Time `json:"expiresAt"` } func (Session) IsNode() {} diff --git a/pkg/server/api/connect/v1/v1_resolver.go b/pkg/server/api/connect/v1/v1_resolver.go index 23bc369b4..4c86cb06a 100644 --- a/pkg/server/api/connect/v1/v1_resolver.go +++ b/pkg/server/api/connect/v1/v1_resolver.go @@ -160,6 +160,11 @@ func (r *membershipResolver) LastSession(ctx context.Context, obj *types.Members childSession, err := r.iam.SessionService.GetActiveSessionForMembership(ctx, session.ID, obj.ID) if err != nil { + var errSessionNotFound *iam.ErrSessionNotFound + if errors.As(err, &errSessionNotFound) { + return nil, nil + } + panic(fmt.Errorf("cannot get active session for membership: %w", err)) }