saml2 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/saml2/assertion.rb +5 -1
- data/lib/saml2/conditions.rb +74 -0
- data/lib/saml2/response.rb +4 -0
- data/lib/saml2/version.rb +1 -1
- data/spec/fixtures/response_signed.xml +8 -8
- data/spec/fixtures/response_with_attribute_signed.xml +8 -8
- data/spec/lib/conditions_spec.rb +69 -0
- data/spec/lib/response_spec.rb +2 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 314105963831ad59d852c507bdd5a6d5e9144735
|
4
|
+
data.tar.gz: 6b913cac8cf8b4df318e3896a11f1ef583325a36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8483963f3dde271d6a61dbfb812a1a91dc5054296eac2aa69369f6148b228b1283031fac1dc17e6131fecbd97ceade0e2a826a50b49a22a15b0dab47e83e4ea
|
7
|
+
data.tar.gz: 0602173e8d090329e2d9b950affde276c20e409914c99f7a0ddae878b25352682fa33b0538269897865fc765de668016036e104e4c8f2727f9fc7187f365a118
|
data/lib/saml2/assertion.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
require 'saml2/conditions'
|
2
|
+
|
1
3
|
module SAML2
|
2
4
|
class Assertion
|
3
|
-
attr_reader :id, :issue_instant, :statements
|
5
|
+
attr_reader :id, :issue_instant, :conditions, :statements
|
4
6
|
attr_accessor :issuer, :subject
|
5
7
|
|
6
8
|
def initialize
|
7
9
|
@id = "_#{SecureRandom.uuid}"
|
8
10
|
@issue_instant = Time.now.utc
|
9
11
|
@statements = []
|
12
|
+
@conditions = Conditions.new
|
10
13
|
end
|
11
14
|
|
12
15
|
def sign(x509_certificate, private_key, algorithm_name = :sha256)
|
@@ -33,6 +36,7 @@ module SAML2
|
|
33
36
|
|
34
37
|
subject.build(builder)
|
35
38
|
|
39
|
+
conditions.build(builder)
|
36
40
|
statements.each { |stmt| stmt.build(builder) }
|
37
41
|
end
|
38
42
|
end.doc.root
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module SAML2
|
2
|
+
class Conditions < Array
|
3
|
+
attr_accessor :not_before, :not_on_or_after
|
4
|
+
|
5
|
+
def valid?(options = {})
|
6
|
+
now = options[:now] || Time.now
|
7
|
+
return :invalid if not_before && now < not_before
|
8
|
+
return :invalid if not_on_or_after && now >= not_on_or_after
|
9
|
+
|
10
|
+
result = :valid
|
11
|
+
each do |condition|
|
12
|
+
this_result = condition.valid?(options)
|
13
|
+
case this_result
|
14
|
+
when :invalid
|
15
|
+
return :invalid
|
16
|
+
when :indeterminate
|
17
|
+
result = :indeterminate
|
18
|
+
when :valid
|
19
|
+
else
|
20
|
+
raise "unknown validity of #{condition}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def build(builder)
|
27
|
+
builder['saml'].Conditions do |builder|
|
28
|
+
builder.parent['NotBefore'] = not_before.iso8601 if not_before
|
29
|
+
builder.parent['NotOnOrAfter'] = not_on_or_after.iso8601 if not_on_or_after
|
30
|
+
|
31
|
+
each do |condition|
|
32
|
+
condition.build(builder)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Any unknown condition
|
38
|
+
class Condition
|
39
|
+
def valid?(_)
|
40
|
+
:indeterminate
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class AudienceRestriction < Condition
|
45
|
+
attr_accessor :audience
|
46
|
+
|
47
|
+
def initialize(audience)
|
48
|
+
@audience = audience
|
49
|
+
end
|
50
|
+
|
51
|
+
def valid?(options)
|
52
|
+
Array(audience).include?(options[:audience]) ? :valid : :invalid
|
53
|
+
end
|
54
|
+
|
55
|
+
def build(builder)
|
56
|
+
builder['saml'].AudienceRestriction do |builder|
|
57
|
+
Array(audience).each do |single_audience|
|
58
|
+
builder['saml'].Audience(single_audience)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class OneTimeUse < Condition
|
65
|
+
def valid?(_)
|
66
|
+
:valid
|
67
|
+
end
|
68
|
+
|
69
|
+
def build(builder)
|
70
|
+
builder['saml'].OneTimeUse
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/saml2/response.rb
CHANGED
@@ -27,6 +27,8 @@ module SAML2
|
|
27
27
|
statement = authn_request.attribute_consuming_service.create_statement(attributes)
|
28
28
|
response.assertions.first.statements << statement if statement
|
29
29
|
end
|
30
|
+
response.assertions.first.conditions << Conditions::AudienceRestriction.new(authn_request.issuer.id)
|
31
|
+
|
30
32
|
response
|
31
33
|
end
|
32
34
|
|
@@ -42,6 +44,8 @@ module SAML2
|
|
42
44
|
assertion.subject.confirmation.not_on_or_after = Time.now.utc + 30
|
43
45
|
assertion.subject.confirmation.recipient = response.destination if response.destination
|
44
46
|
assertion.issuer = issuer
|
47
|
+
assertion.conditions.not_before = Time.now.utc - 5
|
48
|
+
assertion.conditions.not_on_or_after = Time.now.utc + 30
|
45
49
|
authn_statement = AuthnStatement.new
|
46
50
|
authn_statement.authn_instant = response.issue_instant
|
47
51
|
authn_statement.authn_context_class_ref = AuthnStatement::Classes::UNSPECIFIED
|
data/lib/saml2/version.rb
CHANGED
@@ -9,15 +9,15 @@
|
|
9
9
|
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
10
10
|
</Transforms>
|
11
11
|
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
12
|
-
<DigestValue>
|
12
|
+
<DigestValue>HFJ1RMKtE+J23K/mQqdClLWsdjwboU9M+uTX+PcN/LU=</DigestValue>
|
13
13
|
</Reference>
|
14
14
|
</SignedInfo>
|
15
|
-
<SignatureValue>
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
<SignatureValue>oRUU3idevSgM2QCidYqLAL5Ki2H8qxvkIVw9yNrbv9Mg2D7126wPMerWyKeP+ops
|
16
|
+
6ploHMV0MQRyEFA+4PJ3ZsBU1daVSt3plh+6Szm5zIhWUEc3HhvQirv5IP1lfcxQ
|
17
|
+
IopKnpiZkH9QMLolCLMIfCbOIuIfmssmsEagU/S3aoRVgZLA/x15z2hNEiB+tMqr
|
18
|
+
Elc7i5V81ztnEx47yJhf/mAiZcnLqpnbpJ9XN4NF43QSgkRNU4vCQsx0zA6gj9MB
|
19
|
+
D5h/CKy7KMn+LtaLkHIfv6Y//xN+61PrQ7sr5FIsCGg9XBvXC3PrwEVdADx4/dZO
|
20
|
+
JrJ/DBFeEc8K1KSMXm5qrQ==</SignatureValue>
|
21
21
|
<KeyInfo>
|
22
22
|
<X509Data>
|
23
23
|
<X509Certificate>MIID+jCCAuKgAwIBAgIJAIz/He5UafnhMA0GCSqGSIb3DQEBBQUAMFsxCzAJBgNV
|
@@ -44,4 +44,4 @@ Cg8Yo62X9vWW6PaKXHs3N+g1Ig16NwjdVIYvcxLc2KY0vrqu/R5c8RbmCxMZyss9
|
|
44
44
|
ZtltN+yN40INHGRWnHc=</X509Certificate>
|
45
45
|
</X509Data>
|
46
46
|
</KeyInfo>
|
47
|
-
</Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">jacob</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2015-02-12T22:54:29Z" Recipient="https://siteadmin.test.instructure.com/saml_consume" InResponseTo="_bec424fa5103428909a30ff1e31168327f79474984"/></saml:SubjectConfirmation></saml:Subject><saml:AuthnStatement AuthnInstant="2015-02-12T22:51:29Z"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion></samlp:Response>
|
47
|
+
</Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">jacob</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2015-02-12T22:54:29Z" Recipient="https://siteadmin.test.instructure.com/saml_consume" InResponseTo="_bec424fa5103428909a30ff1e31168327f79474984"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2015-02-12T22:51:24Z" NotOnOrAfter="2015-02-12T22:51:59Z"><saml:AudienceRestriction><saml:Audience>http://siteadmin.instructure.com/saml2</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2015-02-12T22:51:29Z"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion></samlp:Response>
|
@@ -9,15 +9,15 @@
|
|
9
9
|
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
10
10
|
</Transforms>
|
11
11
|
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
12
|
-
<DigestValue>
|
12
|
+
<DigestValue>b9jIvyyPEhWc/kHYHUA8LTCz4pwYSRCE+CL+SNqmiEk=</DigestValue>
|
13
13
|
</Reference>
|
14
14
|
</SignedInfo>
|
15
|
-
<SignatureValue>
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
<SignatureValue>eHHTFNYA1VNbzFOtsoTGn4A+BXdKFXHfJNvWWU52L1kBUfCyeFNVLby03yQRw+CO
|
16
|
+
71JomuTy/jpWU50h27sOfXjWjPkiULRHNPWuDIglrOgnUpu2HeD+i9IoA69/vF9J
|
17
|
+
Bmwm2IubzhBAxc70Dm/oXZ238bN0E+c2u4B9jp6MdVXSL7RDmfKAU19ABAZlYTmJ
|
18
|
+
4xXlS0fjrGPOn+BszBR9BNLDvNST/MgaGmwAU0esP5dYzC0Pwi9lOGD5bO+MOxTp
|
19
|
+
TBx9e0KY3BTEVVOxl8G6M8w9nx5mnKMgHpPq5P/uMHv7m8gUVdMQ8lDvPqyEibPw
|
20
|
+
ABIureP4iKebJVl7JTeoYA==</SignatureValue>
|
21
21
|
<KeyInfo>
|
22
22
|
<X509Data>
|
23
23
|
<X509Certificate>MIID+jCCAuKgAwIBAgIJAIz/He5UafnhMA0GCSqGSIb3DQEBBQUAMFsxCzAJBgNV
|
@@ -44,4 +44,4 @@ Cg8Yo62X9vWW6PaKXHs3N+g1Ig16NwjdVIYvcxLc2KY0vrqu/R5c8RbmCxMZyss9
|
|
44
44
|
ZtltN+yN40INHGRWnHc=</X509Certificate>
|
45
45
|
</X509Data>
|
46
46
|
</KeyInfo>
|
47
|
-
</Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">jacob</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2015-02-12T22:54:29Z" Recipient="https://siteadmin.test.instructure.com/saml_consume" InResponseTo="_bec424fa5103428909a30ff1e31168327f79474984"/></saml:SubjectConfirmation></saml:Subject><saml:AuthnStatement AuthnInstant="2015-02-12T22:51:29Z"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><saml:Attribute xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500" Name="urn:oid:2.5.4.42" FriendlyName="givenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" x500:Encoding="LDAP"><saml:AttributeValue xsi:type="xsd:string">cody</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>
|
47
|
+
</Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">jacob</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2015-02-12T22:54:29Z" Recipient="https://siteadmin.test.instructure.com/saml_consume" InResponseTo="_bec424fa5103428909a30ff1e31168327f79474984"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2015-02-12T22:51:24Z" NotOnOrAfter="2015-02-12T22:51:59Z"><saml:AudienceRestriction><saml:Audience>http://siteadmin.instructure.com/saml2</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2015-02-12T22:51:29Z"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><saml:Attribute xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500" Name="urn:oid:2.5.4.42" FriendlyName="givenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" x500:Encoding="LDAP"><saml:AttributeValue xsi:type="xsd:string">cody</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
module SAML2
|
4
|
+
describe Conditions do
|
5
|
+
it "empty should be valid" do
|
6
|
+
Conditions.new.valid?.must_equal :valid
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be valid with unknown condition" do
|
10
|
+
conditions = Conditions.new
|
11
|
+
conditions << Conditions::Condition.new
|
12
|
+
conditions.valid?.must_equal :indeterminate
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be valid with timestamps" do
|
16
|
+
conditions = Conditions.new
|
17
|
+
now = Time.now.utc
|
18
|
+
conditions.not_before = now - 5
|
19
|
+
conditions.not_on_or_after = now + 30
|
20
|
+
conditions.valid?.must_equal :valid
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be invalid with out of range timestamps" do
|
24
|
+
conditions = Conditions.new
|
25
|
+
now = Time.now.utc
|
26
|
+
conditions.not_before = now - 35
|
27
|
+
conditions.not_on_or_after = now - 5
|
28
|
+
conditions.valid?.must_equal :invalid
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should allow passing now" do
|
32
|
+
conditions = Conditions.new
|
33
|
+
now = Time.now.utc
|
34
|
+
conditions.not_before = now - 35
|
35
|
+
conditions.not_on_or_after = now - 5
|
36
|
+
conditions.valid?(now: now - 10).must_equal :valid
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be invalid before indeterminate" do
|
40
|
+
conditions = Conditions.new
|
41
|
+
now = Time.now.utc
|
42
|
+
conditions.not_before = now + 5
|
43
|
+
conditions << Conditions::Condition.new
|
44
|
+
conditions.valid?.must_equal :invalid
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be invalid before indeterminate (actual conditions)" do
|
48
|
+
conditions = Conditions.new
|
49
|
+
conditions << Conditions::Condition.new
|
50
|
+
conditions << Conditions::AudienceRestriction.new('audience')
|
51
|
+
conditions.valid?.must_equal :invalid
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
describe Conditions::AudienceRestriction do
|
57
|
+
it "should be invalid" do
|
58
|
+
Conditions::AudienceRestriction.new('expected').valid?(audience: 'actual').must_equal :invalid
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should be valid" do
|
62
|
+
Conditions::AudienceRestriction.new('expected').valid?(audience: 'expected').must_equal :valid
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should be valid with an array" do
|
66
|
+
Conditions::AudienceRestriction.new(['expected', 'actual']).valid?(audience: 'actual').must_equal :valid
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/spec/lib/response_spec.rb
CHANGED
@@ -28,6 +28,8 @@ module SAML2
|
|
28
28
|
assertion.instance_variable_set(:@id, "_cdfc3faf-90ad-462f-880d-677483210684")
|
29
29
|
response.instance_variable_set(:@issue_instant, Time.parse("2015-02-12T22:51:29Z"))
|
30
30
|
assertion.instance_variable_set(:@issue_instant, Time.parse("2015-02-12T22:51:29Z"))
|
31
|
+
assertion.conditions.not_before = Time.parse("2015-02-12T22:51:24Z")
|
32
|
+
assertion.conditions.not_on_or_after = Time.parse("2015-02-12T22:51:59Z")
|
31
33
|
assertion.statements.first.authn_instant = Time.parse("2015-02-12T22:51:29Z")
|
32
34
|
confirmation = assertion.subject.confirmation
|
33
35
|
confirmation.not_on_or_after = Time.parse("2015-02-12T22:54:29Z")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saml2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -102,6 +102,7 @@ files:
|
|
102
102
|
- lib/saml2/authn_request.rb
|
103
103
|
- lib/saml2/authn_statement.rb
|
104
104
|
- lib/saml2/base.rb
|
105
|
+
- lib/saml2/conditions.rb
|
105
106
|
- lib/saml2/contact.rb
|
106
107
|
- lib/saml2/endpoint.rb
|
107
108
|
- lib/saml2/engine.rb
|
@@ -139,6 +140,7 @@ files:
|
|
139
140
|
- spec/lib/attribute_consuming_service_spec.rb
|
140
141
|
- spec/lib/attribute_spec.rb
|
141
142
|
- spec/lib/authn_request_spec.rb
|
143
|
+
- spec/lib/conditions_spec.rb
|
142
144
|
- spec/lib/entity_spec.rb
|
143
145
|
- spec/lib/identity_provider_spec.rb
|
144
146
|
- spec/lib/indexed_object_spec.rb
|
@@ -182,6 +184,7 @@ test_files:
|
|
182
184
|
- spec/lib/attribute_consuming_service_spec.rb
|
183
185
|
- spec/lib/attribute_spec.rb
|
184
186
|
- spec/lib/authn_request_spec.rb
|
187
|
+
- spec/lib/conditions_spec.rb
|
185
188
|
- spec/lib/entity_spec.rb
|
186
189
|
- spec/lib/identity_provider_spec.rb
|
187
190
|
- spec/lib/indexed_object_spec.rb
|