rancher/rancher · error
current time %s is before NotBefore %s
Error message
current time %s is before NotBefore %s
What it means
checkAssertionTimeConditions enforces the SAML assertion validity window [NotBefore, NotOnOrAfter) from the IdP response Conditions. This branch fires when Rancher's clock (or the time passed in tests) is strictly before NotBefore, meaning the assertion is not yet valid — almost always clock skew where the IdP's time is ahead of the Rancher server's time, since the IdP typically stamps NotBefore at (or slightly before) its own now.
Source
Thrown at pkg/auth/providers/saml/saml_client.go:702
if err != nil {
return "", fmt.Errorf("could not parse Rancher server URL: %w", err)
}
if parsed.Host != rancherParsed.Host {
return "", fmt.Errorf("redirect URL host %q does not match Rancher host %q", parsed.Host, rancherParsed.Host)
}
return redirectURL, nil
}
// checkAssertionTimeConditions returns an error if now falls outside the
// assertion's [NotBefore, NotOnOrAfter) validity window. A nil or zero-valued
// bound is treated as unbounded on that side.
func checkAssertionTimeConditions(now time.Time, conditions *saml.Conditions) error {
if conditions == nil {
return nil
}
if !conditions.NotBefore.IsZero() && now.Before(conditions.NotBefore) {
return fmt.Errorf("current time %s is before NotBefore %s", now, conditions.NotBefore)
}
if !conditions.NotOnOrAfter.IsZero() && !now.Before(conditions.NotOnOrAfter) {
return fmt.Errorf("current time %s is on or after NotOnOrAfter %s", now, conditions.NotOnOrAfter)
}
return nil
}
// assertionCache tracks recently seen SAML assertion IDs to prevent replay attacks.
type assertionCache struct {
mu sync.Mutex
entries map[string]time.Time // assertion ID -> expiry time
}
func newAssertionCache() *assertionCache {
return &assertionCache{
entries: make(map[string]time.Time),
}View on GitHub (pinned to 932558d4e6)
Solutions
- Synchronize clocks: enable NTP/chrony on both the Rancher server and the IdP host, then confirm with 'date' or 'timedatectl' on each
- Inspect the raw SAML response XML to compare its NotBefore stamp against local time and quantify the skew
- Configure the IdP to apply a notBefore skew margin (e.g. ADFS/ Shibboleak 'notBeforeSkew') that covers observed drift
- Retry the login once clocks are aligned — the fresh assertion will carry updated timestamps
Defensive patterns
Strategy: retry
Try / catch
if err := sp.validateAssertion(now, assertion); err != nil {
if strings.Contains(err.Error(), "before NotBefore") && time.Until(notBefore) < 2*time.Minute {
// Skew window: wait until the assertion becomes valid, then re-validate once
time.Sleep(time.Until(notBefore))
return sp.validateAssertion(time.Now(), assertion)
}
return err
} Prevention
- Run NTP/chrony on Rancher hosts and IdP hosts; alert on drift beyond a few seconds
- Configure a notBefore skew margin on the IdP to absorb residual drift
- Monitor for this error as a clock-health signal, not a SAML problem
When it happens
Trigger: SAML ACS callback processed within the skew window: Rancher clock behind the IdP clock by more than the IdP's not-before skew margin; an IdP that sets NotBefore in the future by policy; tests calling checkAssertionTimeConditions with a fixed now earlier than the fixture's NotBefore.
Common situations: VMs or containers without NTP synchronization; IdP servers with drifted clocks; multi-cluster setups where Rancher and the IdP live on hosts with different time sources; daylight-saving or timezone misconfiguration on the host.
Related errors
- current time %s is on or after NotOnOrAfter %s
- error parsing relay state token: %w
- invalid token
- SAML providers do not implement Authenticate User API
- invalid credentials
AI-assisted analysis of rancher/rancher@932558d4e6 (2026-08-16).
Data as JSON: /api/errors/504c503b39409084.
Report an issue: GitHub.