cie-es 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +19 -0
  5. data/README.md +126 -0
  6. data/Rakefile +41 -0
  7. data/cie-es.gemspec +22 -0
  8. data/lib/cie/ruby-saml/authrequest.rb +205 -0
  9. data/lib/cie/ruby-saml/coding.rb +34 -0
  10. data/lib/cie/ruby-saml/error_handling.rb +27 -0
  11. data/lib/cie/ruby-saml/logging.rb +26 -0
  12. data/lib/cie/ruby-saml/logout_request.rb +126 -0
  13. data/lib/cie/ruby-saml/logout_response.rb +132 -0
  14. data/lib/cie/ruby-saml/metadata.rb +489 -0
  15. data/lib/cie/ruby-saml/request.rb +81 -0
  16. data/lib/cie/ruby-saml/response.rb +678 -0
  17. data/lib/cie/ruby-saml/settings.rb +89 -0
  18. data/lib/cie/ruby-saml/utils.rb +225 -0
  19. data/lib/cie/ruby-saml/validation_error.rb +7 -0
  20. data/lib/cie/ruby-saml/version.rb +5 -0
  21. data/lib/cie/xml_security.rb +166 -0
  22. data/lib/cie/xml_security_new.rb +373 -0
  23. data/lib/cie-es.rb +14 -0
  24. data/lib/schemas/saml20assertion_schema.xsd +283 -0
  25. data/lib/schemas/saml20protocol_schema.xsd +302 -0
  26. data/lib/schemas/xenc_schema.xsd +146 -0
  27. data/lib/schemas/xmldsig_schema.xsd +318 -0
  28. data/test/certificates/certificate1 +12 -0
  29. data/test/logoutrequest_test.rb +98 -0
  30. data/test/request_test.rb +53 -0
  31. data/test/response_test.rb +219 -0
  32. data/test/responses/adfs_response_sha1.xml +46 -0
  33. data/test/responses/adfs_response_sha256.xml +46 -0
  34. data/test/responses/adfs_response_sha384.xml +46 -0
  35. data/test/responses/adfs_response_sha512.xml +46 -0
  36. data/test/responses/no_signature_ns.xml +48 -0
  37. data/test/responses/open_saml_response.xml +56 -0
  38. data/test/responses/response1.xml.base64 +1 -0
  39. data/test/responses/response2.xml.base64 +79 -0
  40. data/test/responses/response3.xml.base64 +66 -0
  41. data/test/responses/response4.xml.base64 +93 -0
  42. data/test/responses/response5.xml.base64 +102 -0
  43. data/test/responses/response_with_ampersands.xml +139 -0
  44. data/test/responses/response_with_ampersands.xml.base64 +93 -0
  45. data/test/responses/simple_saml_php.xml +71 -0
  46. data/test/responses/wrapped_response_2.xml.base64 +150 -0
  47. data/test/settings_test.rb +43 -0
  48. data/test/test_helper.rb +65 -0
  49. data/test/xml_security_test.rb +123 -0
  50. metadata +119 -0
@@ -0,0 +1,132 @@
1
+ #encoding: utf-8
2
+
3
+ require "rexml/document"
4
+
5
+ module Cie
6
+ module Saml
7
+ class LogoutResponse
8
+ include Coding
9
+ include Request
10
+ ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
11
+ PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
12
+ DSIG = "http://www.w3.org/2000/09/xmldsig#"
13
+
14
+ def initialize( options = { } )
15
+ opt = { :response => nil, :settings => nil }.merge(options)
16
+ # We've recieved a LogoutResponse from the IdP
17
+ if opt[:response]
18
+ begin
19
+ @response = Cie::XMLSecurity::SignedDocument.new(decode( opt[:response] ))
20
+ # Check to see if we have a root tag using the "protocol" namespace.
21
+ # If not, it means this is deflated text and we need to raise to
22
+ # the rescue below
23
+ raise if @response.nil?
24
+ raise if @response.root.nil?
25
+ raise if @response.root.namespace != PROTOCOL
26
+ document
27
+ rescue
28
+ @response = Cie::XMLSecurity::SignedDocument.new( inflate(decode( opt[:response] ) ) )
29
+ end
30
+ end
31
+ # We plan to create() a new LogoutResponse
32
+ if opt[:settings]
33
+ @settings = opt[:settings]
34
+ end
35
+ end
36
+
37
+ # Create a LogoutResponse to to the IdP's LogoutRequest
38
+ # (For IdP initiated SLO)
39
+ def create( options )
40
+ opt = { :transaction_id => nil,
41
+ :in_response_to => nil,
42
+ :status => "urn:oasis:names:tc:SAML:2.0:status:Success",
43
+ :extra_parameters => nil }.merge(options)
44
+ return nil if opt[:transaction_id].nil?
45
+ @response = REXML::Document.new
46
+ @response.context[:attribute_quote] = :quote
47
+ uuid = "_" + UUID.new.generate
48
+ time = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
49
+ root = @response.add_element "saml2p:LogoutResponse", { "xmlns:saml2p" => PROTOCOL }
50
+ root.attributes['ID'] = uuid
51
+ root.attributes['IssueInstant'] = time
52
+ root.attributes['Version'] = "2.0"
53
+ # Just convenient naming to accept both names as InResponseTo
54
+ if opt[:transaction_id]
55
+ root.attributes['InResponseTo'] = opt[:transaction_id]
56
+ elsif opt[:in_response_to]
57
+ root.attributes['InResponseTo'] = opt[:in_response_to]
58
+ end
59
+ if opt[:status]
60
+ status = root.add_element "saml2p:Status"
61
+ status_code = status.add_element "saml2p:StatusCode", {
62
+ "Value" => opt[:status]
63
+ }
64
+ end
65
+ if @settings && @settings.issuer
66
+ issuer = root.add_element "saml:Issuer", {
67
+ "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion"
68
+ }
69
+ issuer.text = @settings.issuer
70
+ end
71
+ meta = Metadata.new( @settings )
72
+ Logging.debug "Created LogoutResponse:\n#{@response}"
73
+ return meta.create_slo_response( to_s, opt[:extra_parameters] )
74
+
75
+ #root.attributes['Destination'] = action
76
+
77
+ end
78
+ # function to return the created request as an XML document
79
+ def to_xml
80
+ text = ""
81
+ @response.write(text, 1)
82
+ return text
83
+ end
84
+ def to_s
85
+ @response.to_s
86
+ end
87
+
88
+ def issuer
89
+ element = REXML::XPath.first(@response, "/p:LogoutResponse/a:Issuer", {
90
+ "p" => PROTOCOL, "a" => ASSERTION} )
91
+ return nil if element.nil?
92
+ element.text
93
+ end
94
+
95
+ def in_response_to
96
+ element = REXML::XPath.first(@response, "/p:LogoutResponse", {
97
+ "p" => PROTOCOL })
98
+ return nil if element.nil?
99
+ element.attributes["InResponseTo"]
100
+ end
101
+
102
+ def success?
103
+ element = REXML::XPath.first(@response, "/p:LogoutResponse/p:Status/p:StatusCode", {
104
+ "p" => PROTOCOL })
105
+ return false if element.nil?
106
+ element.attributes["Value"] == "urn:oasis:names:tc:SAML:2.0:status:Success"
107
+
108
+ end
109
+ def is_valid?
110
+ validate(soft = true)
111
+ end
112
+
113
+ def validate!
114
+ validate( soft = false )
115
+ end
116
+ def validate( soft = true )
117
+ return false if @response.nil?
118
+ # Skip validation with a failed response if we don't have settings
119
+ return false if @settings.nil?
120
+ return false if @response.validate(@settings, soft) == false
121
+
122
+ return true
123
+
124
+ end
125
+
126
+ protected
127
+ def document
128
+ REXML::Document.new(@response)
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,489 @@
1
+ require "rexml/document"
2
+ require "rexml/xpath"
3
+ require "net/https"
4
+ require "uri"
5
+ require "digest/md5"
6
+ require "nokogiri"
7
+ require_relative "../xml_security_new" #fa il require della nokogiri
8
+ require "uuid"
9
+
10
+ # Class to return SP metadata based on the settings requested.
11
+ # Return this XML in a controller, then give that URL to the the
12
+ # IdP administrator. The IdP will poll the URL and your settings
13
+ # will be updated automatically
14
+ module Cie
15
+ module Saml
16
+ class Metadata
17
+ include REXML
18
+ include Coding
19
+ # a few symbols for SAML class names
20
+ HTTP_POST = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
21
+ HTTP_GET = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
22
+
23
+ attr_accessor :uuid
24
+
25
+ def initialize(settings=nil)
26
+ if settings
27
+ @settings = settings
28
+ end
29
+ end
30
+
31
+ def generate(settings)
32
+ #meta_doc = REXML::Document.new
33
+ meta_doc = Cie::XMLSecurityNew::Document.new
34
+ root = meta_doc.add_element "md:EntityDescriptor", {
35
+ "xmlns:md" => "urn:oasis:names:tc:SAML:2.0:metadata",
36
+ "xmlns:xml" => "http://www.w3.org/XML/1998/namespace"
37
+ }
38
+ if settings.issuer != nil
39
+ root.attributes["entityID"] = settings.issuer
40
+ end
41
+ uuid = "_" + UUID.new.generate
42
+ self.uuid = uuid
43
+ root.attributes["ID"] = uuid
44
+
45
+ sp_sso = root.add_element "md:SPSSODescriptor", {
46
+ "protocolSupportEnumeration" => "urn:oasis:names:tc:SAML:2.0:protocol",
47
+ "WantAssertionsSigned" => "true",
48
+ "AuthnRequestsSigned" => "true"
49
+
50
+ }
51
+
52
+
53
+ # if settings.sp_cert != nil
54
+ # keyDescriptor = sp_sso.add_element "md:KeyDescriptor", {
55
+ # "use" => "signing"
56
+ # }
57
+ # keyInfo = keyDescriptor.add_element "ds:KeyInfo", {
58
+ # "xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"
59
+ # }
60
+ # x509Data = keyInfo.add_element "ds:X509Data"
61
+ # x509Certificate = x509Data.add_element "ds:X509Certificate"
62
+ # file = ""
63
+ # File.foreach(settings.sp_cert){ |line|
64
+ # file += line unless (line.include?("RSA PUBLIC KEY") || line.include?("CERTIFICATE"))
65
+ # }
66
+ # x509Certificate.text = file
67
+ # end
68
+
69
+ # Add KeyDescriptor if messages will be signed / encrypted
70
+ #cert = settings.get_sp_cert
71
+ cert = settings.get_cert(settings.sp_cert)
72
+ if cert
73
+
74
+ if cert.is_a?(String)
75
+ cert = OpenSSL::X509::Certificate.new(cert)
76
+ end
77
+
78
+ cert_text = Base64.encode64(cert.to_der).to_s.gsub(/\n/, "").gsub(/\t/, "")
79
+ kd = sp_sso.add_element "md:KeyDescriptor", { "use" => "signing" }
80
+ ki = kd.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
81
+ xd = ki.add_element "ds:X509Data"
82
+ xc = xd.add_element "ds:X509Certificate"
83
+ xc.text = cert_text
84
+
85
+ # kd2 = sp_sso.add_element "md:KeyDescriptor", { "use" => "encryption" }
86
+ # ki2 = kd2.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
87
+ # xd2 = ki2.add_element "ds:X509Data"
88
+ # xc2 = xd2.add_element "ds:X509Certificate"
89
+ # xc2.text = cert_text
90
+ end
91
+
92
+ if !settings.sp_external_consumer_cert.nil? && settings.sp_external_consumer_cert.length > 0
93
+ settings.sp_external_consumer_cert.each{ |cert_cons_external|
94
+ cert_ex = settings.get_cert(cert_cons_external)
95
+ if cert_ex
96
+
97
+ if cert_ex.is_a?(String)
98
+ cert_ex = OpenSSL::X509::Certificate.new(cert_ex)
99
+ end
100
+
101
+ cert_text = Base64.encode64(cert_ex.to_der).to_s.gsub(/\n/, "").gsub(/\t/, "")
102
+ kd = sp_sso.add_element "md:KeyDescriptor", { "use" => "signing" }
103
+ ki = kd.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
104
+ xd = ki.add_element "ds:X509Data"
105
+ xc = xd.add_element "ds:X509Certificate"
106
+ xc.text = cert_text
107
+ end
108
+ }
109
+ end
110
+
111
+ if settings.single_logout_service_url != nil
112
+ sp_sso.add_element "md:SingleLogoutService", {
113
+ "Binding" => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
114
+ "Location" => settings.single_logout_service_url
115
+ }
116
+ sp_sso.add_element "md:SingleLogoutService", {
117
+ "Binding" => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
118
+ "Location" => settings.single_logout_service_url
119
+ }
120
+ end
121
+
122
+ #Logout dei servizi esterni
123
+ unless settings.hash_assertion_consumer.blank?
124
+ settings.hash_assertion_consumer.each_pair{ |index, hash_service|
125
+ unless hash_service['logout'].blank?
126
+ sp_sso.add_element "md:SingleLogoutService", {
127
+ "Binding" => hash_service['logout']['binding'] || "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
128
+ "Location" => hash_service['logout']['location']
129
+ }
130
+ end
131
+ }
132
+ end
133
+
134
+ name_identifier_formats = settings.name_identifier_format
135
+ if name_identifier_formats != nil
136
+ name_id = []
137
+ name_identifier_formats.each_with_index{ |format, index|
138
+ name_id[index] = sp_sso.add_element "md:NameIDFormat"
139
+ name_id[index].text = format
140
+ }
141
+
142
+ end
143
+
144
+ if settings.assertion_consumer_service_url
145
+
146
+ #ciclo e creo i vari tag AssertionConsumerService
147
+ settings.hash_assertion_consumer.each_pair{ |index, hash_service|
148
+
149
+ sp_sso.add_element "md:AssertionConsumerService", {
150
+ "Binding" => settings.assertion_consumer_service_binding,
151
+ "Location" => (hash_service['external'] ? hash_service['url_consumer'] : settings.assertion_consumer_service_url ),
152
+ "isDefault" => hash_service['default'],
153
+ "index" => index
154
+ }
155
+ }
156
+
157
+ # #Caso con eidas
158
+ # sp_sso.add_element "md:AssertionConsumerService", {
159
+ # "Binding" => settings.assertion_consumer_service_binding,
160
+ # "Location" => settings.assertion_consumer_service_url,
161
+ # "index" => 99
162
+ # }
163
+
164
+ # sp_sso.add_element "md:AssertionConsumerService", {
165
+ # "Binding" => settings.assertion_consumer_service_binding,
166
+ # "Location" => settings.assertion_consumer_service_url,
167
+ # "index" => 100
168
+ # }
169
+
170
+ settings.hash_assertion_consumer.each_pair{ |index, hash_service|
171
+
172
+ #AttributeConsumingService
173
+ attr_cons_service = sp_sso.add_element "md:AttributeConsumingService", {
174
+ "index" => index,
175
+ }
176
+ service_name = attr_cons_service.add_element "md:ServiceName", {
177
+ "xml:lang" => "it"
178
+ }
179
+ service_name.text = hash_service['testo']
180
+ unless hash_service['description'].blank?
181
+ service_description = attr_cons_service.add_element "md:ServiceDescription", {
182
+ "xml:lang" => "it"
183
+ }
184
+ service_description.text = hash_service['description']
185
+ end
186
+
187
+ if hash_service['array_campi'].is_a?(Array)
188
+ hash_service['array_campi'].each_with_index{ |attribute, index|
189
+ attr_cons_service.add_element "md:RequestedAttribute", {
190
+ "Name" => attribute
191
+ }
192
+ }
193
+ else #hash
194
+ hash_service['array_campi'].each_pair{ |attribute, name_format|
195
+ attr_cons_service.add_element "md:RequestedAttribute", {
196
+ "Name" => attribute,
197
+ "NameFormat" => name_format
198
+ }
199
+ }
200
+ end
201
+ }
202
+
203
+
204
+
205
+
206
+ #Per EIDAS
207
+ # #AttributeConsumingService
208
+ # attr_cons_service = sp_sso.add_element "md:AttributeConsumingService", {
209
+ # "index" => "99",
210
+ # }
211
+ # service_name
212
+ # = attr_cons_service.add_element "md:ServiceName", {
213
+ # "xml:lang" => "it"
214
+ # }
215
+ # service_name.text = "eIDAS Natural Person Minimum Attribute Set"
216
+ # settings.requested_attribute.each_with_index{ |attribute, index|
217
+ # attr_cons_service.add_element "md:RequestedAttribute", {
218
+ # "Name" => attribute
219
+ # }
220
+ # }
221
+
222
+ # #AttributeConsumingService
223
+ # attr_cons_service = sp_sso.add_element "md:AttributeConsumingService", {
224
+ # "index" => "100",
225
+ # }
226
+ # service_name = attr_cons_service.add_element "md:ServiceName", {
227
+ # "xml:lang" => "it"
228
+ # }
229
+ # service_name.text = "eIDAS Natural Person Full Attribute Set"
230
+ # settings.requested_attribute.each_with_index{ |attribute, index|
231
+ # attr_cons_service.add_element "md:RequestedAttribute", {
232
+ # "Name" => attribute
233
+ # }
234
+ # }
235
+
236
+
237
+ end
238
+ #organization
239
+ organization = root.add_element "md:Organization"
240
+ org_name = organization.add_element "md:OrganizationName", {
241
+ "xml:lang" => "it"
242
+ }
243
+ org_name.text = settings.organization['org_name']
244
+ org_display_name = organization.add_element "md:OrganizationDisplayName", {
245
+ "xml:lang" => "it"
246
+ }
247
+ org_display_name.text = settings.organization['org_display_name']
248
+ org_url = organization.add_element "md:OrganizationURL", {
249
+ "xml:lang" => "it"
250
+ }
251
+ org_url.text = settings.organization['org_url']
252
+
253
+ #meta_doc << REXML::XMLDecl.new(version='1.0', encoding='UTF-8')
254
+ meta_doc << REXML::XMLDecl.new("1.0", "UTF-8")
255
+
256
+
257
+ #SE SERVE ANCHE ENCRYPTION
258
+ # # Add KeyDescriptor if messages will be signed / encrypted
259
+ #
260
+ # if cert
261
+ # cert_text = Base64.encode64(cert.to_der).gsub("\n", '')
262
+ # kd = sp_sso.add_element "md:KeyDescriptor", { "use" => "signing" }
263
+ # ki = kd.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
264
+ # xd = ki.add_element "ds:X509Data"
265
+ # xc = xd.add_element "ds:X509Certificate"
266
+ # xc.text = cert_text
267
+
268
+ # kd2 = sp_sso.add_element "md:KeyDescriptor", { "use" => "encryption" }
269
+ # ki2 = kd2.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
270
+ # xd2 = ki2.add_element "ds:X509Data"
271
+ # xc2 = xd2.add_element "ds:X509Certificate"
272
+ # xc2.text = cert_text
273
+ # end
274
+
275
+ #cert = settings.get_sp_cert
276
+ cert = settings.get_cert(settings.sp_cert) #inserisco il certificato principale
277
+ # embed signature
278
+ if settings.metadata_signed && settings.sp_private_key && settings.sp_cert
279
+ private_key = settings.get_sp_key
280
+ meta_doc.sign_document(private_key, cert)
281
+ end
282
+ ret = ""
283
+ # stampo come stringa semplice i metadata per non avere problemi con validazione firma
284
+ ret = meta_doc.to_s
285
+ #Logging.debug "Generated metadata:\n#{ret}"
286
+
287
+ return ret
288
+
289
+ end
290
+
291
+ def create_sso_request(message, extra_parameters = {} )
292
+ build_message( :type => "SAMLRequest",
293
+ :service => "SingleSignOnService",
294
+ :message => message, :extra_parameters => extra_parameters)
295
+ end
296
+ def create_sso_response(message, extra_parameters = {} )
297
+ build_message( :type => "SAMLResponse",
298
+ :service => "SingleSignOnService",
299
+ :message => message, :extra_parameters => extra_parameters)
300
+ end
301
+ def create_slo_request(message, extra_parameters = {} )
302
+ build_message( :type => "SAMLRequest",
303
+ :service => "SingleLogoutService",
304
+ :message => message, :extra_parameters => extra_parameters)
305
+ end
306
+ def create_slo_response(message, extra_parameters = {} )
307
+ build_message( :type => "SAMLResponse",
308
+ :service => "SingleLogoutService",
309
+ :message => message, :extra_parameters => extra_parameters)
310
+ end
311
+
312
+ # Construct a SAML message using information in the IdP metadata.
313
+ # :type can be either "SAMLRequest" or "SAMLResponse"
314
+ # :service refers to the Binding method,
315
+ # either "SingleLogoutService" or "SingleSignOnService"
316
+ # :message is the SAML message itself (XML)
317
+ # I've provided easy to use wrapper functions above
318
+ def build_message( options = {} )
319
+ opt = { :type => nil, :service => nil, :message => nil, :extra_parameters => nil }.merge(options)
320
+ url = binding_select( opt[:service] )
321
+ return message_get( opt[:type], url, opt[:message], opt[:extra_parameters] )
322
+ end
323
+
324
+ # get the IdP metadata, and select the appropriate SSO binding
325
+ # that we can support. Currently this is HTTP-Redirect and HTTP-POST
326
+ # but more could be added in the future
327
+ def binding_select(service)
328
+ # first check if we're still using the old hard coded method for
329
+ # backwards compatability
330
+ if service == "SingleSignOnService" && @settings.idp_sso_target_url != nil
331
+ return @settings.idp_sso_target_url
332
+ end
333
+ if service == "SingleLogoutService" && @settings.idp_slo_target_url != nil
334
+ return @settings.idp_slo_target_url
335
+ end
336
+
337
+ meta_doc = get_idp_metadata
338
+
339
+ return nil unless meta_doc
340
+ # first try GET (REDIRECT)
341
+ sso_element = REXML::XPath.first(meta_doc, "/EntityDescriptor/IDPSSODescriptor/#{service}[@Binding='#{HTTP_GET}']")
342
+ if !sso_element.nil?
343
+ @URL = sso_element.attributes["Location"]
344
+ Logging.debug "binding_select: GET from #{@URL}"
345
+ return @URL
346
+ end
347
+
348
+ # next try post
349
+ sso_element = REXML::XPath.first(meta_doc, "/EntityDescriptor/IDPSSODescriptor/#{service}[@Binding='#{HTTP_POST}']")
350
+ if !sso_element.nil?
351
+ @URL = sso_element.attributes["Location"]
352
+ #Logging.debug "binding_select: POST to #{@URL}"
353
+ return @URL
354
+ end
355
+
356
+ # other types we might want to add in the future: SOAP, Artifact
357
+ end
358
+
359
+
360
+ def fetch(uri_str, limit = 10)
361
+ # You should choose a better exception.
362
+ raise ArgumentError, 'too many HTTP redirects' if limit == 0
363
+
364
+ uri = URI.parse(uri_str)
365
+ if uri.scheme == "http"
366
+ response = Net::HTTP.get_response(uri)
367
+ elsif uri.scheme == "https"
368
+ http = Net::HTTP.new(uri.host, uri.port)
369
+ http.use_ssl = true
370
+ # Most IdPs will probably use self signed certs
371
+ #http.verify_mode = OpenSSL::SSL::VERIFY_PEER
372
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
373
+ get = Net::HTTP::Get.new(uri.request_uri)
374
+ response = http.request(get)
375
+ end
376
+
377
+ case response
378
+ when Net::HTTPSuccess then
379
+ response
380
+ when Net::HTTPRedirection then
381
+ location = response['location']
382
+ warn "redirected to #{location}"
383
+ fetch(location, limit - 1)
384
+ else
385
+ response.value
386
+ end
387
+ end
388
+
389
+
390
+
391
+ # Retrieve the remote IdP metadata from the URL or a cached copy
392
+ # returns a REXML document of the metadata
393
+ def get_idp_metadata
394
+ return false if @settings.idp_metadata.nil?
395
+
396
+ # Look up the metdata in cache first
397
+ id = Digest::MD5.hexdigest(@settings.idp_metadata)
398
+ response = fetch(@settings.idp_metadata)
399
+ #meta_text = response.body
400
+ #testo_response = meta_text.sub!(' xmlns:xml="http://www.w3.org/XML/1998/namespace"', '') da errori
401
+ #uso nokogiri per cercare il certificato, uso la funzione che rimuove tutti i namespace
402
+ doc_noko = Nokogiri::XML(response.body.gsub(/\n/, "").gsub(/\t/, "")) #modifica per poste
403
+ doc_noko.remove_namespaces!
404
+ extract_certificate(doc_noko)
405
+ doc_rexml = REXML::Document.new(doc_noko.to_xml)
406
+
407
+ return doc_rexml
408
+
409
+ # USE OF CACHE WITH CERTIFICATE
410
+ # lookup = @cache.read(id)
411
+ # if lookup != nil
412
+ # Logging.debug "IdP metadata cached lookup for #{@settings.idp_metadata}"
413
+ # doc = REXML::Document.new( lookup )
414
+ # extract_certificate( doc )
415
+ # return doc
416
+ # end
417
+
418
+ # Logging.debug "IdP metadata cache miss on #{@settings.idp_metadata}"
419
+ # # cache miss
420
+ # if File.exists?(@settings.idp_metadata)
421
+ # fp = File.open( @settings.idp_metadata, "r")
422
+ # meta_text = fp.read
423
+ # else
424
+ # uri = URI.parse(@settings.idp_metadata)
425
+ # if uri.scheme == "http"
426
+ # response = Net::HTTP.get_response(uri)
427
+ # meta_text = response.body
428
+ # elsif uri.scheme == "https"
429
+ # http = Net::HTTP.new(uri.host, uri.port)
430
+ # http.use_ssl = true
431
+ # # Most IdPs will probably use self signed certs
432
+ # #http.verify_mode = OpenSSL::SSL::VERIFY_PEER
433
+ # http.verify_mode = OpenSSL::SSL::VERIFY_NONE
434
+ # get = Net::HTTP::Get.new(uri.request_uri)
435
+ # response = http.request(get)
436
+ # meta_text = response.body
437
+ # end
438
+ # end
439
+ # # Add it to the cache
440
+ # @cache.write(id, meta_text, @settings.idp_metadata_ttl )
441
+ # doc = REXML::Document.new( meta_text )
442
+ # extract_certificate(doc)
443
+ # return doc
444
+ end
445
+
446
+ def extract_certificate(meta_doc)
447
+ #ricerco il certificato con nokogiri
448
+ # pull out the x509 tag
449
+ x509 = meta_doc.xpath("//EntityDescriptor//IDPSSODescriptor//KeyDescriptor//KeyInfo//X509Data//X509Certificate")
450
+
451
+ #x509 = REXML::XPath.first(meta_doc, "/md:EntityDescriptor/md:IDPSSODescriptor"+"/md:KeyDescriptor"+"/ds:KeyInfo/ds:X509Data/ds:X509Certificate")
452
+ # If the IdP didn't specify the use attribute
453
+ if x509.nil?
454
+ x509 = meta_doc.xpath("//EntityDescriptor//IDPSSODescriptor//KeyDescriptor//KeyInfo//X509Data//X509Certificate")
455
+ # x509 = REXML::XPath.first(meta_doc,
456
+ # "/EntityDescriptor/IDPSSODescriptor" +
457
+ # "/KeyDescriptor" +
458
+ # "/ds:KeyInfo/ds:X509Data/ds:X509Certificate"
459
+ # )
460
+ end
461
+ @settings.idp_cert = x509.children.to_s.gsub(/\n/, "").gsub(/\t/, "")
462
+ end
463
+
464
+ # construct the parameter list on the URL and return
465
+ def message_get( type, url, message, extra_parameters = {} )
466
+ params = Hash.new
467
+ if extra_parameters
468
+ params.merge!(extra_parameters)
469
+ end
470
+ # compress GET requests to try and stay under that 8KB request limit
471
+ #deflate of samlrequest
472
+ params[type] = encode( deflate( message ) )
473
+ #Logging.debug "#{type}=#{params[type]}"
474
+
475
+ uri = Addressable::URI.parse(url)
476
+ if uri.query_values == nil
477
+ uri.query_values = params
478
+ else
479
+ # solution to stevenwilkin's parameter merge
480
+ uri.query_values = params.merge(uri.query_values)
481
+ end
482
+ url = uri.to_s
483
+ #Logging.debug "Sending to URL #{url}"
484
+ return url
485
+ end
486
+
487
+ end
488
+ end
489
+ end