saml2 3.1.2 → 3.1.4
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/Rakefile +6 -4
- data/exe/bulk_verify_responses +94 -0
- data/lib/saml2/assertion.rb +7 -7
- data/lib/saml2/attribute/x500.rb +31 -28
- data/lib/saml2/attribute.rb +53 -49
- data/lib/saml2/attribute_consuming_service.rb +29 -31
- data/lib/saml2/authn_request.rb +54 -47
- data/lib/saml2/authn_statement.rb +31 -20
- data/lib/saml2/base.rb +72 -63
- data/lib/saml2/bindings/http_post.rb +7 -7
- data/lib/saml2/bindings/http_redirect.rb +37 -33
- data/lib/saml2/bindings.rb +1 -1
- data/lib/saml2/conditions.rb +19 -16
- data/lib/saml2/contact.rb +19 -18
- data/lib/saml2/endpoint.rb +14 -11
- data/lib/saml2/entity.rb +27 -27
- data/lib/saml2/identity_provider.rb +13 -10
- data/lib/saml2/indexed_object.rb +15 -12
- data/lib/saml2/key.rb +43 -34
- data/lib/saml2/localized_name.rb +11 -10
- data/lib/saml2/logout_request.rb +8 -8
- data/lib/saml2/logout_response.rb +4 -4
- data/lib/saml2/message.rb +24 -20
- data/lib/saml2/name_id.rb +45 -41
- data/lib/saml2/namespaces.rb +8 -8
- data/lib/saml2/organization.rb +11 -10
- data/lib/saml2/organization_and_contacts.rb +5 -5
- data/lib/saml2/request.rb +3 -3
- data/lib/saml2/requested_authn_context.rb +4 -4
- data/lib/saml2/response.rb +45 -33
- data/lib/saml2/role.rb +11 -11
- data/lib/saml2/schemas.rb +13 -10
- data/lib/saml2/service_provider.rb +11 -12
- data/lib/saml2/signable.rb +23 -18
- data/lib/saml2/sso.rb +5 -5
- data/lib/saml2/status.rb +9 -7
- data/lib/saml2/status_response.rb +5 -5
- data/lib/saml2/subject.rb +28 -28
- data/lib/saml2/version.rb +1 -1
- data/lib/saml2.rb +7 -7
- metadata +78 -122
- data/spec/fixtures/FederationMetadata.xml +0 -670
- data/spec/fixtures/authnrequest.xml +0 -12
- data/spec/fixtures/certificate.pem +0 -24
- data/spec/fixtures/entities.xml +0 -13
- data/spec/fixtures/external-uri-reference-response.xml +0 -48
- data/spec/fixtures/identity_provider.xml +0 -46
- data/spec/fixtures/noconditions_response.xml +0 -1
- data/spec/fixtures/othercertificate.pem +0 -25
- data/spec/fixtures/privatekey.key +0 -27
- data/spec/fixtures/response_assertion_signed_reffed_from_response.xml +0 -6
- data/spec/fixtures/response_signed.xml +0 -46
- data/spec/fixtures/response_tampered_certificate.xml +0 -25
- data/spec/fixtures/response_tampered_signature.xml +0 -46
- data/spec/fixtures/response_with_attribute_signed.xml +0 -46
- data/spec/fixtures/response_with_encrypted_assertion.xml +0 -58
- data/spec/fixtures/response_with_rsa_key_value.xml +0 -1
- data/spec/fixtures/response_with_signed_assertion_and_encrypted_subject.xml +0 -116
- data/spec/fixtures/response_without_keyinfo.xml +0 -1
- data/spec/fixtures/service_provider.xml +0 -79
- data/spec/fixtures/test3-response.xml +0 -9
- data/spec/fixtures/test6-response.xml +0 -10
- data/spec/fixtures/test7-response.xml +0 -10
- data/spec/fixtures/xml_missigned_assertion.xml +0 -84
- data/spec/fixtures/xml_signature_wrapping_attack_duplicate_ids.xml +0 -11
- data/spec/fixtures/xml_signature_wrapping_attack_response_attributes.xml +0 -45
- data/spec/fixtures/xml_signature_wrapping_attack_response_nameid.xml +0 -44
- data/spec/fixtures/xslt-transform-response.xml +0 -57
- data/spec/lib/attribute_consuming_service_spec.rb +0 -129
- data/spec/lib/attribute_spec.rb +0 -149
- data/spec/lib/authn_request_spec.rb +0 -52
- data/spec/lib/bindings/http_redirect_spec.rb +0 -183
- data/spec/lib/conditions_spec.rb +0 -74
- data/spec/lib/entity_spec.rb +0 -58
- data/spec/lib/identity_provider_spec.rb +0 -43
- data/spec/lib/indexed_object_spec.rb +0 -71
- data/spec/lib/key_spec.rb +0 -23
- data/spec/lib/logout_request_spec.rb +0 -33
- data/spec/lib/logout_response_spec.rb +0 -33
- data/spec/lib/message_spec.rb +0 -23
- data/spec/lib/response_spec.rb +0 -293
- data/spec/lib/service_provider_spec.rb +0 -76
- data/spec/lib/signable_spec.rb +0 -15
- data/spec/spec_helper.rb +0 -8
data/lib/saml2/localized_name.rb
CHANGED
@@ -1,20 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "saml2/base"
|
4
|
+
require "saml2/namespaces"
|
5
5
|
|
6
6
|
module SAML2
|
7
7
|
class LocalizedName < Hash
|
8
8
|
attr_reader :element
|
9
9
|
|
10
10
|
def initialize(element, name = nil)
|
11
|
+
super()
|
11
12
|
@element = element
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
return if name.nil?
|
14
|
+
|
15
|
+
if name.is_a?(Hash)
|
16
|
+
replace(name)
|
17
|
+
else
|
18
|
+
self[nil] = name
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
@@ -42,14 +43,14 @@ module SAML2
|
|
42
43
|
def from_xml(nodes)
|
43
44
|
clear
|
44
45
|
nodes.each do |node|
|
45
|
-
self[node[
|
46
|
+
self[node["xml:lang"].to_sym] = node.content && node.content.strip
|
46
47
|
end
|
47
48
|
self
|
48
49
|
end
|
49
50
|
|
50
51
|
def build(builder)
|
51
52
|
each do |lang, value|
|
52
|
-
builder[
|
53
|
+
builder["md"].__send__(element, value, "xml:lang" => lang)
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end
|
data/lib/saml2/logout_request.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "saml2/name_id"
|
4
|
+
require "saml2/request"
|
5
5
|
|
6
6
|
module SAML2
|
7
7
|
class LogoutRequest < Request
|
@@ -24,27 +24,27 @@ module SAML2
|
|
24
24
|
|
25
25
|
# @return [NameID]
|
26
26
|
def name_id
|
27
|
-
@name_id ||= (NameID.from_xml(xml.at_xpath(
|
27
|
+
@name_id ||= (NameID.from_xml(xml.at_xpath("saml:NameID", Namespaces::ALL)) if xml)
|
28
28
|
end
|
29
29
|
|
30
30
|
# @return [String, Array<String>]
|
31
31
|
def session_index
|
32
|
-
@session_index ||= (load_string_array(xml,
|
32
|
+
@session_index ||= (load_string_array(xml, "samlp:SessionIndex") if xml)
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
37
|
def build(builder)
|
38
|
-
builder[
|
39
|
-
|
40
|
-
|
38
|
+
builder["samlp"].LogoutRequest(
|
39
|
+
"xmlns:samlp" => Namespaces::SAMLP,
|
40
|
+
"xmlns:saml" => Namespaces::SAML
|
41
41
|
) do |logout_request|
|
42
42
|
super(logout_request)
|
43
43
|
|
44
44
|
name_id.build(logout_request)
|
45
45
|
|
46
46
|
Array(session_index).each do |session_index_instance|
|
47
|
-
logout_request[
|
47
|
+
logout_request["samlp"].SessionIndex(session_index_instance)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "saml2/status_response"
|
4
4
|
|
5
5
|
module SAML2
|
6
6
|
class LogoutResponse < StatusResponse
|
@@ -21,9 +21,9 @@ module SAML2
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def build(builder)
|
24
|
-
builder[
|
25
|
-
|
26
|
-
|
24
|
+
builder["samlp"].LogoutResponse(
|
25
|
+
"xmlns:samlp" => Namespaces::SAMLP,
|
26
|
+
"xmlns:saml" => Namespaces::SAML
|
27
27
|
) do |logout_response|
|
28
28
|
super(logout_response)
|
29
29
|
end
|
data/lib/saml2/message.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "securerandom"
|
4
|
+
require "time"
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require "saml2/base"
|
7
|
+
require "saml2/signable"
|
8
8
|
|
9
9
|
module SAML2
|
10
10
|
class InvalidMessage < RuntimeError
|
@@ -59,8 +59,10 @@ module SAML2
|
|
59
59
|
# SAML message type.
|
60
60
|
def from_xml(node)
|
61
61
|
return super unless self == Message
|
62
|
+
|
62
63
|
klass = Message.known_messages[node.name]
|
63
|
-
raise UnknownMessage
|
64
|
+
raise UnknownMessage, "Unknown message #{node.name}" unless klass
|
65
|
+
|
64
66
|
klass.from_xml(node)
|
65
67
|
end
|
66
68
|
|
@@ -72,8 +74,12 @@ module SAML2
|
|
72
74
|
# If called on a subclass, will raise if the parsed message does not
|
73
75
|
# match the class is was called on.
|
74
76
|
def parse(xml)
|
75
|
-
result = Message.from_xml(Nokogiri::XML(xml
|
76
|
-
|
77
|
+
result = Message.from_xml(Nokogiri::XML(xml, &:strict).root)
|
78
|
+
unless self == Message || result.instance_of?(self)
|
79
|
+
raise UnexpectedMessage,
|
80
|
+
"Expected a #{name}, but got a #{result.class.name}"
|
81
|
+
end
|
82
|
+
|
77
83
|
result
|
78
84
|
rescue Nokogiri::XML::SyntaxError
|
79
85
|
raise CorruptMessage
|
@@ -86,10 +92,10 @@ module SAML2
|
|
86
92
|
end
|
87
93
|
|
88
94
|
def inherited(klass)
|
95
|
+
super
|
89
96
|
# explicitly keep track of all messages in this base class
|
90
|
-
Message.known_messages[klass.name.sub(/^SAML2::/,
|
97
|
+
Message.known_messages[klass.name.sub(/^SAML2::/, "")] = klass
|
91
98
|
end
|
92
|
-
|
93
99
|
end
|
94
100
|
|
95
101
|
def initialize
|
@@ -133,37 +139,35 @@ module SAML2
|
|
133
139
|
|
134
140
|
# @return [String]
|
135
141
|
def id
|
136
|
-
@id ||= xml[
|
142
|
+
@id ||= xml["ID"]
|
137
143
|
end
|
138
144
|
|
139
145
|
# @return [Time]
|
140
146
|
def issue_instant
|
141
|
-
@issue_instant ||= Time.parse(xml[
|
147
|
+
@issue_instant ||= Time.parse(xml["IssueInstant"])
|
142
148
|
end
|
143
149
|
|
144
150
|
# @return [String, nil]
|
145
151
|
def destination
|
146
|
-
if xml && !instance_variable_defined?(:@destination)
|
147
|
-
@destination = xml['Destination']
|
148
|
-
end
|
152
|
+
@destination = xml["Destination"] if xml && !instance_variable_defined?(:@destination)
|
149
153
|
@destination
|
150
154
|
end
|
151
155
|
|
152
156
|
# @return [NameID, nil]
|
153
157
|
def issuer
|
154
|
-
@issuer ||= NameID.from_xml(xml.at_xpath(
|
158
|
+
@issuer ||= NameID.from_xml(xml.at_xpath("saml:Issuer", Namespaces::ALL))
|
155
159
|
end
|
156
160
|
|
157
161
|
protected
|
158
162
|
|
159
163
|
# should be called from inside the specific request element
|
160
164
|
def build(message)
|
161
|
-
message.parent[
|
162
|
-
message.parent[
|
163
|
-
message.parent[
|
164
|
-
message.parent[
|
165
|
+
message.parent["ID"] = id
|
166
|
+
message.parent["Version"] = "2.0"
|
167
|
+
message.parent["IssueInstant"] = issue_instant.iso8601
|
168
|
+
message.parent["Destination"] = destination if destination
|
165
169
|
|
166
|
-
issuer
|
170
|
+
issuer&.build(message, element: "Issuer")
|
167
171
|
end
|
168
172
|
end
|
169
173
|
end
|
data/lib/saml2/name_id.rb
CHANGED
@@ -1,19 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "saml2/base"
|
4
|
+
require "saml2/namespaces"
|
5
5
|
|
6
6
|
module SAML2
|
7
7
|
class NameID < Base
|
8
8
|
module Format
|
9
|
-
EMAIL_ADDRESS
|
10
|
-
ENTITY
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
EMAIL_ADDRESS = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
10
|
+
ENTITY =
|
11
|
+
"urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
|
12
|
+
KERBEROS =
|
13
|
+
"urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos" # name[/instance]@REALM
|
14
|
+
PERSISTENT =
|
15
|
+
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" # opaque, pseudo-random, unique per SP-IdP pair
|
16
|
+
TRANSIENT =
|
17
|
+
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient" # opaque, will likely change
|
18
|
+
UNSPECIFIED =
|
19
|
+
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
20
|
+
WINDOWS_DOMAIN_QUALIFIED_NAME =
|
21
|
+
"urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName" # [DomainName\]UserName
|
22
|
+
X509_SUBJECT_NAME = "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName"
|
17
23
|
end
|
18
24
|
|
19
25
|
class Policy < Base
|
@@ -25,6 +31,7 @@ module SAML2
|
|
25
31
|
# @param format optional [String]
|
26
32
|
# @param sp_name_qualifier optional [String]
|
27
33
|
def initialize(allow_create = nil, format = nil, sp_name_qualifier = nil)
|
34
|
+
super()
|
28
35
|
@allow_create = allow_create if allow_create
|
29
36
|
@format = format if format
|
30
37
|
@sp_name_qualifier = sp_name_qualifier if sp_name_qualifier
|
@@ -32,43 +39,37 @@ module SAML2
|
|
32
39
|
|
33
40
|
# @return [Boolean, nil]
|
34
41
|
def allow_create?
|
35
|
-
if xml && !instance_variable_defined?(:@allow_create)
|
36
|
-
@allow_create = xml['AllowCreate']&.== 'true'
|
37
|
-
end
|
42
|
+
@allow_create = xml["AllowCreate"]&.== "true" if xml && !instance_variable_defined?(:@allow_create)
|
38
43
|
@allow_create
|
39
44
|
end
|
40
45
|
|
41
46
|
# @see Format
|
42
47
|
# @return [String, nil]
|
43
48
|
def format
|
44
|
-
if xml && !instance_variable_defined?(:@format)
|
45
|
-
@format = xml['Format']
|
46
|
-
end
|
49
|
+
@format = xml["Format"] if xml && !instance_variable_defined?(:@format)
|
47
50
|
@format
|
48
51
|
end
|
49
52
|
|
50
53
|
# @return [String, nil]
|
51
54
|
def sp_name_qualifier
|
52
|
-
if xml && !instance_variable_defined?(:@sp_name_qualifier)
|
53
|
-
@sp_name_qualifier = xml['SPNameQualifier']
|
54
|
-
end
|
55
|
+
@sp_name_qualifier = xml["SPNameQualifier"] if xml && !instance_variable_defined?(:@sp_name_qualifier)
|
55
56
|
@sp_name_qualifier
|
56
57
|
end
|
57
58
|
|
58
59
|
# @param rhs [Policy]
|
59
60
|
# @return [Boolean]
|
60
|
-
def ==(
|
61
|
-
allow_create? ==
|
62
|
-
|
63
|
-
|
61
|
+
def ==(other)
|
62
|
+
allow_create? == other.allow_create? &&
|
63
|
+
format == other.format &&
|
64
|
+
sp_name_qualifier == other.sp_name_qualifier
|
64
65
|
end
|
65
66
|
|
66
67
|
# (see Base#build)
|
67
68
|
def build(builder)
|
68
|
-
builder[
|
69
|
-
name_id_policy.parent[
|
70
|
-
name_id_policy.parent[
|
71
|
-
name_id_policy.parent[
|
69
|
+
builder["samlp"].NameIDPolicy do |name_id_policy|
|
70
|
+
name_id_policy.parent["Format"] = format if format
|
71
|
+
name_id_policy.parent["SPNameQualifier"] = sp_name_qualifier if sp_name_qualifier
|
72
|
+
name_id_policy.parent["AllowCreate"] = allow_create? unless allow_create?.nil?
|
72
73
|
end
|
73
74
|
end
|
74
75
|
end
|
@@ -81,9 +82,9 @@ module SAML2
|
|
81
82
|
# (see Base#from_xml)
|
82
83
|
def from_xml(node)
|
83
84
|
self.id = node.content.strip
|
84
|
-
self.format = node[
|
85
|
-
self.name_qualifier = node[
|
86
|
-
self.sp_name_qualifier = node[
|
85
|
+
self.format = node["Format"]
|
86
|
+
self.name_qualifier = node["NameQualifier"]
|
87
|
+
self.sp_name_qualifier = node["SPNameQualifier"]
|
87
88
|
end
|
88
89
|
|
89
90
|
# @param id [String]
|
@@ -91,26 +92,29 @@ module SAML2
|
|
91
92
|
# @param name_qualifier optional [String]
|
92
93
|
# @param sp_name_qualifier optional [String]
|
93
94
|
def initialize(id = nil, format = nil, name_qualifier: nil, sp_name_qualifier: nil)
|
94
|
-
|
95
|
-
|
95
|
+
super()
|
96
|
+
@id = id
|
97
|
+
@format = format
|
98
|
+
@name_qualifier = name_qualifier
|
99
|
+
@sp_name_qualifier = sp_name_qualifier
|
96
100
|
end
|
97
101
|
|
98
102
|
# @param rhs [NameID]
|
99
103
|
# @return [Boolean]
|
100
|
-
def ==(
|
101
|
-
id ==
|
102
|
-
|
103
|
-
|
104
|
-
|
104
|
+
def ==(other)
|
105
|
+
id == other.id &&
|
106
|
+
format == other.format &&
|
107
|
+
name_qualifier == other.name_qualifier &&
|
108
|
+
sp_name_qualifier == other.sp_name_qualifier
|
105
109
|
end
|
106
110
|
|
107
111
|
# (see Base#build)
|
108
112
|
def build(builder, element: nil)
|
109
113
|
args = {}
|
110
|
-
args[
|
111
|
-
args[
|
112
|
-
args[
|
113
|
-
builder[
|
114
|
+
args["Format"] = format if format
|
115
|
+
args["NameQualifier"] = name_qualifier if name_qualifier
|
116
|
+
args["SPNameQualifier"] = sp_name_qualifier if sp_name_qualifier
|
117
|
+
builder["saml"].__send__(element || "NameID", id, args)
|
114
118
|
end
|
115
119
|
end
|
116
120
|
end
|
data/lib/saml2/namespaces.rb
CHANGED
@@ -12,14 +12,14 @@ module SAML2
|
|
12
12
|
X500 = "urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
|
13
13
|
|
14
14
|
ALL = {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
"xmlns:dsig" => DSIG,
|
16
|
+
"xmlns:md" => METADATA,
|
17
|
+
"xmlns:saml" => SAML,
|
18
|
+
"xmlns:samlp" => SAMLP,
|
19
|
+
"xmlns:x500" => X500,
|
20
|
+
"xmlns:xenc" => XENC,
|
21
|
+
"xmlns:xs" => XS,
|
22
|
+
"xmlns:xsi" => XSI
|
23
23
|
}.freeze
|
24
24
|
end
|
25
25
|
end
|
data/lib/saml2/organization.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "saml2/base"
|
4
|
+
require "saml2/localized_name"
|
5
|
+
require "saml2/namespaces"
|
6
6
|
|
7
7
|
module SAML2
|
8
8
|
class Organization < Base
|
@@ -11,20 +11,21 @@ module SAML2
|
|
11
11
|
|
12
12
|
# (see Base#from_xml)
|
13
13
|
def from_xml(node)
|
14
|
-
name.from_xml(node.xpath(
|
15
|
-
display_name.from_xml(node.xpath(
|
16
|
-
url.from_xml(node.xpath(
|
14
|
+
name.from_xml(node.xpath("md:OrganizationName", Namespaces::ALL))
|
15
|
+
display_name.from_xml(node.xpath("md:OrganizationDisplayName", Namespaces::ALL))
|
16
|
+
url.from_xml(node.xpath("md:OrganizationURL", Namespaces::ALL))
|
17
17
|
end
|
18
18
|
|
19
19
|
def initialize(name = nil, display_name = nil, url = nil)
|
20
|
-
|
21
|
-
@
|
22
|
-
@
|
20
|
+
super()
|
21
|
+
@name = LocalizedName.new("OrganizationName", name)
|
22
|
+
@display_name = LocalizedName.new("OrganizationDisplayName", display_name)
|
23
|
+
@url = LocalizedName.new("OrganizationURL", url)
|
23
24
|
end
|
24
25
|
|
25
26
|
# (see Base#build)
|
26
27
|
def build(builder)
|
27
|
-
builder[
|
28
|
+
builder["md"].Organization do |organization|
|
28
29
|
@name.build(organization)
|
29
30
|
@display_name.build(organization)
|
30
31
|
@url.build(organization)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "saml2/contact"
|
4
|
+
require "saml2/organization"
|
5
5
|
|
6
6
|
module SAML2
|
7
7
|
module OrganizationAndContacts
|
@@ -22,20 +22,20 @@ module SAML2
|
|
22
22
|
# @return [Organization, nil]
|
23
23
|
def organization
|
24
24
|
unless instance_variable_defined?(:@organization)
|
25
|
-
@organization = Organization.from_xml(xml.at_xpath(
|
25
|
+
@organization = Organization.from_xml(xml.at_xpath("md:Organization", Namespaces::ALL))
|
26
26
|
end
|
27
27
|
@organization
|
28
28
|
end
|
29
29
|
|
30
30
|
# @return [Array<Contact>]
|
31
31
|
def contacts
|
32
|
-
@contacts ||= load_object_array(xml,
|
32
|
+
@contacts ||= load_object_array(xml, "md:ContactPerson", Contact)
|
33
33
|
end
|
34
34
|
|
35
35
|
protected
|
36
36
|
|
37
37
|
def build(builder)
|
38
|
-
organization
|
38
|
+
organization&.build(builder)
|
39
39
|
contacts.each do |contact|
|
40
40
|
contact.build(builder)
|
41
41
|
end
|
data/lib/saml2/request.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "saml2/base"
|
4
4
|
|
5
5
|
module SAML2
|
6
6
|
class RequestedAuthnContext < Base
|
@@ -11,10 +11,10 @@ module SAML2
|
|
11
11
|
|
12
12
|
# (see Base#build)
|
13
13
|
def build(builder)
|
14
|
-
builder[
|
15
|
-
requested_authn_context.parent[
|
14
|
+
builder["samlp"].RequestedAuthnContext do |requested_authn_context|
|
15
|
+
requested_authn_context.parent["Comparison"] = comparison.to_s if comparison
|
16
16
|
Array(class_ref).each do |individual_class_ref|
|
17
|
-
requested_authn_context[
|
17
|
+
requested_authn_context["saml"].AuthnContextClassRef(individual_class_ref)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|