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