ruby-saml 0.8.9 → 0.8.10

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-saml might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 646f99f7f6a7590eb22b51fad5f183cfed8038be
4
- data.tar.gz: 008e10e85a4aea26fdf2c067cc8f6112d18f55a7
2
+ SHA256:
3
+ metadata.gz: 1a564ad5fdd002f4648b22638bf51dd7ad029ea633484289c7ce2e8759a3c5d6
4
+ data.tar.gz: 15d0f1c459006f4c65fc9cb916b29b55098e68d9e3c5123080737b41b4e5e449
5
5
  SHA512:
6
- metadata.gz: 7d239d7038cf7041e4dab1dd27dd92e5bb1f53d777ace0aa0c4ed9f08b4a9b077555e7d1eeed2ed8a8e21767039267747b9194172148e74bac7703205b862a16
7
- data.tar.gz: 151df4d9fc610fbef47e5c93c73b8f25f9297b0bd457106e6fcd427933eebbe164c415d807ca9f70749937d5df66a4e49fb5423a7be2de6b1cd24641a077f94e
6
+ metadata.gz: 943d65750b9895285e60b24d612c1cce77bef3a262387121ccf9b7f8536ebfea27874d3a68ff095dc1a36e2bc3c53f509de07d2e4e31c02a20437e18015af561
7
+ data.tar.gz: ccf1223639a43235641ba2533e61473e4ff248624571cd05177ccd1dd0611f7d8df16f405fd74af2987112a988f5fcb0f2f6c54fe3830f89d3688964780ea333
data/Gemfile CHANGED
@@ -5,9 +5,16 @@ source 'http://rubygems.org'
5
5
 
6
6
  gemspec
7
7
 
8
+ if RUBY_VERSION < '1.9'
9
+ gem 'nokogiri', '~> 1.5.0'
10
+ elsif RUBY_VERSION < '2.1'
11
+ gem 'nokogiri', '>= 1.5.0', '<= 1.6.8.1'
12
+ else
13
+ gem 'nokogiri', '>= 1.5.0'
14
+ end
15
+
8
16
  group :test do
9
17
  if RUBY_VERSION < '1.9'
10
- gem 'nokogiri', '~> 1.5.0'
11
18
  gem 'ruby-debug', '~> 0.10.4'
12
19
  elsif RUBY_VERSION < '2.0'
13
20
  gem 'debugger-linecache', '~> 1.2.0'
@@ -23,5 +30,6 @@ group :test do
23
30
  gem 'shoulda', '~> 2.11'
24
31
  gem 'systemu', '~> 2'
25
32
  gem 'test-unit', '~> 3.0.9'
33
+ gem 'minitest', '~> 5.5'
26
34
  gem 'timecop', '<= 0.6.0'
27
35
  end
@@ -1,16 +1,49 @@
1
1
  require "base64"
2
- require "uuid"
3
2
  require "zlib"
4
3
  require "cgi"
5
- require "rexml/document"
6
- require "rexml/xpath"
4
+ require "onelogin/ruby-saml/utils"
7
5
 
8
6
  module OneLogin
9
7
  module RubySaml
10
- include REXML
8
+
11
9
  class Authrequest
10
+ # AuthNRequest ID
11
+ attr_reader :uuid
12
+
13
+ # Initializes the AuthNRequest. An Authrequest Object.
14
+ # Asigns an ID, a random uuid.
15
+ #
16
+ def initialize
17
+ @uuid = OneLogin::RubySaml::Utils.uuid
18
+ end
19
+
12
20
  def create(settings, params = {})
13
- params = {} if params.nil?
21
+ params = create_params(settings, params)
22
+ params_prefix = (settings.idp_sso_target_url =~ /\?/) ? '&' : '?'
23
+ saml_request = CGI.escape(params.delete("SAMLRequest"))
24
+ request_params = "#{params_prefix}SAMLRequest=#{saml_request}"
25
+ params.each_pair do |key, value|
26
+ request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
27
+ end
28
+ raise "Invalid settings, idp_sso_target_url is not set!" if settings.idp_sso_target_url.nil?
29
+ @login_url = settings.idp_sso_target_url + request_params
30
+ end
31
+
32
+ # Creates the Get parameters for the request.
33
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
34
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
35
+ # @return [Hash] Parameters
36
+ #
37
+ def create_params(settings, params={})
38
+ # The method expects :RelayState but sometimes we get 'RelayState' instead.
39
+ # Based on the HashWithIndifferentAccess value in Rails we could experience
40
+ # conflicts so this line will solve them.
41
+ relay_state = params[:RelayState] || params['RelayState']
42
+
43
+ if relay_state.nil?
44
+ params.delete(:RelayState)
45
+ params.delete('RelayState')
46
+ end
14
47
 
15
48
  request_doc = create_authentication_xml_doc(settings)
16
49
  request_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
@@ -20,28 +53,49 @@ module OneLogin
20
53
 
21
54
  Logging.debug "Created AuthnRequest: #{request}"
22
55
 
23
- request = Zlib::Deflate.deflate(request, 9)[2..-5] if settings.compress_request
56
+ request = Zlib::Deflate.deflate(request, 9)[2..-5] if settings.compress_request
24
57
  if Base64.respond_to?('strict_encode64')
25
- base64_request = Base64.strict_encode64(request)
58
+ base64_request = Base64.strict_encode64(request)
26
59
  else
27
- base64_request = Base64.encode64(request).gsub(/\n/, "")
60
+ base64_request = Base64.encode64(request).gsub(/\n/, "")
61
+ end
62
+
63
+ request_params = {"SAMLRequest" => base64_request}
64
+
65
+ if settings.security[:authn_requests_signed] && !settings.security[:embed_sign] && settings.private_key
66
+ params['SigAlg'] = settings.security[:signature_method]
67
+ url_string = OneLogin::RubySaml::Utils.build_query(
68
+ :type => 'SAMLRequest',
69
+ :data => base64_request,
70
+ :relay_state => relay_state,
71
+ :sig_alg => params['SigAlg']
72
+ )
73
+ sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
74
+ signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
75
+ if Base64.respond_to?('strict_encode64')
76
+ params['Signature'] = Base64.strict_encode64(signature)
77
+ else
78
+ params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
79
+ end
28
80
  end
29
- encoded_request = CGI.escape(base64_request)
30
- params_prefix = (settings.idp_sso_target_url =~ /\?/) ? '&' : '?'
31
- request_params = "#{params_prefix}SAMLRequest=#{encoded_request}"
32
81
 
33
82
  params.each_pair do |key, value|
34
- request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
83
+ request_params[key] = value.to_s
35
84
  end
36
85
 
37
- settings.idp_sso_target_url + request_params
86
+ request_params
38
87
  end
39
88
 
40
89
  def create_authentication_xml_doc(settings)
41
- uuid = "_" + UUID.new.generate
42
- time = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
43
- # Create AuthnRequest root element using REXML
44
- request_doc = REXML::Document.new
90
+ document = create_xml_document(settings)
91
+ sign_document(document, settings)
92
+ end
93
+
94
+ def create_xml_document(settings)
95
+ time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
96
+
97
+ request_doc = XMLSecurity::Document.new
98
+ request_doc.uuid = uuid
45
99
 
46
100
  root = request_doc.add_element "samlp:AuthnRequest", { "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol", "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
47
101
  root.attributes['ID'] = uuid
@@ -97,6 +151,17 @@ module OneLogin
97
151
  request_doc
98
152
  end
99
153
 
154
+ def sign_document(document, settings)
155
+ # embed signature
156
+ if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
157
+ private_key = settings.get_sp_key
158
+ cert = settings.get_sp_cert
159
+ document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
160
+ end
161
+
162
+ document
163
+ end
164
+
100
165
  end
101
166
  end
102
167
  end
@@ -1,49 +1,106 @@
1
1
  require "base64"
2
- require "uuid"
3
2
  require "zlib"
4
3
  require "cgi"
4
+ require 'rexml/document'
5
+ require "onelogin/ruby-saml/utils"
5
6
 
6
7
  module OneLogin
7
8
  module RubySaml
8
- include REXML
9
+
9
10
  class Logoutrequest
10
11
 
11
12
  attr_reader :uuid # Can be obtained if neccessary
12
13
 
13
14
  def initialize
14
- @uuid = "_" + UUID.new.generate
15
+ @uuid = OneLogin::RubySaml::Utils.uuid
15
16
  end
16
17
 
17
18
  def create(settings, params={})
18
- request_doc = create_unauth_xml_doc(settings, params)
19
+ params = create_params(settings, params)
20
+ params_prefix = (settings.idp_slo_target_url =~ /\?/) ? '&' : '?'
21
+ saml_request = CGI.escape(params.delete("SAMLRequest"))
22
+ request_params = "#{params_prefix}SAMLRequest=#{saml_request}"
23
+ params.each_pair do |key, value|
24
+ request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
25
+ end
26
+ @logout_url = settings.idp_slo_target_url + request_params
27
+ end
28
+
29
+ # Creates the Get parameters for the logout request.
30
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
31
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
32
+ # @return [Hash] Parameters
33
+ #
34
+ def create_params(settings, params={})
35
+ # The method expects :RelayState but sometimes we get 'RelayState' instead.
36
+ # Based on the HashWithIndifferentAccess value in Rails we could experience
37
+ # conflicts so this line will solve them.
38
+ relay_state = params[:RelayState] || params['RelayState']
39
+
40
+ if relay_state.nil?
41
+ params.delete(:RelayState)
42
+ params.delete('RelayState')
43
+ end
44
+
45
+ request_doc = create_logout_request_xml_doc(settings)
46
+ request_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
47
+
19
48
  request = ""
20
49
  request_doc.write(request)
21
50
 
22
- deflated_request = Zlib::Deflate.deflate(request, 9)[2..-5]
51
+ Logging.debug "Created SLO Logout Request: #{request}"
52
+
53
+ request = Zlib::Deflate.deflate(request, 9)[2..-5] if settings.compress_request
23
54
  if Base64.respond_to?('strict_encode64')
24
- base64_request = Base64.strict_encode64(deflated_request)
55
+ base64_request = Base64.strict_encode64(request)
25
56
  else
26
- base64_request = Base64.encode64(deflated_request).gsub(/\n/, "")
57
+ base64_request = Base64.encode64(request).gsub(/\n/, "")
27
58
  end
28
- encoded_request = CGI.escape(base64_request)
59
+ request_params = {"SAMLRequest" => base64_request}
29
60
 
30
- params_prefix = (settings.idp_slo_target_url =~ /\?/) ? '&' : '?'
31
- request_params = "#{params_prefix}SAMLRequest=#{encoded_request}"
61
+ if settings.security[:logout_requests_signed] && !settings.security[:embed_sign] && settings.private_key
62
+ params['SigAlg'] = settings.security[:signature_method]
63
+ url_string = OneLogin::RubySaml::Utils.build_query(
64
+ :type => 'SAMLRequest',
65
+ :data => base64_request,
66
+ :relay_state => relay_state,
67
+ :sig_alg => params['SigAlg']
68
+ )
69
+ sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
70
+ signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
71
+ if Base64.respond_to?('strict_encode64')
72
+ params['Signature'] = Base64.strict_encode64(signature)
73
+ else
74
+ params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
75
+ end
76
+ end
32
77
 
33
78
  params.each_pair do |key, value|
34
- request_params << "&#{key}=#{CGI.escape(value.to_s)}"
79
+ request_params[key] = value.to_s
35
80
  end
36
81
 
37
- @logout_url = settings.idp_slo_target_url + request_params
82
+ request_params
38
83
  end
39
84
 
40
- def create_unauth_xml_doc(settings, params)
85
+ # Creates the SAMLRequest String.
86
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
87
+ # @return [String] The SAMLRequest String.
88
+ #
89
+ def create_logout_request_xml_doc(settings)
90
+ document = create_xml_document(settings)
91
+ sign_document(document, settings)
92
+ end
93
+
94
+ def create_xml_document(settings, request_doc=nil)
95
+ time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
41
96
 
42
- time = Time.new().strftime("%Y-%m-%dT%H:%M:%S")
97
+ if request_doc.nil?
98
+ request_doc = XMLSecurity::Document.new
99
+ request_doc.uuid = uuid
100
+ end
43
101
 
44
- request_doc = REXML::Document.new
45
102
  root = request_doc.add_element "samlp:LogoutRequest", { "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol" }
46
- root.attributes['ID'] = @uuid
103
+ root.attributes['ID'] = uuid
47
104
  root.attributes['IssueInstant'] = time
48
105
  root.attributes['Version'] = "2.0"
49
106
 
@@ -57,8 +114,6 @@ module OneLogin
57
114
  name_id.attributes['NameQualifier'] = settings.sp_name_qualifier if settings.sp_name_qualifier
58
115
  name_id.attributes['Format'] = settings.name_identifier_format if settings.name_identifier_format
59
116
  name_id.text = settings.name_identifier_value
60
- else
61
- raise ValidationError.new("Missing required name identifier")
62
117
  end
63
118
 
64
119
  if settings.sessionindex
@@ -81,6 +136,23 @@ module OneLogin
81
136
  end
82
137
  request_doc
83
138
  end
139
+
140
+ def sign_document(document, settings)
141
+ # embed signature
142
+ if settings.security[:logout_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
143
+ private_key = settings.get_sp_key
144
+ cert = settings.get_sp_cert
145
+ document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
146
+ end
147
+
148
+ document
149
+ end
150
+
151
+ # Leave due compatibility
152
+ def create_unauth_xml_doc(settings, params)
153
+ request_doc = ReXML::Document.new
154
+ create_xml_document(settings, request_doc)
155
+ end
84
156
  end
85
157
  end
86
158
  end
@@ -1,27 +1,52 @@
1
+ require "xml_security"
2
+ require "onelogin/ruby-saml/utils"
3
+
1
4
  module OneLogin
2
5
  module RubySaml
3
6
  class Settings
4
- def initialize(overrides = {})
5
- config = DEFAULTS.merge(overrides)
6
- config.each do |k,v|
7
- acc = "#{k.to_s}=".to_sym
8
- self.send(acc, v) if self.respond_to? acc
9
- end
7
+ def initialize(overrides = {}, keep_security_attributes = false)
8
+ if keep_security_attributes
9
+ security_attributes = overrides.delete(:security) || {}
10
+ config = DEFAULTS.merge(overrides)
11
+ config[:security] = DEFAULTS[:security].merge(security_attributes)
12
+ else
13
+ config = DEFAULTS.merge(overrides)
14
+ end
15
+
16
+ config.each do |k,v|
17
+ acc = "#{k.to_s}=".to_sym
18
+ if respond_to? acc
19
+ value = v.is_a?(Hash) ? v.dup : v
20
+ send(acc, value)
21
+ end
22
+ end
10
23
  end
11
- attr_accessor :assertion_consumer_service_url, :sp_entity_id, :sp_name_qualifier
12
- attr_accessor :idp_sso_target_url, :idp_cert_fingerprint, :idp_cert, :name_identifier_format
13
- attr_accessor :authn_context
24
+
25
+ #idp data
26
+ attr_accessor :idp_sso_target_url
27
+ attr_accessor :idp_cert_fingerprint
28
+ attr_accessor :idp_cert
14
29
  attr_accessor :idp_slo_target_url
30
+ #sp data
31
+ attr_accessor :sp_entity_id
32
+ attr_accessor :assertion_consumer_service_url
33
+ attr_accessor :authn_context
34
+ attr_accessor :sp_name_qualifier
35
+ attr_accessor :name_identifier_format
15
36
  attr_accessor :name_identifier_value
16
37
  attr_accessor :name_identifier_value_requested
17
38
  attr_accessor :sessionindex
18
39
  attr_accessor :assertion_consumer_logout_service_url
19
40
  attr_accessor :compress_request
41
+ attr_accessor :compress_response
20
42
  attr_accessor :double_quote_xml_attribute_values
21
43
  attr_accessor :force_authn
22
44
  attr_accessor :passive
23
45
  attr_accessor :protocol_binding
24
-
46
+ attr_accessor :certificate
47
+ attr_accessor :private_key
48
+ # Work-flow
49
+ attr_accessor :security
25
50
  # Compability
26
51
  attr_accessor :issuer
27
52
  attr_accessor :assertion_consumer_logout_service_url
@@ -92,14 +117,50 @@ module OneLogin
92
117
  @single_logout_service_binding = url
93
118
  end
94
119
 
120
+ # @return [OpenSSL::X509::Certificate|nil] Build the SP certificate from the settings (previously format it)
121
+ #
122
+ def get_sp_cert
123
+ return nil if certificate.nil? || certificate.empty?
124
+
125
+ formatted_cert = OneLogin::RubySaml::Utils.format_cert(certificate)
126
+ OpenSSL::X509::Certificate.new(formatted_cert)
127
+ end
128
+
129
+ # @return [OpenSSL::X509::Certificate|nil] Build the New SP certificate from the settings (previously format it)
130
+ #
131
+ def get_sp_cert_new
132
+ return nil if certificate_new.nil? || certificate_new.empty?
133
+
134
+ formatted_cert = OneLogin::RubySaml::Utils.format_cert(certificate_new)
135
+ OpenSSL::X509::Certificate.new(formatted_cert)
136
+ end
137
+
138
+ # @return [OpenSSL::PKey::RSA] Build the SP private from the settings (previously format it)
139
+ #
140
+ def get_sp_key
141
+ return nil if private_key.nil? || private_key.empty?
142
+
143
+ formatted_private_key = OneLogin::RubySaml::Utils.format_private_key(private_key)
144
+ OpenSSL::PKey::RSA.new(formatted_private_key)
145
+ end
146
+
95
147
  private
96
148
 
97
149
  DEFAULTS = {
98
150
  :compress_request => true,
151
+ :compress_response => true,
99
152
  :double_quote_xml_attribute_values => false,
100
153
  :assertion_consumer_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST".freeze,
101
- :single_logout_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect".freeze
102
- }
154
+ :single_logout_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect".freeze,
155
+ :security => {
156
+ :authn_requests_signed => false,
157
+ :logout_requests_signed => false,
158
+ :logout_responses_signed => false,
159
+ :embed_sign => false,
160
+ :digest_method => XMLSecurity::Document::SHA1,
161
+ :signature_method => XMLSecurity::Document::RSA_SHA1
162
+ }.freeze
163
+ }.freeze
103
164
  end
104
165
  end
105
166
  end
@@ -0,0 +1,157 @@
1
+ require "base64"
2
+ require "zlib"
3
+ require "cgi"
4
+ require "onelogin/ruby-saml/utils"
5
+
6
+ module OneLogin
7
+ module RubySaml
8
+
9
+ # SAML2 Logout Response (SLO SP initiated)
10
+ #
11
+ class SloLogoutresponse
12
+
13
+ # Logout Response ID
14
+ attr_reader :uuid
15
+
16
+ # Initializes the Logout Response. A SloLogoutresponse Object.
17
+ # Asigns an ID, a random uuid.
18
+ #
19
+ def initialize
20
+ @uuid = OneLogin::RubySaml::Utils.uuid
21
+ end
22
+
23
+ # Creates the Logout Response string.
24
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
25
+ # @param request_id [String] The ID of the LogoutRequest sent by this SP to the IdP. That ID will be placed as the InResponseTo in the logout response
26
+ # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
27
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
28
+ # @return [String] Logout Request string that includes the SAMLRequest
29
+ #
30
+ def create(settings, request_id = nil, logout_message = nil, params = {})
31
+ params = create_params(settings, request_id, logout_message, params)
32
+ params_prefix = (settings.idp_slo_target_url =~ /\?/) ? '&' : '?'
33
+ saml_response = CGI.escape(params.delete("SAMLResponse"))
34
+ response_params = "#{params_prefix}SAMLResponse=#{saml_response}"
35
+ params.each_pair do |key, value|
36
+ response_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
37
+ end
38
+
39
+ @logout_url = settings.idp_slo_target_url + response_params
40
+ end
41
+
42
+ # Creates the Get parameters for the logout response.
43
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
44
+ # @param request_id [String] The ID of the LogoutRequest sent by this SP to the IdP. That ID will be placed as the InResponseTo in the logout response
45
+ # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
46
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
47
+ # @return [Hash] Parameters
48
+ #
49
+ def create_params(settings, request_id = nil, logout_message = nil, params = {})
50
+ # The method expects :RelayState but sometimes we get 'RelayState' instead.
51
+ # Based on the HashWithIndifferentAccess value in Rails we could experience
52
+ # conflicts so this line will solve them.
53
+ relay_state = params[:RelayState] || params['RelayState']
54
+
55
+ if relay_state.nil?
56
+ params.delete(:RelayState)
57
+ params.delete('RelayState')
58
+ end
59
+
60
+ response_doc = create_logout_response_xml_doc(settings, request_id, logout_message)
61
+ response_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
62
+
63
+ response = ""
64
+ response_doc.write(response)
65
+
66
+ Logging.debug "Created SLO Logout Response: #{response}"
67
+
68
+ response = Zlib::Deflate.deflate(response, 9)[2..-5] if settings.compress_response
69
+ if Base64.respond_to?('strict_encode64')
70
+ base64_response = Base64.strict_encode64(response)
71
+ else
72
+ base64_response = Base64.encode64(response).gsub(/\n/, "")
73
+ end
74
+ response_params = {"SAMLResponse" => base64_response}
75
+
76
+ if settings.security[:logout_responses_signed] && !settings.security[:embed_sign] && settings.private_key
77
+ params['SigAlg'] = settings.security[:signature_method]
78
+ url_string = OneLogin::RubySaml::Utils.build_query(
79
+ :type => 'SAMLResponse',
80
+ :data => base64_response,
81
+ :relay_state => relay_state,
82
+ :sig_alg => params['SigAlg']
83
+ )
84
+ sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
85
+ signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
86
+ if Base64.respond_to?('strict_encode64')
87
+ params['Signature'] = Base64.strict_encode64(signature)
88
+ else
89
+ params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
90
+ end
91
+ end
92
+
93
+ params.each_pair do |key, value|
94
+ response_params[key] = value.to_s
95
+ end
96
+
97
+ response_params
98
+ end
99
+
100
+ # Creates the SAMLResponse String.
101
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
102
+ # @param request_id [String] The ID of the LogoutRequest sent by this SP to the IdP. That ID will be placed as the InResponseTo in the logout response
103
+ # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
104
+ # @return [String] The SAMLResponse String.
105
+ #
106
+ def create_logout_response_xml_doc(settings, request_id = nil, logout_message = nil)
107
+ document = create_xml_document(settings, request_id, logout_message)
108
+ sign_document(document, settings)
109
+ end
110
+
111
+ def create_xml_document(settings, request_id = nil, logout_message = nil)
112
+ time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
113
+
114
+ response_doc = XMLSecurity::Document.new
115
+ response_doc.uuid = uuid
116
+
117
+ root = response_doc.add_element 'samlp:LogoutResponse', { 'xmlns:samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol', "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
118
+ root.attributes['ID'] = uuid
119
+ root.attributes['IssueInstant'] = time
120
+ root.attributes['Version'] = '2.0'
121
+ root.attributes['InResponseTo'] = request_id unless request_id.nil?
122
+ root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil?
123
+
124
+ if settings.sp_entity_id != nil
125
+ issuer = root.add_element "saml:Issuer"
126
+ issuer.text = settings.sp_entity_id
127
+ end
128
+
129
+ # add success message
130
+ status = root.add_element 'samlp:Status'
131
+
132
+ # success status code
133
+ status_code = status.add_element 'samlp:StatusCode'
134
+ status_code.attributes['Value'] = 'urn:oasis:names:tc:SAML:2.0:status:Success'
135
+
136
+ # success status message
137
+ logout_message ||= 'Successfully Signed Out'
138
+ status_message = status.add_element 'samlp:StatusMessage'
139
+ status_message.text = logout_message
140
+
141
+ response_doc
142
+ end
143
+
144
+ def sign_document(document, settings)
145
+ # embed signature
146
+ if settings.security[:logout_responses_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
147
+ private_key = settings.get_sp_key
148
+ cert = settings.get_sp_cert
149
+ document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
150
+ end
151
+
152
+ document
153
+ end
154
+
155
+ end
156
+ end
157
+ end