saml2 1.0.8 → 1.0.9
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.rb +5 -0
- data/lib/saml2/assertion.rb +5 -5
- data/lib/saml2/attribute.rb +9 -9
- data/lib/saml2/authn_request.rb +17 -5
- data/lib/saml2/authn_statement.rb +3 -3
- data/lib/saml2/base.rb +5 -5
- data/lib/saml2/conditions.rb +6 -6
- data/lib/saml2/contact.rb +6 -6
- data/lib/saml2/entity.rb +2 -2
- data/lib/saml2/identity_provider.rb +6 -6
- data/lib/saml2/key.rb +6 -6
- data/lib/saml2/organization.rb +4 -4
- data/lib/saml2/response.rb +6 -6
- data/lib/saml2/sso.rb +0 -2
- data/lib/saml2/subject.rb +9 -9
- data/lib/saml2/version.rb +1 -1
- data/spec/lib/attribute_consuming_service_spec.rb +1 -1
- data/spec/lib/attribute_spec.rb +3 -3
- data/spec/lib/authn_request_spec.rb +5 -0
- data/spec/lib/entity_spec.rb +3 -3
- data/spec/lib/indexed_object_spec.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5806ee95e988647a1593ddb8c9f833b1c0ae9064
|
4
|
+
data.tar.gz: 536f3c655fb7e81ff79003f46dbd1f3d9ec76d3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 487c35b7ae581c8dcc89140341cbb7d1513eac561c571b416c4b5a889b2010eacfae9250f7462837425487b90dec337e0c26456c085cf392b2f3c55bb0ab63ca
|
7
|
+
data.tar.gz: ac21dc27daa7f8297187dd7f7a2f9797fdb9fe3c4bb986d7d258edd296a9709ab1ec2a9b3fea0b89fd2b251fec4547ccef31b08c06352459f14ca79d6a49dfc4
|
data/lib/saml2.rb
CHANGED
data/lib/saml2/assertion.rb
CHANGED
@@ -31,13 +31,13 @@ module SAML2
|
|
31
31
|
ID: id,
|
32
32
|
Version: '2.0',
|
33
33
|
IssueInstant: issue_instant.iso8601
|
34
|
-
) do |
|
35
|
-
issuer.build(
|
34
|
+
) do |assertion|
|
35
|
+
issuer.build(assertion, element: 'Issuer')
|
36
36
|
|
37
|
-
subject.build(
|
37
|
+
subject.build(assertion)
|
38
38
|
|
39
|
-
conditions.build(
|
40
|
-
statements.each { |stmt| stmt.build(
|
39
|
+
conditions.build(assertion)
|
40
|
+
statements.each { |stmt| stmt.build(assertion) }
|
41
41
|
end
|
42
42
|
end.doc.root
|
43
43
|
end
|
data/lib/saml2/attribute.rb
CHANGED
@@ -52,13 +52,13 @@ module SAML2
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def build(builder)
|
55
|
-
builder['saml'].Attribute('Name' => name) do |
|
56
|
-
|
57
|
-
|
55
|
+
builder['saml'].Attribute('Name' => name) do |attribute|
|
56
|
+
attribute.parent['FriendlyName'] = friendly_name if friendly_name
|
57
|
+
attribute.parent['NameFormat'] = name_format if name_format
|
58
58
|
Array.wrap(value).each do |value|
|
59
59
|
xsi_type, val = convert_to_xsi(value)
|
60
|
-
|
61
|
-
|
60
|
+
attribute['saml'].AttributeValue(val) do |attribute_value|
|
61
|
+
attribute_value.parent['xsi:type'] = xsi_type if xsi_type
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -68,8 +68,8 @@ module SAML2
|
|
68
68
|
@name = node['Name']
|
69
69
|
@friendly_name = node['FriendlyName']
|
70
70
|
@name_format = node['NameFormat']
|
71
|
-
values = node.xpath('saml:AttributeValue', Namespaces::ALL).map do |
|
72
|
-
convert_from_xsi(
|
71
|
+
values = node.xpath('saml:AttributeValue', Namespaces::ALL).map do |value|
|
72
|
+
convert_from_xsi(value.attribute_with_ns('type', Namespaces::XSI), value.content && value.content.strip)
|
73
73
|
end
|
74
74
|
@value = case values.length
|
75
75
|
when 0; nil
|
@@ -131,8 +131,8 @@ module SAML2
|
|
131
131
|
|
132
132
|
def build(builder)
|
133
133
|
builder['saml'].AttributeStatement('xmlns:xs' => Namespaces::XS,
|
134
|
-
'xmlns:xsi' => Namespaces::XSI) do |
|
135
|
-
@attributes.each { |attr| attr.build(
|
134
|
+
'xmlns:xsi' => Namespaces::XSI) do |statement|
|
135
|
+
@attributes.each { |attr| attr.build(statement) }
|
136
136
|
end
|
137
137
|
end
|
138
138
|
end
|
data/lib/saml2/authn_request.rb
CHANGED
@@ -9,16 +9,28 @@ require 'saml2/schemas'
|
|
9
9
|
require 'saml2/subject'
|
10
10
|
|
11
11
|
module SAML2
|
12
|
+
class MessageTooLarge < RuntimeError
|
13
|
+
end
|
14
|
+
|
12
15
|
class AuthnRequest
|
13
16
|
def self.decode(authnrequest)
|
14
17
|
begin
|
15
|
-
|
16
|
-
authnrequest =
|
17
|
-
zstream.
|
18
|
+
raise MessageTooLarge if authnrequest.bytesize > SAML2.config[:max_message_size]
|
19
|
+
authnrequest = Base64.decode64(authnrequest)
|
20
|
+
zstream = Zlib::Inflate.new
|
21
|
+
xml = ''
|
22
|
+
# do it in 1K slices, so we can protect against bombs
|
23
|
+
(0..authnrequest.bytesize / 1024).each do |i|
|
24
|
+
xml.concat(zstream.inflate(authnrequest.byteslice(i * 1024, 1024)))
|
25
|
+
raise MessageTooLarge if xml.bytesize > SAML2.config[:max_message_size]
|
26
|
+
end
|
27
|
+
xml.concat(zstream.finish)
|
28
|
+
raise MessageTooLarge if xml.bytesize > SAML2.config[:max_message_size]
|
29
|
+
|
18
30
|
zstream.close
|
19
|
-
rescue Zlib::BufError
|
31
|
+
rescue Zlib::DataError, Zlib::BufError
|
20
32
|
end
|
21
|
-
parse(
|
33
|
+
parse(xml)
|
22
34
|
end
|
23
35
|
|
24
36
|
def self.parse(authnrequest)
|
@@ -16,9 +16,9 @@ module SAML2
|
|
16
16
|
attr_accessor :authn_instant, :authn_context_class_ref
|
17
17
|
|
18
18
|
def build(builder)
|
19
|
-
builder['saml'].AuthnStatement('AuthnInstant' => authn_instant.iso8601) do |
|
20
|
-
|
21
|
-
|
19
|
+
builder['saml'].AuthnStatement('AuthnInstant' => authn_instant.iso8601) do |authn_statement|
|
20
|
+
authn_statement['saml'].AuthnContext do |authn_context|
|
21
|
+
authn_context['saml'].AuthnContextClassRef(authn_context_class_ref) if authn_context_class_ref
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
data/lib/saml2/base.rb
CHANGED
@@ -27,17 +27,17 @@ module SAML2
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def self.load_string_array(node, element)
|
30
|
-
node.xpath(element, Namespaces::ALL).map do |
|
31
|
-
|
30
|
+
node.xpath(element, Namespaces::ALL).map do |element_node|
|
31
|
+
element_node.content && element_node.content.strip
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
def self.load_object_array(node, element, klass)
|
36
|
-
node.xpath(element, Namespaces::ALL).map do |
|
36
|
+
node.xpath(element, Namespaces::ALL).map do |element_node|
|
37
37
|
if klass.is_a?(Hash)
|
38
|
-
klass[
|
38
|
+
klass[element_node.name].from_xml(element_node)
|
39
39
|
else
|
40
|
-
klass.from_xml(
|
40
|
+
klass.from_xml(element_node)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
data/lib/saml2/conditions.rb
CHANGED
@@ -26,12 +26,12 @@ module SAML2
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def build(builder)
|
29
|
-
builder['saml'].Conditions do |
|
30
|
-
|
31
|
-
|
29
|
+
builder['saml'].Conditions do |conditions|
|
30
|
+
conditions.parent['NotBefore'] = not_before.iso8601 if not_before
|
31
|
+
conditions.parent['NotOnOrAfter'] = not_on_or_after.iso8601 if not_on_or_after
|
32
32
|
|
33
33
|
each do |condition|
|
34
|
-
condition.build(
|
34
|
+
condition.build(conditions)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -55,9 +55,9 @@ module SAML2
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def build(builder)
|
58
|
-
builder['saml'].AudienceRestriction do |
|
58
|
+
builder['saml'].AudienceRestriction do |audience_restriction|
|
59
59
|
Array.wrap(audience).each do |single_audience|
|
60
|
-
|
60
|
+
audience_restriction['saml'].Audience(single_audience)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
data/lib/saml2/contact.rb
CHANGED
@@ -34,15 +34,15 @@ module SAML2
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def build(builder)
|
37
|
-
builder['md'].ContactPerson('contactType' => type) do |
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
builder['md'].ContactPerson('contactType' => type) do |contact_person|
|
38
|
+
contact_person['md'].Company(company) if company
|
39
|
+
contact_person['md'].GivenName(given_name) if given_name
|
40
|
+
contact_person['md'].SurName(surname) if surname
|
41
41
|
email_addresses.each do |email|
|
42
|
-
|
42
|
+
contact_person['md'].EmailAddress(email)
|
43
43
|
end
|
44
44
|
telephone_numbers.each do |tel|
|
45
|
-
|
45
|
+
contact_person['md'].TelephoneNumber(tel)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
data/lib/saml2/entity.rb
CHANGED
@@ -120,9 +120,9 @@ module SAML2
|
|
120
120
|
builder['md'].EntityDescriptor('entityID' => entity_id,
|
121
121
|
'xmlns:md' => Namespaces::METADATA,
|
122
122
|
'xmlns:dsig' => Namespaces::DSIG,
|
123
|
-
'xmlns:xenc' => Namespaces::XENC) do |
|
123
|
+
'xmlns:xenc' => Namespaces::XENC) do |entity_descriptor|
|
124
124
|
roles.each do |role|
|
125
|
-
role.build(
|
125
|
+
role.build(entity_descriptor)
|
126
126
|
end
|
127
127
|
|
128
128
|
super
|
@@ -41,21 +41,21 @@ module SAML2
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def build(builder)
|
44
|
-
builder['md'].IDPSSODescriptor do |
|
45
|
-
super(
|
44
|
+
builder['md'].IDPSSODescriptor do |idp_sso_descriptor|
|
45
|
+
super(idp_sso_descriptor)
|
46
46
|
|
47
|
-
|
47
|
+
idp_sso_descriptor['WantAuthnRequestsSigned'] = want_authn_requests_signed? unless want_authn_requests_signed?.nil?
|
48
48
|
|
49
49
|
single_sign_on_services.each do |sso|
|
50
|
-
sso.build(
|
50
|
+
sso.build(idp_sso_descriptor, 'SingleSignOnService')
|
51
51
|
end
|
52
52
|
|
53
53
|
attribute_profiles.each do |ap|
|
54
|
-
|
54
|
+
idp_sso_descriptor['md'].AttributeProfile(ap)
|
55
55
|
end
|
56
56
|
|
57
57
|
attributes.each do |attr|
|
58
|
-
attr.build(
|
58
|
+
attr.build(idp_sso_descriptor)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
data/lib/saml2/key.rb
CHANGED
@@ -38,15 +38,15 @@ module SAML2
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def build(builder)
|
41
|
-
builder['md'].KeyDescriptor do |
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
builder['md'].KeyDescriptor do |key_descriptor|
|
42
|
+
key_descriptor.parent['use'] = use if use
|
43
|
+
key_descriptor['dsig'].KeyInfo do |key_info|
|
44
|
+
key_info['dsig'].X509Data do |x509_data|
|
45
|
+
x509_data['dsig'].X509Certificate(x509)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
encryption_methods.each do |method|
|
49
|
-
|
49
|
+
key_descriptor['xenc'].EncryptionMethod('Algorithm' => method)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
data/lib/saml2/organization.rb
CHANGED
@@ -37,10 +37,10 @@ module SAML2
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def build(builder)
|
40
|
-
builder['md'].Organization do |
|
41
|
-
self.class.build(
|
42
|
-
self.class.build(
|
43
|
-
self.class.build(
|
40
|
+
builder['md'].Organization do |organization|
|
41
|
+
self.class.build(organization, @name, 'OrganizationName')
|
42
|
+
self.class.build(organization, @display_name, 'OrganizationDisplayName')
|
43
|
+
self.class.build(organization, @url, 'OrganizationURL')
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
data/lib/saml2/response.rb
CHANGED
@@ -77,17 +77,17 @@ module SAML2
|
|
77
77
|
Version: '2.0',
|
78
78
|
IssueInstant: issue_instant.iso8601,
|
79
79
|
Destination: destination
|
80
|
-
) do |
|
81
|
-
|
80
|
+
) do |response|
|
81
|
+
response.parent['InResponseTo'] = in_response_to if in_response_to
|
82
82
|
|
83
|
-
issuer.build(
|
83
|
+
issuer.build(response, element: 'Issuer', include_namespace: true) if issuer
|
84
84
|
|
85
|
-
|
86
|
-
|
85
|
+
response['samlp'].Status do |status|
|
86
|
+
status['samlp'].StatusCode(Value: status_code)
|
87
87
|
end
|
88
88
|
|
89
89
|
assertions.each do |assertion|
|
90
|
-
|
90
|
+
response.parent << assertion.to_xml
|
91
91
|
end
|
92
92
|
end
|
93
93
|
end
|
data/lib/saml2/sso.rb
CHANGED
data/lib/saml2/subject.rb
CHANGED
@@ -14,9 +14,9 @@ module SAML2
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def build(builder)
|
17
|
-
builder['saml'].Subject do |
|
18
|
-
name_id.build(
|
19
|
-
confirmation.build(
|
17
|
+
builder['saml'].Subject do |subject|
|
18
|
+
name_id.build(subject) if name_id
|
19
|
+
confirmation.build(subject) if confirmation
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -30,16 +30,16 @@ module SAML2
|
|
30
30
|
attr_accessor :method, :not_before, :not_on_or_after, :recipient, :in_response_to
|
31
31
|
|
32
32
|
def build(builder)
|
33
|
-
builder['saml'].SubjectConfirmation('Method' => method) do |
|
33
|
+
builder['saml'].SubjectConfirmation('Method' => method) do |subject_confirmation|
|
34
34
|
if in_response_to ||
|
35
35
|
recipient ||
|
36
36
|
not_before ||
|
37
37
|
not_on_or_after
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
subject_confirmation['saml'].SubjectConfirmationData do |subject_confirmation_data|
|
39
|
+
subject_confirmation_data.parent['NotBefore'] = not_before.iso8601 if not_before
|
40
|
+
subject_confirmation_data.parent['NotOnOrAfter'] = not_on_or_after.iso8601 if not_on_or_after
|
41
|
+
subject_confirmation_data.parent['Recipient'] = recipient if recipient
|
42
|
+
subject_confirmation_data.parent['InResponseTo'] = in_response_to if in_response_to
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
data/lib/saml2/version.rb
CHANGED
data/spec/lib/attribute_spec.rb
CHANGED
@@ -4,9 +4,9 @@ module SAML2
|
|
4
4
|
describe Attribute do
|
5
5
|
def serialize(attribute)
|
6
6
|
doc = Nokogiri::XML::Builder.new do |builder|
|
7
|
-
builder['saml'].Root('xmlns:saml' => Namespaces::SAML) do |
|
8
|
-
attribute.build(
|
9
|
-
|
7
|
+
builder['saml'].Root('xmlns:saml' => Namespaces::SAML) do |root|
|
8
|
+
attribute.build(root)
|
9
|
+
root.parent.child['xmlns:saml'] = Namespaces::SAML
|
10
10
|
end
|
11
11
|
end.doc
|
12
12
|
doc.root.child.to_s
|
@@ -15,6 +15,11 @@ module SAML2
|
|
15
15
|
authnrequest = AuthnRequest.decode('abc')
|
16
16
|
authnrequest.valid_schema?.must_equal false
|
17
17
|
end
|
18
|
+
|
19
|
+
it "doesn't allow deflate bombs" do
|
20
|
+
bomb = Base64.encode64(Zlib::Deflate.deflate("\0" * 2 * 1024 * 1024))
|
21
|
+
-> { AuthnRequest.decode(bomb) }.must_raise MessageTooLarge
|
22
|
+
end
|
18
23
|
end
|
19
24
|
|
20
25
|
it "should be valid" do
|
data/spec/lib/entity_spec.rb
CHANGED
@@ -9,12 +9,12 @@ module SAML2
|
|
9
9
|
|
10
10
|
it "should return nil when not valid schema" do
|
11
11
|
entity = Entity.parse("<xml></xml>")
|
12
|
-
entity
|
12
|
+
assert_nil(entity)
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should return nil on non-XML" do
|
16
16
|
entity = Entity.parse("garbage")
|
17
|
-
entity
|
17
|
+
assert_nil(entity)
|
18
18
|
end
|
19
19
|
|
20
20
|
describe "valid schema" do
|
@@ -27,7 +27,7 @@ module SAML2
|
|
27
27
|
it "should parse the organization" do
|
28
28
|
entity.organization.display_name.must_equal 'Canvas'
|
29
29
|
entity.organization.display_name('en').must_equal 'Canvas'
|
30
|
-
entity.organization.display_name('es')
|
30
|
+
assert_nil(entity.organization.display_name('es'))
|
31
31
|
entity.organization.display_name(:all).must_equal en: 'Canvas'
|
32
32
|
end
|
33
33
|
|
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.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -193,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
193
193
|
version: '0'
|
194
194
|
requirements: []
|
195
195
|
rubyforge_project:
|
196
|
-
rubygems_version: 2.6.
|
196
|
+
rubygems_version: 2.6.11
|
197
197
|
signing_key:
|
198
198
|
specification_version: 4
|
199
199
|
summary: SAML 2.0 Library
|