saml2 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|