Skip to content

Commit 2abfb1a

Browse files
committed
Merge remote-tracking branch 'remotes/origin/master' into new-idp-binding-params
2 parents 95cc64a + 018d079 commit 2abfb1a

2 files changed

Lines changed: 60 additions & 20 deletions

File tree

lib/onelogin/ruby-saml/utils.rb

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,21 @@ class Utils
1717
redirect: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect".freeze }.freeze
1818
DSIG = "http://www.w3.org/2000/09/xmldsig#".freeze
1919
XENC = "http://www.w3.org/2001/04/xmlenc#".freeze
20-
DURATION_FORMAT = %r(^(-?)P(?:(?:(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?)|(?:(\d+)W))$).freeze
20+
DURATION_FORMAT = %r(^
21+
(-?)P # 1: Duration sign
22+
(?:
23+
(?:(\d+)Y)? # 2: Years
24+
(?:(\d+)M)? # 3: Months
25+
(?:(\d+)D)? # 4: Days
26+
(?:T
27+
(?:(\d+)H)? # 5: Hours
28+
(?:(\d+)M)? # 6: Minutes
29+
(?:(\d+(?:[.,]\d+)?)S)? # 7: Seconds
30+
)?
31+
|
32+
(\d+)W # 8: Weeks
33+
)
34+
$)x.freeze
2135

2236
# Checks if the x509 cert provided is expired
2337
#
@@ -39,31 +53,18 @@ def self.is_cert_expired(cert)
3953
# current time.
4054
#
4155
# @return [Integer] The new timestamp, after the duration is applied.
42-
#
56+
#
4357
def self.parse_duration(duration, timestamp=Time.now.utc)
4458
matches = duration.match(DURATION_FORMAT)
45-
59+
4660
if matches.nil?
4761
raise Exception.new("Invalid ISO 8601 duration")
4862
end
4963

50-
durYears = matches[2].to_i
51-
durMonths = matches[3].to_i
52-
durDays = matches[4].to_i
53-
durHours = matches[5].to_i
54-
durMinutes = matches[6].to_i
55-
durSeconds = matches[7].to_f
56-
durWeeks = matches[8].to_i
57-
58-
if matches[1] == "-"
59-
durYears = -durYears
60-
durMonths = -durMonths
61-
durDays = -durDays
62-
durHours = -durHours
63-
durMinutes = -durMinutes
64-
durSeconds = -durSeconds
65-
durWeeks = -durWeeks
66-
end
64+
sign = matches[1] == '-' ? -1 : 1
65+
66+
durYears, durMonths, durDays, durHours, durMinutes, durSeconds, durWeeks =
67+
matches[2..8].map { |match| match ? sign * match.tr(',', '.').to_f : 0.0 }
6768

6869
initial_datetime = Time.at(timestamp).utc.to_datetime
6970
final_datetime = initial_datetime.next_year(durYears)

test/utils_test.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,45 @@
11
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
22

33
class UtilsTest < Minitest::Test
4+
describe ".parse_duration" do
5+
DURATIONS_FROM_EPOCH = {
6+
# Basic formats
7+
"P1Y1M1D" => "1971-02-02T00:00:00.000Z",
8+
"PT1H1M1S" => "1970-01-01T01:01:01.000Z",
9+
"P1W" => "1970-01-08T00:00:00.000Z",
10+
"P1Y1M1DT1H1M1S" => "1971-02-02T01:01:01.000Z",
11+
12+
# Negative duration
13+
"-P1Y1M1DT1H1M1S" => "1968-11-29T22:58:59.000Z",
14+
15+
# Nominal wraparounds
16+
"P13M" => "1971-02-01T00:00:00.000Z",
17+
"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"
22+
}
23+
24+
def result(duration, reference = 0)
25+
Time.at(
26+
OneLogin::RubySaml::Utils.parse_duration(duration, reference)
27+
).utc.iso8601(3)
28+
end
29+
30+
DURATIONS_FROM_EPOCH.each do |duration, expected|
31+
it "parses #{duration} to return #{expected} from the given timestamp" do
32+
assert_equal expected, result(duration)
33+
end
34+
end
35+
36+
it "returns the last calendar day of the next month when advancing from a longer month to a shorter one" do
37+
initial_timestamp = Time.iso8601("1970-01-31T00:00:00.000Z").to_i
38+
39+
assert_equal "1970-02-28T00:00:00.000Z", result("P1M", initial_timestamp)
40+
end
41+
end
42+
443
describe ".format_cert" do
544
let(:formatted_certificate) {read_certificate("formatted_certificate")}
645
let(:formatted_chained_certificate) {read_certificate("formatted_chained_certificate")}

0 commit comments

Comments
 (0)