Skip to content

Commit 978ac73

Browse files
committed
Merge pull request #79 from lawrencepit/not_before
Allow for clock drift.
2 parents 805428c + f0ba924 commit 978ac73

File tree

3 files changed

+39
-8
lines changed

3 files changed

+39
-8
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,20 @@ to the IdP settings.
118118
end
119119
```
120120

121+
## Clock Drift
122+
123+
Server clocks tend to drift naturally. If during validation of the response you get the error "Current time is earlier than NotBefore condition" then this may be due to clock differences between your system and that of the Identity Provider.
124+
125+
First, ensure that both systems synchronize their clocks, using for example the industry standard [Network Time Protocol (NTP)](http://en.wikipedia.org/wiki/Network_Time_Protocol).
126+
127+
Even then you may experience intermittent issues though, because the clock of the Identity Provider may drift slightly ahead of your system clocks. To allow for a small amount of clock drift you can initialize the response passing in an option named `:allowed_clock_drift`. Its value must be given in a number (and/or fraction) of seconds. The value given is added to the current time at which the response is validated before it's tested against the `NotBefore` assertion. For example:
128+
129+
```ruby
130+
response = Onelogin::Saml::Response.new(params[:SAMLResponse], :allowed_clock_drift => 1)
131+
```
132+
133+
Make sure to keep the value as comfortably small as possible to keep security risks to a minimum.
134+
121135
## Note on Patches/Pull Requests
122136

123137
* Fork the project.

lib/onelogin/ruby-saml/response.rb

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ def conditions
9292
@conditions ||= xpath_first_from_signed_assertion('/a:Conditions')
9393
end
9494

95+
def not_before
96+
@not_before ||= parse_time(conditions, "NotBefore")
97+
end
98+
99+
def not_on_or_after
100+
@not_on_or_after ||= parse_time(conditions, "NotOnOrAfter")
101+
end
102+
95103
def issuer
96104
@issuer ||= begin
97105
node = REXML::XPath.first(document, "/p:Response/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
@@ -161,16 +169,14 @@ def validate_conditions(soft = true)
161169
return true if conditions.nil?
162170
return true if options[:skip_conditions]
163171

164-
if (not_before = parse_time(conditions, "NotBefore"))
165-
if Time.now.utc < not_before
166-
return soft ? false : validation_error("Current time is earlier than NotBefore condition")
167-
end
172+
now = Time.now.utc
173+
174+
if not_before && (now + (options[:allowed_clock_drift] || 0)) < not_before
175+
return soft ? false : validation_error("Current time is earlier than NotBefore condition")
168176
end
169177

170-
if (not_on_or_after = parse_time(conditions, "NotOnOrAfter"))
171-
if Time.now.utc >= not_on_or_after
172-
return soft ? false : validation_error("Current time is on or after NotOnOrAfter condition")
173-
end
178+
if not_on_or_after && now >= not_on_or_after
179+
return soft ? false : validation_error("Current time is on or after NotOnOrAfter condition")
174180
end
175181

176182
true

test/response_test.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,17 @@ class RubySamlTest < Test::Unit::TestCase
184184
response = Onelogin::Saml::Response.new(response_document_5)
185185
assert response.send(:validate_conditions, true)
186186
end
187+
188+
should "optionally allow for clock drift" do
189+
# The NotBefore condition in the document is 2011-06-14T18:21:01.516Z
190+
Time.stubs(:now).returns(Time.parse("2011-06-14T18:21:01Z"))
191+
response = Onelogin::Saml::Response.new(response_document_5, :allowed_clock_drift => 0.515)
192+
assert !response.send(:validate_conditions, true)
193+
194+
Time.stubs(:now).returns(Time.parse("2011-06-14T18:21:01Z"))
195+
response = Onelogin::Saml::Response.new(response_document_5, :allowed_clock_drift => 0.516)
196+
assert response.send(:validate_conditions, true)
197+
end
187198
end
188199

189200
context "#attributes" do

0 commit comments

Comments
 (0)