ruby-saml 0.8.9 → 0.8.10

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.

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