Skip to content

Commit ab0b88e

Browse files
author
Simon Coffey
committed
Support decimal seconds in cacheDuration parsing
Since the introduction of cacheDuration parsing in 25cbddd we've been seeing parsing failures for one of our IdPs, whose cacheDuration value is set to cacheDuration="PT6H0M0.000S" This is a valid ISO8601 duration, however the regexp being used for parsing doesn't provide for the possibility of milliseconds. The ISO8601 spec[1] supports decimal values for at least some of a duration's components (S4.4.3.2): > If necessary for a particular application, the lowest order > components may have a decimal fraction. It's not entirely plain which components this might refer to, however the xsd:duration spec[2] is plainer: > The numbers may be any unsigned integer, with the exception of the > number of seconds, which may be an unsigned decimal number. This commit therefore adds fractional seconds support to the duration parsing. To ensure that we actually respect these values, I've updated our parsed value coercion to produce floats for all components. This is arguably unnecessary for the non-float components (since the regexp will only accept integers), but it allows us to reduce the code with no ill effects. The ISO spec permits arbitrary decimal precision, and supports both commas and dots as the decimal separator, so since the xsd:duration schema doesn't mention either concern, I've followed the ISO spec here. [1] https://www.loc.gov/standards/datetime/iso-tc154-wg5_n0038_iso_wd_8601-1_2016-02-16.pdf [2] http://www.datypic.com/sc/xsd/t-xsd_duration.html
1 parent f3aa90a commit ab0b88e

File tree

2 files changed

+14
-15
lines changed

2 files changed

+14
-15
lines changed

lib/onelogin/ruby-saml/utils.rb

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ class Utils
1616
DSIG = "http://www.w3.org/2000/09/xmldsig#"
1717
XENC = "http://www.w3.org/2001/04/xmlenc#"
1818
DURATION_FORMAT = %r(^
19-
(-?)P # 1: Duration sign
19+
(-?)P # 1: Duration sign
2020
(?:
21-
(?:(\d+)Y)? # 2: Years
22-
(?:(\d+)M)? # 3: Months
23-
(?:(\d+)D)? # 4: Days
21+
(?:(\d+)Y)? # 2: Years
22+
(?:(\d+)M)? # 3: Months
23+
(?:(\d+)D)? # 4: Days
2424
(?:T
25-
(?:(\d+)H)? # 5: Hours
26-
(?:(\d+)M)? # 6: Minutes
27-
(?:(\d+)S)? # 7: Seconds and optional milliseconds
25+
(?:(\d+)H)? # 5: Hours
26+
(?:(\d+)M)? # 6: Minutes
27+
(?:(\d+(?:[.,]\d+)?)S)? # 7: Seconds
2828
)?
2929
|
30-
(\d+)W # 8: Weeks
30+
(\d+)W # 8: Weeks
3131
)
3232
$)x
3333

@@ -59,13 +59,8 @@ def self.parse_duration(duration, timestamp=Time.now.utc)
5959
raise Exception.new("Invalid ISO 8601 duration")
6060
end
6161

62-
durYears = matches[2].to_i
63-
durMonths = matches[3].to_i
64-
durDays = matches[4].to_i
65-
durHours = matches[5].to_i
66-
durMinutes = matches[6].to_i
67-
durSeconds = matches[7].to_f
68-
durWeeks = matches[8].to_i
62+
durYears, durMonths, durDays, durHours, durMinutes, durSeconds, durWeeks =
63+
matches[2..8].map { |match| match ? match.tr(',', '.').to_f : 0.0 }
6964

7065
if matches[1] == "-"
7166
durYears = -durYears

test/utils_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class UtilsTest < Minitest::Test
1515
# Nominal wraparounds
1616
"P13M" => "1971-02-01T00:00:00.000Z",
1717
"P31D" => "1970-02-01T00:00:00.000Z",
18+
19+
# Decimal seconds
20+
"PT0.5S" => "1970-01-01T00:00:00.500Z",
21+
"PT0,5S" => "1970-01-01T00:00:00.500Z"
1822
}
1923

2024
def result(duration, reference = 0)

0 commit comments

Comments
 (0)