From 398215b9b126e46eecbdb0e9ae5950b7675712f2 Mon Sep 17 00:00:00 2001 From: Bharat Kathi Date: Thu, 4 Jun 2026 15:50:26 -0700 Subject: [PATCH] fix(saml): emit assertion timestamps in UTC (Zulu) form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The saml pod runs in America/Los_Angeles (ENV TZ from the Dockerfile), so the times we hand crewjam (req.Now for Conditions/IssueInstant, session CreateTime/ExpireTime for AuthnInstant) carried a -07:00 offset. crewjam's xsd:dateTime layout (...Z07:00) renders that offset literally, and strict SPs require the Zulu '...Z' form — samlsp.com rejected the response with 'time data ...-07:00 does not match format ...Z'. Force these times to UTC; crewjam's own TimeNow is already UTC. --- saml/service/identity.go | 8 +++++--- saml/service/response.go | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/saml/service/identity.go b/saml/service/identity.go index 5248bce..82b6481 100644 --- a/saml/service/identity.go +++ b/saml/service/identity.go @@ -68,9 +68,11 @@ func BuildSession(entityID string, clientID string) (*saml.Session, error) { } session := &saml.Session{ - ID: entityID, - CreateTime: time.Now(), - ExpireTime: time.Now().Add(time.Hour), + ID: entityID, + // UTC so the assertion's AuthnInstant/SessionNotOnOrAfter serialize in + // the Zulu form SAML requires (see GenerateResponse). + CreateTime: time.Now().UTC(), + ExpireTime: time.Now().Add(time.Hour).UTC(), Index: entityID, NameID: email, NameIDFormat: string(saml.EmailAddressNameIDFormat), diff --git a/saml/service/response.go b/saml/service/response.go index af7b41f..10072f1 100644 --- a/saml/service/response.go +++ b/saml/service/response.go @@ -46,7 +46,10 @@ func GenerateResponse(requestBuffer []byte, relayState string, entityID string, if err := req.Validate(); err != nil { return ResponseForm{}, err } - req.Now = time.Now() + // UTC: SAML serializes timestamps as xsd:dateTime and crewjam's layout emits + // a zone offset for non-UTC times (e.g. -07:00 under the pod's TZ), which + // strict SPs reject — they require the Zulu "...Z" form. + req.Now = time.Now().UTC() sp, err := ResolveSP(req.Request.Issuer.Value) if err != nil {