11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
# File 'lib/samlr/tools/response_builder.rb', line 11
def self.build(options = {})
issue_instant = options[:issue_instant] || Samlr::Tools::Timestamp.stamp
response_id = options[:response_id] || Samlr::Tools.uuid
assertion_id = options[:assertion_id] || Samlr::Tools.uuid
status_code = options[:status_code] || "urn:oasis:names:tc:SAML:2.0:status:Success"
name_id_format = options[:name_id_format] || EMAIL_FORMAT
subject_conf_m = options[:subject_conf_m] || "urn:oasis:names:tc:SAML:2.0:cm:bearer"
version = options[:version] || "2.0"
auth_context = options[:auth_context] || "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
issuer = options[:issuer] || "ResponseBuilder IdP"
attributes = options[:attributes] || {}
destination = options.fetch(:destination)
in_response_to = options.fetch(:in_response_to)
name_id = options.fetch(:name_id)
not_on_or_after = options.fetch(:not_on_or_after)
not_before = options.fetch(:not_before)
audience = options.fetch(:audience)
sign_assertion = [ true, false ].member?(options[:sign_assertion]) ? options[:sign_assertion] : true
sign_response = [ true, false ].member?(options[:sign_response]) ? options[:sign_response] : true
skip_assertion = options[:skip_assertion]
skip_conditions = options[:skip_conditions]
builder = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
xml.Response("xmlns:samlp" => NS_MAP["samlp"], "ID" => response_id, "InResponseTo" => in_response_to, "Version" => version, "IssueInstant" => issue_instant, "Destination" => destination) do
xml.doc.root.add_namespace_definition("saml", NS_MAP["saml"])
xml.doc.root.namespace = xml.doc.root.namespace_definitions.find { |ns| ns.prefix == "samlp" }
xml["saml"].Issuer(issuer)
xml["samlp"].Status { |xml| xml["samlp"].StatusCode("Value" => status_code) }
unless skip_assertion
xml["saml"].Assertion("xmlns:saml" => NS_MAP["saml"], "ID" => assertion_id, "IssueInstant" => issue_instant, "Version" => "2.0") do
xml["saml"].Issuer(issuer)
xml["saml"].Subject do
xml["saml"].NameID(name_id, "Format" => name_id_format)
xml["saml"].SubjectConfirmation("Method" => subject_conf_m) do
xml["saml"].SubjectConfirmationData("InResponseTo" => in_response_to, "NotOnOrAfter" => not_on_or_after, "Recipient" => destination)
end
end
unless skip_conditions
xml["saml"].Conditions("NotBefore" => not_before, "NotOnOrAfter" => not_on_or_after) do
xml["saml"].AudienceRestriction do
xml["saml"].Audience(audience)
end
end
end
xml["saml"].AuthnStatement("AuthnInstant" => issue_instant, "SessionIndex" => assertion_id) do
xml["saml"].AuthnContext do
xml["saml"].AuthnContextClassRef(auth_context)
end
end
unless attributes.empty?
xml["saml"].AttributeStatement do
attributes.keys.sort.each do |name|
xml["saml"].Attribute("Name" => name) do
values = Array(attributes[name])
values.each do |value|
xml["saml"].AttributeValue(value, "xmlns:xsi" => NS_MAP["xsi"], "xmlns:xs" => NS_MAP["xs"], "xsi:type" => "xs:string")
end
end
end
end
end
end
end
end
end
response = builder.doc
response = sign(response, assertion_id, options) if sign_assertion
response = sign(response, response_id, options) if sign_response
response.to_xml(COMPACT)
end
|